23_permissions_boundaries/
23_permissions_boundaries.rs1use std::sync::{Arc, RwLock};
14use wami::{
15 provider::AwsProvider,
16 service::{
17 EvaluationService, PermissionsBoundaryService, PolicyService, RoleService, UserService,
18 },
19 store::memory::InMemoryWamiStore,
20 wami::identity::role::requests::CreateRoleRequest,
21 wami::identity::user::requests::CreateUserRequest,
22 wami::policies::evaluation::SimulatePrincipalPolicyRequest,
23 wami::policies::permissions_boundary::{
24 DeletePermissionsBoundaryRequest, PrincipalType, PutPermissionsBoundaryRequest,
25 },
26 wami::policies::policy::requests::CreatePolicyRequest,
27};
28
29#[tokio::main]
30async fn main() -> Result<(), Box<dyn std::error::Error>> {
31 println!("=== WAMI Example 23: Permissions Boundaries ===\n");
32
33 let store = Arc::new(RwLock::new(InMemoryWamiStore::default()));
35 let account_id = "123456789012";
36 let _provider = Arc::new(AwsProvider::new());
37
38 let user_service = UserService::new(store.clone(), account_id.to_string());
39 let role_service = RoleService::new(store.clone(), account_id.to_string());
40 let policy_service = PolicyService::new(store.clone(), account_id.to_string());
41 let boundary_service = PermissionsBoundaryService::new(store.clone(), account_id.to_string());
42 let evaluation_service = EvaluationService::new(store.clone(), account_id.to_string());
43
44 println!("š Part 1: Creating User with Admin Policy\n");
48
49 let alice_req = CreateUserRequest {
51 user_name: "alice".to_string(),
52 path: Some("/developers/".to_string()),
53 permissions_boundary: None,
54 tags: None,
55 };
56 let alice = user_service.create_user(alice_req).await?;
57 println!("ā
Created user: {}", alice.user_name);
58 println!(" ARN: {}\n", alice.arn);
59
60 let admin_policy_doc = r#"{
62 "Version": "2012-10-17",
63 "Statement": [{
64 "Effect": "Allow",
65 "Action": "*",
66 "Resource": "*"
67 }]
68 }"#;
69 let admin_policy = policy_service
70 .create_policy(CreatePolicyRequest {
71 policy_name: "AdminPolicy".to_string(),
72 policy_document: admin_policy_doc.to_string(),
73 path: Some("/".to_string()),
74 description: Some("Full admin access".to_string()),
75 tags: None,
76 })
77 .await?;
78 println!("ā
Created admin policy: {}", admin_policy.policy_name);
79 println!(" ARN: {}", admin_policy.arn);
80 println!(" Allows: All actions on all resources\n");
81
82 println!("š Part 2: Creating S3-Only Boundary Policy\n");
86
87 let s3_boundary_doc = r#"{
88 "Version": "2012-10-17",
89 "Statement": [{
90 "Effect": "Allow",
91 "Action": "s3:*",
92 "Resource": "*"
93 }]
94 }"#;
95 let s3_boundary = policy_service
96 .create_policy(CreatePolicyRequest {
97 policy_name: "S3OnlyBoundary".to_string(),
98 policy_document: s3_boundary_doc.to_string(),
99 path: Some("/boundaries/".to_string()),
100 description: Some("Limits permissions to S3 only".to_string()),
101 tags: None,
102 })
103 .await?;
104 println!("ā
Created boundary policy: {}", s3_boundary.policy_name);
105 println!(" ARN: {}", s3_boundary.arn);
106 println!(" Allows: Only S3 actions\n");
107
108 println!("š Part 3: Testing Permissions WITHOUT Boundary\n");
112
113 let sim_req = SimulatePrincipalPolicyRequest {
115 policy_source_arn: alice.arn.clone(),
116 action_names: vec![
117 "s3:GetObject".to_string(),
118 "ec2:RunInstances".to_string(),
119 "iam:CreateUser".to_string(),
120 ],
121 resource_arns: Some(vec!["*".to_string()]),
122 policy_input_list: Some(vec![admin_policy_doc.to_string()]),
123 context_entries: None,
124 };
125
126 let results = evaluation_service
127 .simulate_principal_policy(sim_req)
128 .await?;
129
130 println!("Action Evaluation Results:");
131 for result in &results.evaluation_results {
132 println!(
133 " ⢠{} on {} ā {}",
134 result.eval_action_name, result.eval_resource_name, result.eval_decision
135 );
136 }
137 println!();
138
139 println!("š Part 4: Attaching S3-Only Boundary to User\n");
143
144 let put_boundary_req = PutPermissionsBoundaryRequest {
145 principal_type: PrincipalType::User,
146 principal_name: "alice".to_string(),
147 permissions_boundary: s3_boundary.arn.clone(),
148 };
149 boundary_service
150 .put_permissions_boundary(put_boundary_req)
151 .await?;
152 println!("ā
Attached permissions boundary to alice");
153 println!(" Boundary: {}", s3_boundary.arn);
154 println!(" Effect: Alice's permissions are now limited to S3 actions only\n");
155
156 println!("š Part 5: Testing Permissions WITH Boundary\n");
160
161 let sim_req_with_boundary = SimulatePrincipalPolicyRequest {
162 policy_source_arn: alice.arn.clone(),
163 action_names: vec![
164 "s3:GetObject".to_string(),
165 "s3:PutObject".to_string(),
166 "ec2:RunInstances".to_string(),
167 "iam:CreateUser".to_string(),
168 ],
169 resource_arns: Some(vec!["*".to_string()]),
170 policy_input_list: Some(vec![admin_policy_doc.to_string()]),
171 context_entries: None,
172 };
173
174 let results_with_boundary = evaluation_service
175 .simulate_principal_policy(sim_req_with_boundary)
176 .await?;
177
178 println!("Action Evaluation Results (with boundary):");
179 for result in &results_with_boundary.evaluation_results {
180 let status = match result.eval_decision.as_str() {
181 "allowed" => "ā
ALLOWED",
182 "denied" => "ā DENIED",
183 _ => "ā ļø IMPLICIT DENY",
184 };
185 println!(
186 " {} ā {} ({})",
187 result.eval_action_name, status, result.eval_decision
188 );
189 }
190 println!("\nš Notice:");
191 println!(" ⢠S3 actions are ALLOWED (both policy and boundary allow)");
192 println!(" ⢠EC2 and IAM actions are DENIED (boundary restricts them)\n");
193
194 println!("š Part 6: Using Boundaries with Roles\n");
198
199 let assume_policy_doc = r#"{
201 "Version": "2012-10-17",
202 "Statement": [{
203 "Effect": "Allow",
204 "Principal": {"Service": "ec2.amazonaws.com"},
205 "Action": "sts:AssumeRole"
206 }]
207 }"#;
208
209 let dev_role_req = CreateRoleRequest {
210 role_name: "DeveloperRole".to_string(),
211 assume_role_policy_document: assume_policy_doc.to_string(),
212 path: Some("/roles/".to_string()),
213 description: Some("Role for developers".to_string()),
214 max_session_duration: None,
215 permissions_boundary: None,
216 tags: None,
217 };
218 let dev_role = role_service.create_role(dev_role_req).await?;
219 println!("ā
Created role: {}", dev_role.role_name);
220 println!(" ARN: {}\n", dev_role.arn);
221
222 let read_only_boundary_doc = r#"{
224 "Version": "2012-10-17",
225 "Statement": [{
226 "Effect": "Allow",
227 "Action": [
228 "s3:Get*",
229 "s3:List*",
230 "ec2:Describe*"
231 ],
232 "Resource": "*"
233 }]
234 }"#;
235 let read_only_boundary = policy_service
236 .create_policy(CreatePolicyRequest {
237 policy_name: "ReadOnlyBoundary".to_string(),
238 policy_document: read_only_boundary_doc.to_string(),
239 path: Some("/boundaries/".to_string()),
240 description: Some("Limits to read-only operations".to_string()),
241 tags: None,
242 })
243 .await?;
244 println!(
245 "ā
Created read-only boundary: {}",
246 read_only_boundary.policy_name
247 );
248
249 let put_role_boundary = PutPermissionsBoundaryRequest {
251 principal_type: PrincipalType::Role,
252 principal_name: "DeveloperRole".to_string(),
253 permissions_boundary: read_only_boundary.arn.clone(),
254 };
255 boundary_service
256 .put_permissions_boundary(put_role_boundary)
257 .await?;
258 println!("ā
Attached read-only boundary to DeveloperRole\n");
259
260 let role_sim_req = SimulatePrincipalPolicyRequest {
262 policy_source_arn: dev_role.arn.clone(),
263 action_names: vec![
264 "s3:GetObject".to_string(),
265 "s3:PutObject".to_string(),
266 "ec2:DescribeInstances".to_string(),
267 "ec2:RunInstances".to_string(),
268 ],
269 resource_arns: Some(vec!["*".to_string()]),
270 policy_input_list: Some(vec![admin_policy_doc.to_string()]),
271 context_entries: None,
272 };
273
274 let role_results = evaluation_service
275 .simulate_principal_policy(role_sim_req)
276 .await?;
277
278 println!("Role Action Evaluation (with read-only boundary):");
279 for result in &role_results.evaluation_results {
280 let status = match result.eval_decision.as_str() {
281 "allowed" => "ā
ALLOWED",
282 "denied" => "ā DENIED",
283 _ => "ā ļø IMPLICIT DENY",
284 };
285 println!(" {} ā {} ", result.eval_action_name, status);
286 }
287 println!("\nš Notice:");
288 println!(" ⢠Read operations (Get*, Describe*) are ALLOWED");
289 println!(" ⢠Write operations (Put*, Run*) are DENIED by boundary\n");
290
291 println!("š Part 7: Removing Permissions Boundaries\n");
295
296 let delete_user_boundary = DeletePermissionsBoundaryRequest {
297 principal_type: PrincipalType::User,
298 principal_name: "alice".to_string(),
299 };
300 boundary_service
301 .delete_permissions_boundary(delete_user_boundary)
302 .await?;
303 println!("ā
Removed boundary from alice");
304 println!(" Effect: Alice now has full admin permissions again\n");
305
306 let delete_role_boundary = DeletePermissionsBoundaryRequest {
307 principal_type: PrincipalType::Role,
308 principal_name: "DeveloperRole".to_string(),
309 };
310 boundary_service
311 .delete_permissions_boundary(delete_role_boundary)
312 .await?;
313 println!("ā
Removed boundary from DeveloperRole\n");
314
315 println!("š Part 8: Real-World Use Cases\n");
319 println!("Use Case 1: Sandbox Environments");
320 println!(" - Attach boundaries to prevent developers from:");
321 println!(" ⢠Creating IAM users/roles");
322 println!(" ⢠Modifying billing/account settings");
323 println!(" ⢠Accessing production resources\n");
324
325 println!("Use Case 2: Contractor Access");
326 println!(" - Limit contractors to specific services:");
327 println!(" ⢠Allow S3 and Lambda only");
328 println!(" ⢠Prevent infrastructure changes");
329 println!(" ⢠Ensure audit trail compliance\n");
330
331 println!("Use Case 3: Delegated Administration");
332 println!(" - Allow team leads to create users but:");
333 println!(" ⢠Boundary prevents privilege escalation");
334 println!(" ⢠New users inherit safe permission limits");
335 println!(" ⢠Central security team controls boundaries\n");
336
337 println!("Use Case 4: Multi-Tenant SaaS");
338 println!(" - Each tenant gets a boundary policy:");
339 println!(" ⢠Restricts access to tenant-specific resources");
340 println!(" ⢠Prevents cross-tenant data access");
341 println!(" ⢠Simplifies per-tenant permission management\n");
342
343 println!("=== Example 23 Complete ===");
344 println!("\nš Key Takeaways:");
345 println!(" 1. Boundaries set maximum permissions (ceiling)");
346 println!(" 2. Effective permissions = identity policies ā© boundary");
347 println!(" 3. Both identity policy AND boundary must allow an action");
348 println!(" 4. Boundaries prevent privilege escalation");
349 println!(" 5. Use for security controls, sandboxes, and delegation");
350
351 Ok(())
352}