Skip to main content

24_policy_attachment/
24_policy_attachment.rs

1//! Example 24: Policy Attachment
2//!
3//! This example demonstrates how to attach managed policies and inline policies
4//! to users, groups, and roles.
5
6use std::sync::Arc;
7use tokio::sync::RwLock;
8use wami::arn::{TenantPath, WamiArn};
9use wami::context::WamiContext;
10use wami::service::{AttachmentService, InlinePolicyService, PolicyService, UserService};
11use wami::store::memory::InMemoryWamiStore;
12use wami::wami::identity::user::CreateUserRequest;
13use wami::wami::policies::attachment::{AttachUserPolicyRequest, ListAttachedUserPoliciesRequest};
14use wami::wami::policies::inline::{
15    GetUserPolicyRequest, ListUserPoliciesRequest, PutUserPolicyRequest,
16};
17use wami::wami::policies::policy::CreatePolicyRequest;
18
19#[tokio::main]
20async fn main() -> Result<(), Box<dyn std::error::Error>> {
21    // Initialize logging
22    env_logger::init();
23
24    // Initialize store
25    let store = Arc::new(RwLock::new(InMemoryWamiStore::default()));
26
27    // Create context
28    let context = WamiContext::builder()
29        .instance_id("123456789012")
30        .tenant_path(TenantPath::single(0))
31        .caller_arn(
32            WamiArn::builder()
33                .service(wami::arn::Service::Iam)
34                .tenant_path(TenantPath::single(0))
35                .wami_instance("123456789012")
36                .resource("user", "admin")
37                .build()?,
38        )
39        .is_root(false)
40        .build()?;
41
42    println!("=== Policy Attachment Example ===\n");
43
44    // Step 1: Create a user
45    println!("1. Creating user 'alice'...");
46    let user_service = UserService::new(store.clone());
47    let create_user_req = CreateUserRequest {
48        user_name: "alice".to_string(),
49        path: Some("/".to_string()),
50        tags: Some(vec![]),
51        permissions_boundary: None,
52    };
53    let user = user_service.create_user(&context, create_user_req).await?;
54    println!("   Created user: {} (ARN: {})\n", user.user_name, user.arn);
55
56    // Step 2: Create a managed policy
57    println!("2. Creating managed policy 'S3ReadOnly'...");
58    let policy_service = PolicyService::new(store.clone());
59    let policy_doc = r#"{
60        "Version": "2012-10-17",
61        "Statement": [{
62            "Effect": "Allow",
63            "Action": ["s3:GetObject", "s3:ListBucket"],
64            "Resource": "*"
65        }]
66    }"#;
67
68    let create_policy_req = CreatePolicyRequest {
69        policy_name: "S3ReadOnly".to_string(),
70        path: Some("/".to_string()),
71        policy_document: policy_doc.to_string(),
72        description: Some("Read-only access to S3".to_string()),
73        tags: Some(vec![]),
74    };
75    let policy = policy_service
76        .create_policy(&context, create_policy_req)
77        .await?;
78    println!(
79        "   Created policy: {} (ARN: {})\n",
80        policy.policy_name, policy.arn
81    );
82
83    // Step 3: Attach the managed policy to the user
84    println!("3. Attaching managed policy to user...");
85    let attachment_service = AttachmentService::new(store.clone());
86    let attach_req = AttachUserPolicyRequest {
87        user_name: "alice".to_string(),
88        policy_arn: policy.arn.clone(),
89    };
90    let attach_resp = attachment_service
91        .attach_user_policy(&context, attach_req)
92        .await?;
93    println!("   {}\n", attach_resp.message);
94
95    // Step 4: List attached policies
96    println!("4. Listing attached policies for user 'alice'...");
97    let list_req = ListAttachedUserPoliciesRequest {
98        user_name: "alice".to_string(),
99    };
100    let list_resp = attachment_service
101        .list_attached_user_policies(&context, list_req)
102        .await?;
103    println!(
104        "   Found {} attached policies:",
105        list_resp.attached_policies.len()
106    );
107    for p in &list_resp.attached_policies {
108        println!("   - {} ({})", p.policy_name, p.policy_arn);
109    }
110    println!();
111
112    // Step 5: Add an inline policy
113    println!("5. Adding inline policy 'DenyDelete' to user...");
114    let inline_service = InlinePolicyService::new(store.clone());
115    let inline_doc = r#"{
116        "Version": "2012-10-17",
117        "Statement": [{
118            "Effect": "Deny",
119            "Action": ["*:Delete*"],
120            "Resource": "*"
121        }]
122    }"#;
123
124    let put_inline_req = PutUserPolicyRequest {
125        user_name: "alice".to_string(),
126        policy_name: "DenyDelete".to_string(),
127        policy_document: inline_doc.to_string(),
128    };
129    let put_resp = inline_service
130        .put_user_policy(&context, put_inline_req)
131        .await?;
132    println!("   {}\n", put_resp.message);
133
134    // Step 6: List inline policies
135    println!("6. Listing inline policies for user 'alice'...");
136    let list_inline_req = ListUserPoliciesRequest {
137        user_name: "alice".to_string(),
138    };
139    let list_inline_resp = inline_service
140        .list_user_policies(&context, list_inline_req)
141        .await?;
142    println!(
143        "   Found {} inline policies:",
144        list_inline_resp.policy_names.len()
145    );
146    for name in &list_inline_resp.policy_names {
147        println!("   - {}", name);
148    }
149    println!();
150
151    // Step 7: Get inline policy content
152    println!("7. Getting inline policy 'DenyDelete'...");
153    let get_inline_req = GetUserPolicyRequest {
154        user_name: "alice".to_string(),
155        policy_name: "DenyDelete".to_string(),
156    };
157    let get_resp = inline_service
158        .get_user_policy(&context, get_inline_req)
159        .await?;
160    println!("   Policy document:\n{}\n", get_resp.policy_document);
161
162    println!("=== Summary ===");
163    println!("User 'alice' now has:");
164    println!(
165        "- {} managed policy attached (S3ReadOnly)",
166        list_resp.attached_policies.len()
167    );
168    println!(
169        "- {} inline policy (DenyDelete)",
170        list_inline_resp.policy_names.len()
171    );
172    println!("\nThis grants alice read access to S3 but denies all delete operations.");
173
174    Ok(())
175}