pub struct RoleService<S> { /* private fields */ }Expand description
Service for managing IAM roles
Provides high-level operations for role management.
Implementations§
Source§impl<S: RoleStore> RoleService<S>
impl<S: RoleStore> RoleService<S>
Sourcepub fn new(store: Arc<RwLock<S>>, account_id: String) -> Self
pub fn new(store: Arc<RwLock<S>>, account_id: String) -> Self
Create a new RoleService with default AWS provider
Examples found in repository?
examples/19_role_assumption_workflow.rs (line 29)
21async fn main() -> Result<(), Box<dyn std::error::Error>> {
22 println!("=== Role Assumption Workflow ===\n");
23
24 let store = Arc::new(RwLock::new(InMemoryWamiStore::default()));
25 let _provider = Arc::new(AwsProvider::new());
26 let account_id = "123456789012";
27
28 let user_service = UserService::new(store.clone(), account_id.to_string());
29 let role_service = RoleService::new(store.clone(), account_id.to_string());
30 let sts_service = AssumeRoleService::new(store.clone(), account_id.to_string());
31
32 // Create user
33 println!("Step 1: Creating user...\n");
34 let alice = user_service
35 .create_user(CreateUserRequest {
36 user_name: "alice".to_string(),
37 path: Some("/".to_string()),
38 permissions_boundary: None,
39 tags: None,
40 })
41 .await?;
42 println!("✓ Created alice: {}", alice.arn);
43
44 // Create elevated role
45 println!("\nStep 2: Creating admin role...\n");
46 let trust_policy = r#"{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"AWS":"*"},"Action":"sts:AssumeRole"}]}"#;
47 let role = role_service
48 .create_role(CreateRoleRequest {
49 role_name: "AdminRole".to_string(),
50 path: Some("/".to_string()),
51 assume_role_policy_document: trust_policy.to_string(),
52 description: Some("Admin role for elevated access".to_string()),
53 max_session_duration: Some(3600),
54 permissions_boundary: None,
55 tags: None,
56 })
57 .await?;
58 println!("✓ Created AdminRole: {}", role.arn);
59
60 // Assume role
61 println!("\nStep 3: Alice assuming AdminRole...\n");
62 let assume_req = AssumeRoleRequest {
63 role_arn: role.arn.clone(),
64 role_session_name: "alice-admin-session".to_string(),
65 duration_seconds: Some(3600),
66 external_id: None,
67 policy: None,
68 };
69
70 let response = sts_service.assume_role(assume_req, &alice.arn).await?;
71 println!("✓ Successfully assumed role!");
72 println!(" Assumed Role ARN: {}", response.assumed_role_user.arn);
73 println!(" Access Key: {}", response.credentials.access_key_id);
74 println!(" Expiration: {}", response.credentials.expiration);
75
76 println!("\n✅ Example completed successfully!");
77 println!("Key takeaways:");
78 println!("- AssumeRole provides temporary elevated permissions");
79 println!("- Trust policies control who can assume roles");
80 println!("- Session credentials expire automatically");
81
82 Ok(())
83}More examples
examples/03_service_layer_intro.rs (line 33)
21async fn main() -> Result<(), Box<dyn std::error::Error>> {
22 println!("=== Service Layer Introduction ===\n");
23
24 // Step 1: Initialize store with Arc<RwLock> for thread-safe access
25 println!("Step 1: Initializing services...\n");
26 let store = Arc::new(RwLock::new(InMemoryWamiStore::default()));
27 let _provider = Arc::new(AwsProvider::new());
28 let account_id = "123456789012";
29
30 // Create services
31 let user_service = UserService::new(store.clone(), account_id.to_string());
32 let group_service = GroupService::new(store.clone(), account_id.to_string());
33 let role_service = RoleService::new(store.clone(), account_id.to_string());
34
35 println!("✓ Services initialized");
36
37 // === CREATE Operations via Services ===
38 println!("\nStep 2: Creating resources via services...\n");
39
40 // Create users
41 println!("Creating users...");
42 let alice_req = CreateUserRequest {
43 user_name: "alice".to_string(),
44 path: Some("/users/".to_string()),
45 permissions_boundary: None,
46 tags: None,
47 };
48 let alice = user_service.create_user(alice_req).await?;
49 println!("✓ Created user: {}", alice.user_name);
50
51 let bob_req = CreateUserRequest {
52 user_name: "bob".to_string(),
53 path: Some("/users/".to_string()),
54 permissions_boundary: None,
55 tags: None,
56 };
57 user_service.create_user(bob_req).await?;
58 println!("✓ Created user: bob");
59
60 // Create groups
61 println!("\nCreating groups...");
62 let dev_group_req = CreateGroupRequest {
63 group_name: "developers".to_string(),
64 path: Some("/groups/".to_string()),
65 tags: None,
66 };
67 let dev_group = group_service.create_group(dev_group_req).await?;
68 println!("✓ Created group: {}", dev_group.group_name);
69
70 // Create role
71 println!("\nCreating role...");
72 let role_req = CreateRoleRequest {
73 role_name: "deploy-role".to_string(),
74 path: Some("/roles/".to_string()),
75 assume_role_policy_document: r#"{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"AWS":"*"},"Action":"sts:AssumeRole"}]}"#.to_string(),
76 description: Some("Role for deployment".to_string()),
77 max_session_duration: Some(3600),
78 permissions_boundary: None,
79 tags: None,
80 };
81 let role = role_service.create_role(role_req).await?;
82 println!("✓ Created role: {}", role.role_name);
83
84 // === READ Operations via Services ===
85 println!("\n\nStep 3: Reading resources via services...\n");
86
87 // Get specific user
88 let alice_retrieved = user_service.get_user("alice").await?;
89 if let Some(user) = alice_retrieved {
90 println!("✓ Retrieved user 'alice':");
91 println!(" - User ID: {}", user.user_id);
92 println!(" - ARN: {}", user.arn);
93 }
94
95 // List users
96 let users = user_service
97 .list_users(ListUsersRequest {
98 path_prefix: None,
99 pagination: None,
100 })
101 .await?;
102 println!("\n✓ Found {} users via service:", users.0.len());
103 for user in &users.0 {
104 println!(" - {}", user.user_name);
105 }
106
107 // === UPDATE Operations via Services ===
108 println!("\n\nStep 4: Updating resources via services...\n");
109
110 use wami::wami::identity::user::requests::UpdateUserRequest;
111 let update_req = UpdateUserRequest {
112 user_name: "alice".to_string(),
113 new_user_name: None,
114 new_path: Some("/admin-users/".to_string()),
115 };
116 user_service.update_user(update_req).await?;
117 println!("✓ Updated alice's path to '/admin-users/'");
118
119 // === DELETE Operations via Services ===
120 println!("\n\nStep 5: Deleting resources via services...\n");
121
122 user_service.delete_user("bob").await?;
123 println!("✓ Deleted user 'bob'");
124
125 // Verify deletion
126 let bob_check = user_service.get_user("bob").await?;
127 if bob_check.is_none() {
128 println!(" Verified: bob no longer exists");
129 }
130
131 println!("\n✅ Example completed successfully!");
132 println!("Key takeaways:");
133 println!("- Services provide a higher-level API than raw store access");
134 println!("- Arc<RwLock<Store>> enables thread-safe concurrent operations");
135 println!("- Services use request/response DTOs for clean API contracts");
136 println!("- Services encapsulate business logic and validation");
137
138 Ok(())
139}examples/07_cross_tenant_role_assumption.rs (line 65)
22async fn main() -> Result<(), Box<dyn std::error::Error>> {
23 println!("=== Cross-Tenant Role Assumption ===\n");
24
25 let store = Arc::new(RwLock::new(InMemoryWamiStore::default()));
26 let _provider = Arc::new(AwsProvider::new());
27
28 // === SETUP TENANTS ===
29 println!("Step 1: Creating two tenants...\n");
30
31 let tenant_service = TenantService::new(store.clone(), "root".to_string());
32
33 // Tenant A (source)
34 let _tenant_a_id = TenantId::new("company-a");
35 tenant_service
36 .create_tenant("company-a".to_string(), Some("Company A".to_string()), None)
37 .await?;
38 println!("✓ Created tenant: company-a");
39
40 // Tenant B (target)
41 let _tenant_b_id = TenantId::new("company-b");
42 tenant_service
43 .create_tenant("company-b".to_string(), Some("Company B".to_string()), None)
44 .await?;
45 println!("✓ Created tenant: company-b");
46
47 // === CREATE USER IN TENANT A ===
48 println!("\nStep 2: Creating user in tenant A...\n");
49
50 let user_service_a = UserService::new(store.clone(), "company-a".to_string());
51
52 let alice_req = CreateUserRequest {
53 user_name: "alice".to_string(),
54 path: Some("/".to_string()),
55 permissions_boundary: None,
56 tags: None,
57 };
58 let alice = user_service_a.create_user(alice_req).await?;
59 println!("✓ Created alice in company-a");
60 println!(" ARN: {}", alice.arn);
61
62 // === CREATE ROLE IN TENANT B WITH TRUST POLICY ===
63 println!("\nStep 3: Creating cross-tenant role in tenant B...\n");
64
65 let role_service_b = RoleService::new(store.clone(), "company-b".to_string());
66
67 // Trust policy allowing Company A users to assume this role
68 let trust_policy = r#"{
69 "Version": "2012-10-17",
70 "Statement": [{
71 "Effect": "Allow",
72 "Principal": {"AWS": "arn:aws:iam::company-a:root"},
73 "Action": "sts:AssumeRole"
74 }]
75}"#
76 .to_string();
77
78 let role_req = CreateRoleRequest {
79 role_name: "cross-tenant-reader".to_string(),
80 path: Some("/".to_string()),
81 assume_role_policy_document: trust_policy,
82 description: Some("Role for cross-tenant read access".to_string()),
83 max_session_duration: Some(3600),
84 permissions_boundary: None,
85 tags: None,
86 };
87
88 let role = role_service_b.create_role(role_req).await?;
89 println!("✓ Created cross-tenant-reader role in company-b");
90 println!(" Role ARN: {}", role.arn);
91
92 // === ASSUME ROLE ACROSS TENANTS ===
93 println!("\nStep 4: Alice assuming role in company-b...\n");
94
95 let sts_service = AssumeRoleService::new(
96 store.clone(),
97 "company-a".to_string(), // Operating from tenant A
98 );
99
100 let assume_req = AssumeRoleRequest {
101 role_arn: role.arn.clone(),
102 role_session_name: "alice-cross-tenant-session".to_string(),
103 duration_seconds: Some(3600),
104 external_id: None,
105 policy: None,
106 };
107
108 let assume_response = sts_service.assume_role(assume_req, &alice.arn).await?;
109 println!("✓ Alice successfully assumed cross-tenant role!");
110 println!(" Credentials:");
111 println!(
112 " - Access Key: {}",
113 assume_response.credentials.access_key_id
114 );
115 println!(
116 " - Session Token: {}...",
117 &assume_response.credentials.session_token[..20]
118 );
119 println!(
120 " - Expiration: {}",
121 assume_response.credentials.expiration
122 );
123 println!("\n Assumed Role:");
124 println!(" - ARN: {}", assume_response.assumed_role_user.arn);
125 println!(
126 " - User ID: {}",
127 assume_response.assumed_role_user.assumed_role_id
128 );
129
130 // === DEMONSTRATE USE CASE ===
131 println!("\n\nStep 5: Understanding cross-tenant scenarios...\n");
132
133 println!("Cross-tenant role assumption enables:");
134 println!("- Partner company collaboration");
135 println!("- Outsourced operations (DevOps team accessing client resources)");
136 println!("- Centralized security auditing across organizations");
137 println!("- Merger & acquisition transitional access");
138 println!("\nSecurity considerations:");
139 println!("- Trust policies must explicitly allow cross-tenant access");
140 println!("- Use external_id for additional security");
141 println!("- Limit session duration to minimum required");
142 println!("- Attach restrictive permission policies to the role");
143
144 println!("\n✅ Example completed successfully!");
145 println!("Key takeaways:");
146 println!("- Cross-tenant access requires explicit trust policies");
147 println!("- STS provides temporary, limited-privilege credentials");
148 println!("- AssumeRole creates a session with the target role's permissions");
149 println!("- Credentials are time-limited and automatically expire");
150
151 Ok(())
152}examples/12_provider_specific_features.rs (line 29)
20async fn main() -> Result<(), Box<dyn std::error::Error>> {
21 println!("=== Provider-Specific Features ===\n");
22
23 let store = Arc::new(RwLock::new(InMemoryWamiStore::default()));
24
25 // === AWS: IAM ROLES WITH TRUST POLICIES ===
26 println!("Step 1: AWS IAM Role with Trust Policy...\n");
27
28 let _aws_provider = Arc::new(AwsProvider::new());
29 let aws_service = RoleService::new(store.clone(), "123456789012".to_string());
30
31 let aws_trust_policy = r#"{
32 "Version": "2012-10-17",
33 "Statement": [{
34 "Effect": "Allow",
35 "Principal": {"Service": "lambda.amazonaws.com"},
36 "Action": "sts:AssumeRole"
37 }]
38}"#;
39
40 let aws_role_req = CreateRoleRequest {
41 role_name: "lambda-execution-role".to_string(),
42 path: Some("/service-roles/".to_string()),
43 assume_role_policy_document: aws_trust_policy.to_string(),
44 description: Some("Role for Lambda function execution".to_string()),
45 max_session_duration: Some(3600),
46 permissions_boundary: None,
47 tags: None,
48 };
49
50 let aws_role = aws_service.create_role(aws_role_req).await?;
51 println!("✓ Created AWS Lambda execution role:");
52 println!(" - ARN: {}", aws_role.arn);
53 println!(" - Trust Policy: Allows lambda.amazonaws.com to assume");
54 println!(" - Use case: Serverless function execution");
55
56 // === GCP: SERVICE ACCOUNT PATTERN ===
57 println!("\n\nStep 2: GCP Service Account Pattern...\n");
58
59 let _gcp_provider = Arc::new(GcpProvider::new("my-gcp-project".to_string()));
60 let gcp_service = RoleService::new(store.clone(), "my-gcp-project".to_string());
61
62 let gcp_trust_policy = r#"{
63 "bindings": [{
64 "role": "roles/iam.serviceAccountUser",
65 "members": ["serviceAccount:compute@my-gcp-project.iam.gserviceaccount.com"]
66 }]
67}"#;
68
69 let gcp_role_req = CreateRoleRequest {
70 role_name: "compute-service-account".to_string(),
71 path: Some("/service-accounts/".to_string()),
72 assume_role_policy_document: gcp_trust_policy.to_string(),
73 description: Some("Service account for Compute Engine".to_string()),
74 max_session_duration: Some(3600),
75 permissions_boundary: None,
76 tags: None,
77 };
78
79 let gcp_role = gcp_service.create_role(gcp_role_req).await?;
80 println!("✓ Created GCP service account:");
81 println!(" - ARN: {}", gcp_role.arn);
82 println!(" - Bindings: Compute Engine service usage");
83 println!(" - Use case: VM instance identity");
84
85 // === AZURE: MANAGED IDENTITY PATTERN ===
86 println!("\n\nStep 3: Azure Managed Identity Pattern...\n");
87
88 let _azure_provider = Arc::new(AzureProvider::new(
89 "my-subscription".to_string(),
90 "default-rg".to_string(),
91 ));
92 let azure_service = RoleService::new(store.clone(), "my-subscription".to_string());
93
94 let azure_trust_policy = r#"{
95 "properties": {
96 "principalType": "ServicePrincipal",
97 "tenantId": "tenant-id",
98 "type": "SystemAssigned"
99 }
100}"#;
101
102 let azure_role_req = CreateRoleRequest {
103 role_name: "app-managed-identity".to_string(),
104 path: Some("/managed-identities/".to_string()),
105 assume_role_policy_document: azure_trust_policy.to_string(),
106 description: Some("Managed identity for App Service".to_string()),
107 max_session_duration: Some(3600),
108 permissions_boundary: None,
109 tags: None,
110 };
111
112 let azure_role = azure_service.create_role(azure_role_req).await?;
113 println!("✓ Created Azure managed identity:");
114 println!(" - ARN: {}", azure_role.arn);
115 println!(" - Type: System-assigned managed identity");
116 println!(" - Use case: App Service authentication");
117
118 // === COMPARE PATTERNS ===
119 println!("\n\nStep 4: Comparing provider identity patterns...\n");
120
121 println!("AWS IAM Roles:");
122 println!("- Trust policies define who can assume the role");
123 println!("- Used for cross-account and service-to-service access");
124 println!("- Temporary credentials via STS");
125 println!();
126 println!("GCP Service Accounts:");
127 println!("- Special type of account for applications");
128 println!("- IAM bindings control permissions");
129 println!("- Can be impersonated by other principals");
130 println!();
131 println!("Azure Managed Identities:");
132 println!("- Automatically managed by Azure");
133 println!("- System-assigned (bound to resource) or User-assigned");
134 println!("- No credential management required");
135
136 // === DEMONSTRATE UNIFIED VIEW ===
137 println!("\n\nStep 5: Unified view across providers...\n");
138
139 let (all_roles, _, _) = aws_service
140 .list_roles(ListRolesRequest {
141 path_prefix: None,
142 pagination: None,
143 })
144 .await?;
145 println!(
146 "✓ Total roles/identities across all providers: {}",
147 all_roles.len()
148 );
149 for role in &all_roles {
150 let provider = if role.arn.contains("aws") {
151 "AWS"
152 } else if role.arn.contains("gcp") {
153 "GCP"
154 } else {
155 "Azure"
156 };
157 println!(" - {} ({}) → {}", role.role_name, provider, role.arn);
158 }
159
160 println!("\n✅ Example completed successfully!");
161 println!("Key takeaways:");
162 println!("- Each provider has unique identity patterns");
163 println!("- WAMI abstracts differences while preserving provider semantics");
164 println!("- Trust policies define security boundaries");
165 println!("- Choose patterns based on provider strengths");
166
167 Ok(())
168}examples/16_role_based_access_control.rs (line 29)
21async fn main() -> Result<(), Box<dyn std::error::Error>> {
22 println!("=== Role-Based Access Control (RBAC) ===\n");
23
24 let store = Arc::new(RwLock::new(InMemoryWamiStore::default()));
25 let _provider = Arc::new(AwsProvider::new());
26 let account_id = "123456789012";
27
28 let user_service = UserService::new(store.clone(), account_id.to_string());
29 let role_service = RoleService::new(store.clone(), account_id.to_string());
30 let policy_service = PolicyService::new(store.clone(), account_id.to_string());
31
32 // === CREATE POLICIES ===
33 println!("Step 1: Creating role policies...\n");
34
35 let _admin_policy = policy_service.create_policy(CreatePolicyRequest {
36 policy_name: "AdminPolicy".to_string(),
37 path: Some("/rbac/".to_string()),
38 policy_document: r#"{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":"*","Resource":"*"}]}"#.to_string(),
39 description: Some("Full admin access".to_string()),
40 tags: None,
41 }).await?;
42 println!("✓ Created AdminPolicy");
43
44 let _dev_policy = policy_service.create_policy(CreatePolicyRequest {
45 policy_name: "DeveloperPolicy".to_string(),
46 path: Some("/rbac/".to_string()),
47 policy_document: r#"{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":["s3:*","lambda:*"],"Resource":"*"}]}"#.to_string(),
48 description: Some("Developer access to S3 and Lambda".to_string()),
49 tags: None,
50 }).await?;
51 println!("✓ Created DeveloperPolicy");
52
53 let _viewer_policy = policy_service.create_policy(CreatePolicyRequest {
54 policy_name: "ViewerPolicy".to_string(),
55 path: Some("/rbac/".to_string()),
56 policy_document: r#"{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":["s3:Get*","s3:List*"],"Resource":"*"}]}"#.to_string(),
57 description: Some("Read-only access".to_string()),
58 tags: None,
59 }).await?;
60 println!("✓ Created ViewerPolicy");
61
62 // === CREATE ROLES ===
63 println!("\n\nStep 2: Creating roles...\n");
64
65 let trust_policy = r#"{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"AWS":"*"},"Action":"sts:AssumeRole"}]}"#;
66
67 let admin_role = role_service
68 .create_role(CreateRoleRequest {
69 role_name: "Admin".to_string(),
70 path: Some("/rbac/".to_string()),
71 assume_role_policy_document: trust_policy.to_string(),
72 description: Some("Administrator role".to_string()),
73 max_session_duration: Some(3600),
74 permissions_boundary: None,
75 tags: None,
76 })
77 .await?;
78 println!("✓ Created Admin role: {}", admin_role.arn);
79
80 let dev_role = role_service
81 .create_role(CreateRoleRequest {
82 role_name: "Developer".to_string(),
83 path: Some("/rbac/".to_string()),
84 assume_role_policy_document: trust_policy.to_string(),
85 description: Some("Developer role".to_string()),
86 max_session_duration: Some(7200),
87 permissions_boundary: None,
88 tags: None,
89 })
90 .await?;
91 println!("✓ Created Developer role: {}", dev_role.arn);
92
93 let viewer_role = role_service
94 .create_role(CreateRoleRequest {
95 role_name: "Viewer".to_string(),
96 path: Some("/rbac/".to_string()),
97 assume_role_policy_document: trust_policy.to_string(),
98 description: Some("Viewer role".to_string()),
99 max_session_duration: Some(3600),
100 permissions_boundary: None,
101 tags: None,
102 })
103 .await?;
104 println!("✓ Created Viewer role: {}", viewer_role.arn);
105
106 // === CREATE USERS ===
107 println!("\n\nStep 3: Creating users...\n");
108
109 user_service
110 .create_user(CreateUserRequest {
111 user_name: "alice".to_string(),
112 path: Some("/team/".to_string()),
113 permissions_boundary: None,
114 tags: Some(vec![wami::types::Tag {
115 key: "Role".to_string(),
116 value: "Admin".to_string(),
117 }]),
118 })
119 .await?;
120 println!("✓ Created alice (will be assigned Admin role)");
121
122 user_service
123 .create_user(CreateUserRequest {
124 user_name: "bob".to_string(),
125 path: Some("/team/".to_string()),
126 permissions_boundary: None,
127 tags: Some(vec![wami::types::Tag {
128 key: "Role".to_string(),
129 value: "Developer".to_string(),
130 }]),
131 })
132 .await?;
133 println!("✓ Created bob (will be assigned Developer role)");
134
135 user_service
136 .create_user(CreateUserRequest {
137 user_name: "charlie".to_string(),
138 path: Some("/team/".to_string()),
139 permissions_boundary: None,
140 tags: Some(vec![wami::types::Tag {
141 key: "Role".to_string(),
142 value: "Viewer".to_string(),
143 }]),
144 })
145 .await?;
146 println!("✓ Created charlie (will be assigned Viewer role)");
147
148 // === DEMONSTRATE RBAC ===
149 println!("\n\nStep 4: Understanding RBAC pattern...\n");
150
151 println!("RBAC structure created:");
152 println!();
153 println!("Roles → Policies:");
154 println!(" Admin → AdminPolicy (full access)");
155 println!(" Developer → DeveloperPolicy (S3 + Lambda)");
156 println!(" Viewer → ViewerPolicy (read-only)");
157 println!();
158 println!("Users → Roles (via AssumeRole):");
159 println!(" alice → Admin");
160 println!(" bob → Developer");
161 println!(" charlie → Viewer");
162 println!();
163 println!("Benefits of RBAC:");
164 println!("- Centralized permission management");
165 println!("- Easy to add/remove users from roles");
166 println!("- Consistent permissions across teams");
167 println!("- Simplified auditing");
168
169 println!("\n✅ Example completed successfully!");
170
171 Ok(())
172}examples/23_permissions_boundaries.rs (line 39)
30async fn main() -> Result<(), Box<dyn std::error::Error>> {
31 println!("=== WAMI Example 23: Permissions Boundaries ===\n");
32
33 // Initialize store and services
34 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 // ==========================================
45 // Part 1: Create User with Admin Policy
46 // ==========================================
47 println!("📋 Part 1: Creating User with Admin Policy\n");
48
49 // Create a user
50 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 // Create an admin policy (allows all actions)
61 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 // ==========================================
83 // Part 2: Create S3-Only Boundary Policy
84 // ==========================================
85 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 // ==========================================
109 // Part 3: Test Without Boundary
110 // ==========================================
111 println!("📋 Part 3: Testing Permissions WITHOUT Boundary\n");
112
113 // Simulate alice's permissions (admin policy allows everything)
114 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 // ==========================================
140 // Part 4: Attach Boundary to User
141 // ==========================================
142 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 // ==========================================
157 // Part 5: Test WITH Boundary
158 // ==========================================
159 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 // ==========================================
195 // Part 6: Boundary with Roles
196 // ==========================================
197 println!("📋 Part 6: Using Boundaries with Roles\n");
198
199 // Create a role with assume policy
200 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 // Create a read-only boundary
223 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 // Attach boundary to role
250 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 // Test role with boundary
261 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 // ==========================================
292 // Part 7: Removing Boundaries
293 // ==========================================
294 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 // ==========================================
316 // Part 8: Real-World Use Cases
317 // ==========================================
318 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}Sourcepub fn with_provider(&self, provider: Arc<dyn CloudProvider>) -> Self
pub fn with_provider(&self, provider: Arc<dyn CloudProvider>) -> Self
Returns a new service instance with different provider
Sourcepub async fn create_role(&self, request: CreateRoleRequest) -> Result<Role>
pub async fn create_role(&self, request: CreateRoleRequest) -> Result<Role>
Create a new role
Examples found in repository?
examples/19_role_assumption_workflow.rs (lines 48-56)
21async fn main() -> Result<(), Box<dyn std::error::Error>> {
22 println!("=== Role Assumption Workflow ===\n");
23
24 let store = Arc::new(RwLock::new(InMemoryWamiStore::default()));
25 let _provider = Arc::new(AwsProvider::new());
26 let account_id = "123456789012";
27
28 let user_service = UserService::new(store.clone(), account_id.to_string());
29 let role_service = RoleService::new(store.clone(), account_id.to_string());
30 let sts_service = AssumeRoleService::new(store.clone(), account_id.to_string());
31
32 // Create user
33 println!("Step 1: Creating user...\n");
34 let alice = user_service
35 .create_user(CreateUserRequest {
36 user_name: "alice".to_string(),
37 path: Some("/".to_string()),
38 permissions_boundary: None,
39 tags: None,
40 })
41 .await?;
42 println!("✓ Created alice: {}", alice.arn);
43
44 // Create elevated role
45 println!("\nStep 2: Creating admin role...\n");
46 let trust_policy = r#"{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"AWS":"*"},"Action":"sts:AssumeRole"}]}"#;
47 let role = role_service
48 .create_role(CreateRoleRequest {
49 role_name: "AdminRole".to_string(),
50 path: Some("/".to_string()),
51 assume_role_policy_document: trust_policy.to_string(),
52 description: Some("Admin role for elevated access".to_string()),
53 max_session_duration: Some(3600),
54 permissions_boundary: None,
55 tags: None,
56 })
57 .await?;
58 println!("✓ Created AdminRole: {}", role.arn);
59
60 // Assume role
61 println!("\nStep 3: Alice assuming AdminRole...\n");
62 let assume_req = AssumeRoleRequest {
63 role_arn: role.arn.clone(),
64 role_session_name: "alice-admin-session".to_string(),
65 duration_seconds: Some(3600),
66 external_id: None,
67 policy: None,
68 };
69
70 let response = sts_service.assume_role(assume_req, &alice.arn).await?;
71 println!("✓ Successfully assumed role!");
72 println!(" Assumed Role ARN: {}", response.assumed_role_user.arn);
73 println!(" Access Key: {}", response.credentials.access_key_id);
74 println!(" Expiration: {}", response.credentials.expiration);
75
76 println!("\n✅ Example completed successfully!");
77 println!("Key takeaways:");
78 println!("- AssumeRole provides temporary elevated permissions");
79 println!("- Trust policies control who can assume roles");
80 println!("- Session credentials expire automatically");
81
82 Ok(())
83}More examples
examples/03_service_layer_intro.rs (line 81)
21async fn main() -> Result<(), Box<dyn std::error::Error>> {
22 println!("=== Service Layer Introduction ===\n");
23
24 // Step 1: Initialize store with Arc<RwLock> for thread-safe access
25 println!("Step 1: Initializing services...\n");
26 let store = Arc::new(RwLock::new(InMemoryWamiStore::default()));
27 let _provider = Arc::new(AwsProvider::new());
28 let account_id = "123456789012";
29
30 // Create services
31 let user_service = UserService::new(store.clone(), account_id.to_string());
32 let group_service = GroupService::new(store.clone(), account_id.to_string());
33 let role_service = RoleService::new(store.clone(), account_id.to_string());
34
35 println!("✓ Services initialized");
36
37 // === CREATE Operations via Services ===
38 println!("\nStep 2: Creating resources via services...\n");
39
40 // Create users
41 println!("Creating users...");
42 let alice_req = CreateUserRequest {
43 user_name: "alice".to_string(),
44 path: Some("/users/".to_string()),
45 permissions_boundary: None,
46 tags: None,
47 };
48 let alice = user_service.create_user(alice_req).await?;
49 println!("✓ Created user: {}", alice.user_name);
50
51 let bob_req = CreateUserRequest {
52 user_name: "bob".to_string(),
53 path: Some("/users/".to_string()),
54 permissions_boundary: None,
55 tags: None,
56 };
57 user_service.create_user(bob_req).await?;
58 println!("✓ Created user: bob");
59
60 // Create groups
61 println!("\nCreating groups...");
62 let dev_group_req = CreateGroupRequest {
63 group_name: "developers".to_string(),
64 path: Some("/groups/".to_string()),
65 tags: None,
66 };
67 let dev_group = group_service.create_group(dev_group_req).await?;
68 println!("✓ Created group: {}", dev_group.group_name);
69
70 // Create role
71 println!("\nCreating role...");
72 let role_req = CreateRoleRequest {
73 role_name: "deploy-role".to_string(),
74 path: Some("/roles/".to_string()),
75 assume_role_policy_document: r#"{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"AWS":"*"},"Action":"sts:AssumeRole"}]}"#.to_string(),
76 description: Some("Role for deployment".to_string()),
77 max_session_duration: Some(3600),
78 permissions_boundary: None,
79 tags: None,
80 };
81 let role = role_service.create_role(role_req).await?;
82 println!("✓ Created role: {}", role.role_name);
83
84 // === READ Operations via Services ===
85 println!("\n\nStep 3: Reading resources via services...\n");
86
87 // Get specific user
88 let alice_retrieved = user_service.get_user("alice").await?;
89 if let Some(user) = alice_retrieved {
90 println!("✓ Retrieved user 'alice':");
91 println!(" - User ID: {}", user.user_id);
92 println!(" - ARN: {}", user.arn);
93 }
94
95 // List users
96 let users = user_service
97 .list_users(ListUsersRequest {
98 path_prefix: None,
99 pagination: None,
100 })
101 .await?;
102 println!("\n✓ Found {} users via service:", users.0.len());
103 for user in &users.0 {
104 println!(" - {}", user.user_name);
105 }
106
107 // === UPDATE Operations via Services ===
108 println!("\n\nStep 4: Updating resources via services...\n");
109
110 use wami::wami::identity::user::requests::UpdateUserRequest;
111 let update_req = UpdateUserRequest {
112 user_name: "alice".to_string(),
113 new_user_name: None,
114 new_path: Some("/admin-users/".to_string()),
115 };
116 user_service.update_user(update_req).await?;
117 println!("✓ Updated alice's path to '/admin-users/'");
118
119 // === DELETE Operations via Services ===
120 println!("\n\nStep 5: Deleting resources via services...\n");
121
122 user_service.delete_user("bob").await?;
123 println!("✓ Deleted user 'bob'");
124
125 // Verify deletion
126 let bob_check = user_service.get_user("bob").await?;
127 if bob_check.is_none() {
128 println!(" Verified: bob no longer exists");
129 }
130
131 println!("\n✅ Example completed successfully!");
132 println!("Key takeaways:");
133 println!("- Services provide a higher-level API than raw store access");
134 println!("- Arc<RwLock<Store>> enables thread-safe concurrent operations");
135 println!("- Services use request/response DTOs for clean API contracts");
136 println!("- Services encapsulate business logic and validation");
137
138 Ok(())
139}examples/07_cross_tenant_role_assumption.rs (line 88)
22async fn main() -> Result<(), Box<dyn std::error::Error>> {
23 println!("=== Cross-Tenant Role Assumption ===\n");
24
25 let store = Arc::new(RwLock::new(InMemoryWamiStore::default()));
26 let _provider = Arc::new(AwsProvider::new());
27
28 // === SETUP TENANTS ===
29 println!("Step 1: Creating two tenants...\n");
30
31 let tenant_service = TenantService::new(store.clone(), "root".to_string());
32
33 // Tenant A (source)
34 let _tenant_a_id = TenantId::new("company-a");
35 tenant_service
36 .create_tenant("company-a".to_string(), Some("Company A".to_string()), None)
37 .await?;
38 println!("✓ Created tenant: company-a");
39
40 // Tenant B (target)
41 let _tenant_b_id = TenantId::new("company-b");
42 tenant_service
43 .create_tenant("company-b".to_string(), Some("Company B".to_string()), None)
44 .await?;
45 println!("✓ Created tenant: company-b");
46
47 // === CREATE USER IN TENANT A ===
48 println!("\nStep 2: Creating user in tenant A...\n");
49
50 let user_service_a = UserService::new(store.clone(), "company-a".to_string());
51
52 let alice_req = CreateUserRequest {
53 user_name: "alice".to_string(),
54 path: Some("/".to_string()),
55 permissions_boundary: None,
56 tags: None,
57 };
58 let alice = user_service_a.create_user(alice_req).await?;
59 println!("✓ Created alice in company-a");
60 println!(" ARN: {}", alice.arn);
61
62 // === CREATE ROLE IN TENANT B WITH TRUST POLICY ===
63 println!("\nStep 3: Creating cross-tenant role in tenant B...\n");
64
65 let role_service_b = RoleService::new(store.clone(), "company-b".to_string());
66
67 // Trust policy allowing Company A users to assume this role
68 let trust_policy = r#"{
69 "Version": "2012-10-17",
70 "Statement": [{
71 "Effect": "Allow",
72 "Principal": {"AWS": "arn:aws:iam::company-a:root"},
73 "Action": "sts:AssumeRole"
74 }]
75}"#
76 .to_string();
77
78 let role_req = CreateRoleRequest {
79 role_name: "cross-tenant-reader".to_string(),
80 path: Some("/".to_string()),
81 assume_role_policy_document: trust_policy,
82 description: Some("Role for cross-tenant read access".to_string()),
83 max_session_duration: Some(3600),
84 permissions_boundary: None,
85 tags: None,
86 };
87
88 let role = role_service_b.create_role(role_req).await?;
89 println!("✓ Created cross-tenant-reader role in company-b");
90 println!(" Role ARN: {}", role.arn);
91
92 // === ASSUME ROLE ACROSS TENANTS ===
93 println!("\nStep 4: Alice assuming role in company-b...\n");
94
95 let sts_service = AssumeRoleService::new(
96 store.clone(),
97 "company-a".to_string(), // Operating from tenant A
98 );
99
100 let assume_req = AssumeRoleRequest {
101 role_arn: role.arn.clone(),
102 role_session_name: "alice-cross-tenant-session".to_string(),
103 duration_seconds: Some(3600),
104 external_id: None,
105 policy: None,
106 };
107
108 let assume_response = sts_service.assume_role(assume_req, &alice.arn).await?;
109 println!("✓ Alice successfully assumed cross-tenant role!");
110 println!(" Credentials:");
111 println!(
112 " - Access Key: {}",
113 assume_response.credentials.access_key_id
114 );
115 println!(
116 " - Session Token: {}...",
117 &assume_response.credentials.session_token[..20]
118 );
119 println!(
120 " - Expiration: {}",
121 assume_response.credentials.expiration
122 );
123 println!("\n Assumed Role:");
124 println!(" - ARN: {}", assume_response.assumed_role_user.arn);
125 println!(
126 " - User ID: {}",
127 assume_response.assumed_role_user.assumed_role_id
128 );
129
130 // === DEMONSTRATE USE CASE ===
131 println!("\n\nStep 5: Understanding cross-tenant scenarios...\n");
132
133 println!("Cross-tenant role assumption enables:");
134 println!("- Partner company collaboration");
135 println!("- Outsourced operations (DevOps team accessing client resources)");
136 println!("- Centralized security auditing across organizations");
137 println!("- Merger & acquisition transitional access");
138 println!("\nSecurity considerations:");
139 println!("- Trust policies must explicitly allow cross-tenant access");
140 println!("- Use external_id for additional security");
141 println!("- Limit session duration to minimum required");
142 println!("- Attach restrictive permission policies to the role");
143
144 println!("\n✅ Example completed successfully!");
145 println!("Key takeaways:");
146 println!("- Cross-tenant access requires explicit trust policies");
147 println!("- STS provides temporary, limited-privilege credentials");
148 println!("- AssumeRole creates a session with the target role's permissions");
149 println!("- Credentials are time-limited and automatically expire");
150
151 Ok(())
152}examples/12_provider_specific_features.rs (line 50)
20async fn main() -> Result<(), Box<dyn std::error::Error>> {
21 println!("=== Provider-Specific Features ===\n");
22
23 let store = Arc::new(RwLock::new(InMemoryWamiStore::default()));
24
25 // === AWS: IAM ROLES WITH TRUST POLICIES ===
26 println!("Step 1: AWS IAM Role with Trust Policy...\n");
27
28 let _aws_provider = Arc::new(AwsProvider::new());
29 let aws_service = RoleService::new(store.clone(), "123456789012".to_string());
30
31 let aws_trust_policy = r#"{
32 "Version": "2012-10-17",
33 "Statement": [{
34 "Effect": "Allow",
35 "Principal": {"Service": "lambda.amazonaws.com"},
36 "Action": "sts:AssumeRole"
37 }]
38}"#;
39
40 let aws_role_req = CreateRoleRequest {
41 role_name: "lambda-execution-role".to_string(),
42 path: Some("/service-roles/".to_string()),
43 assume_role_policy_document: aws_trust_policy.to_string(),
44 description: Some("Role for Lambda function execution".to_string()),
45 max_session_duration: Some(3600),
46 permissions_boundary: None,
47 tags: None,
48 };
49
50 let aws_role = aws_service.create_role(aws_role_req).await?;
51 println!("✓ Created AWS Lambda execution role:");
52 println!(" - ARN: {}", aws_role.arn);
53 println!(" - Trust Policy: Allows lambda.amazonaws.com to assume");
54 println!(" - Use case: Serverless function execution");
55
56 // === GCP: SERVICE ACCOUNT PATTERN ===
57 println!("\n\nStep 2: GCP Service Account Pattern...\n");
58
59 let _gcp_provider = Arc::new(GcpProvider::new("my-gcp-project".to_string()));
60 let gcp_service = RoleService::new(store.clone(), "my-gcp-project".to_string());
61
62 let gcp_trust_policy = r#"{
63 "bindings": [{
64 "role": "roles/iam.serviceAccountUser",
65 "members": ["serviceAccount:compute@my-gcp-project.iam.gserviceaccount.com"]
66 }]
67}"#;
68
69 let gcp_role_req = CreateRoleRequest {
70 role_name: "compute-service-account".to_string(),
71 path: Some("/service-accounts/".to_string()),
72 assume_role_policy_document: gcp_trust_policy.to_string(),
73 description: Some("Service account for Compute Engine".to_string()),
74 max_session_duration: Some(3600),
75 permissions_boundary: None,
76 tags: None,
77 };
78
79 let gcp_role = gcp_service.create_role(gcp_role_req).await?;
80 println!("✓ Created GCP service account:");
81 println!(" - ARN: {}", gcp_role.arn);
82 println!(" - Bindings: Compute Engine service usage");
83 println!(" - Use case: VM instance identity");
84
85 // === AZURE: MANAGED IDENTITY PATTERN ===
86 println!("\n\nStep 3: Azure Managed Identity Pattern...\n");
87
88 let _azure_provider = Arc::new(AzureProvider::new(
89 "my-subscription".to_string(),
90 "default-rg".to_string(),
91 ));
92 let azure_service = RoleService::new(store.clone(), "my-subscription".to_string());
93
94 let azure_trust_policy = r#"{
95 "properties": {
96 "principalType": "ServicePrincipal",
97 "tenantId": "tenant-id",
98 "type": "SystemAssigned"
99 }
100}"#;
101
102 let azure_role_req = CreateRoleRequest {
103 role_name: "app-managed-identity".to_string(),
104 path: Some("/managed-identities/".to_string()),
105 assume_role_policy_document: azure_trust_policy.to_string(),
106 description: Some("Managed identity for App Service".to_string()),
107 max_session_duration: Some(3600),
108 permissions_boundary: None,
109 tags: None,
110 };
111
112 let azure_role = azure_service.create_role(azure_role_req).await?;
113 println!("✓ Created Azure managed identity:");
114 println!(" - ARN: {}", azure_role.arn);
115 println!(" - Type: System-assigned managed identity");
116 println!(" - Use case: App Service authentication");
117
118 // === COMPARE PATTERNS ===
119 println!("\n\nStep 4: Comparing provider identity patterns...\n");
120
121 println!("AWS IAM Roles:");
122 println!("- Trust policies define who can assume the role");
123 println!("- Used for cross-account and service-to-service access");
124 println!("- Temporary credentials via STS");
125 println!();
126 println!("GCP Service Accounts:");
127 println!("- Special type of account for applications");
128 println!("- IAM bindings control permissions");
129 println!("- Can be impersonated by other principals");
130 println!();
131 println!("Azure Managed Identities:");
132 println!("- Automatically managed by Azure");
133 println!("- System-assigned (bound to resource) or User-assigned");
134 println!("- No credential management required");
135
136 // === DEMONSTRATE UNIFIED VIEW ===
137 println!("\n\nStep 5: Unified view across providers...\n");
138
139 let (all_roles, _, _) = aws_service
140 .list_roles(ListRolesRequest {
141 path_prefix: None,
142 pagination: None,
143 })
144 .await?;
145 println!(
146 "✓ Total roles/identities across all providers: {}",
147 all_roles.len()
148 );
149 for role in &all_roles {
150 let provider = if role.arn.contains("aws") {
151 "AWS"
152 } else if role.arn.contains("gcp") {
153 "GCP"
154 } else {
155 "Azure"
156 };
157 println!(" - {} ({}) → {}", role.role_name, provider, role.arn);
158 }
159
160 println!("\n✅ Example completed successfully!");
161 println!("Key takeaways:");
162 println!("- Each provider has unique identity patterns");
163 println!("- WAMI abstracts differences while preserving provider semantics");
164 println!("- Trust policies define security boundaries");
165 println!("- Choose patterns based on provider strengths");
166
167 Ok(())
168}examples/16_role_based_access_control.rs (lines 68-76)
21async fn main() -> Result<(), Box<dyn std::error::Error>> {
22 println!("=== Role-Based Access Control (RBAC) ===\n");
23
24 let store = Arc::new(RwLock::new(InMemoryWamiStore::default()));
25 let _provider = Arc::new(AwsProvider::new());
26 let account_id = "123456789012";
27
28 let user_service = UserService::new(store.clone(), account_id.to_string());
29 let role_service = RoleService::new(store.clone(), account_id.to_string());
30 let policy_service = PolicyService::new(store.clone(), account_id.to_string());
31
32 // === CREATE POLICIES ===
33 println!("Step 1: Creating role policies...\n");
34
35 let _admin_policy = policy_service.create_policy(CreatePolicyRequest {
36 policy_name: "AdminPolicy".to_string(),
37 path: Some("/rbac/".to_string()),
38 policy_document: r#"{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":"*","Resource":"*"}]}"#.to_string(),
39 description: Some("Full admin access".to_string()),
40 tags: None,
41 }).await?;
42 println!("✓ Created AdminPolicy");
43
44 let _dev_policy = policy_service.create_policy(CreatePolicyRequest {
45 policy_name: "DeveloperPolicy".to_string(),
46 path: Some("/rbac/".to_string()),
47 policy_document: r#"{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":["s3:*","lambda:*"],"Resource":"*"}]}"#.to_string(),
48 description: Some("Developer access to S3 and Lambda".to_string()),
49 tags: None,
50 }).await?;
51 println!("✓ Created DeveloperPolicy");
52
53 let _viewer_policy = policy_service.create_policy(CreatePolicyRequest {
54 policy_name: "ViewerPolicy".to_string(),
55 path: Some("/rbac/".to_string()),
56 policy_document: r#"{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":["s3:Get*","s3:List*"],"Resource":"*"}]}"#.to_string(),
57 description: Some("Read-only access".to_string()),
58 tags: None,
59 }).await?;
60 println!("✓ Created ViewerPolicy");
61
62 // === CREATE ROLES ===
63 println!("\n\nStep 2: Creating roles...\n");
64
65 let trust_policy = r#"{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"AWS":"*"},"Action":"sts:AssumeRole"}]}"#;
66
67 let admin_role = role_service
68 .create_role(CreateRoleRequest {
69 role_name: "Admin".to_string(),
70 path: Some("/rbac/".to_string()),
71 assume_role_policy_document: trust_policy.to_string(),
72 description: Some("Administrator role".to_string()),
73 max_session_duration: Some(3600),
74 permissions_boundary: None,
75 tags: None,
76 })
77 .await?;
78 println!("✓ Created Admin role: {}", admin_role.arn);
79
80 let dev_role = role_service
81 .create_role(CreateRoleRequest {
82 role_name: "Developer".to_string(),
83 path: Some("/rbac/".to_string()),
84 assume_role_policy_document: trust_policy.to_string(),
85 description: Some("Developer role".to_string()),
86 max_session_duration: Some(7200),
87 permissions_boundary: None,
88 tags: None,
89 })
90 .await?;
91 println!("✓ Created Developer role: {}", dev_role.arn);
92
93 let viewer_role = role_service
94 .create_role(CreateRoleRequest {
95 role_name: "Viewer".to_string(),
96 path: Some("/rbac/".to_string()),
97 assume_role_policy_document: trust_policy.to_string(),
98 description: Some("Viewer role".to_string()),
99 max_session_duration: Some(3600),
100 permissions_boundary: None,
101 tags: None,
102 })
103 .await?;
104 println!("✓ Created Viewer role: {}", viewer_role.arn);
105
106 // === CREATE USERS ===
107 println!("\n\nStep 3: Creating users...\n");
108
109 user_service
110 .create_user(CreateUserRequest {
111 user_name: "alice".to_string(),
112 path: Some("/team/".to_string()),
113 permissions_boundary: None,
114 tags: Some(vec![wami::types::Tag {
115 key: "Role".to_string(),
116 value: "Admin".to_string(),
117 }]),
118 })
119 .await?;
120 println!("✓ Created alice (will be assigned Admin role)");
121
122 user_service
123 .create_user(CreateUserRequest {
124 user_name: "bob".to_string(),
125 path: Some("/team/".to_string()),
126 permissions_boundary: None,
127 tags: Some(vec![wami::types::Tag {
128 key: "Role".to_string(),
129 value: "Developer".to_string(),
130 }]),
131 })
132 .await?;
133 println!("✓ Created bob (will be assigned Developer role)");
134
135 user_service
136 .create_user(CreateUserRequest {
137 user_name: "charlie".to_string(),
138 path: Some("/team/".to_string()),
139 permissions_boundary: None,
140 tags: Some(vec![wami::types::Tag {
141 key: "Role".to_string(),
142 value: "Viewer".to_string(),
143 }]),
144 })
145 .await?;
146 println!("✓ Created charlie (will be assigned Viewer role)");
147
148 // === DEMONSTRATE RBAC ===
149 println!("\n\nStep 4: Understanding RBAC pattern...\n");
150
151 println!("RBAC structure created:");
152 println!();
153 println!("Roles → Policies:");
154 println!(" Admin → AdminPolicy (full access)");
155 println!(" Developer → DeveloperPolicy (S3 + Lambda)");
156 println!(" Viewer → ViewerPolicy (read-only)");
157 println!();
158 println!("Users → Roles (via AssumeRole):");
159 println!(" alice → Admin");
160 println!(" bob → Developer");
161 println!(" charlie → Viewer");
162 println!();
163 println!("Benefits of RBAC:");
164 println!("- Centralized permission management");
165 println!("- Easy to add/remove users from roles");
166 println!("- Consistent permissions across teams");
167 println!("- Simplified auditing");
168
169 println!("\n✅ Example completed successfully!");
170
171 Ok(())
172}examples/23_permissions_boundaries.rs (line 218)
30async fn main() -> Result<(), Box<dyn std::error::Error>> {
31 println!("=== WAMI Example 23: Permissions Boundaries ===\n");
32
33 // Initialize store and services
34 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 // ==========================================
45 // Part 1: Create User with Admin Policy
46 // ==========================================
47 println!("📋 Part 1: Creating User with Admin Policy\n");
48
49 // Create a user
50 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 // Create an admin policy (allows all actions)
61 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 // ==========================================
83 // Part 2: Create S3-Only Boundary Policy
84 // ==========================================
85 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 // ==========================================
109 // Part 3: Test Without Boundary
110 // ==========================================
111 println!("📋 Part 3: Testing Permissions WITHOUT Boundary\n");
112
113 // Simulate alice's permissions (admin policy allows everything)
114 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 // ==========================================
140 // Part 4: Attach Boundary to User
141 // ==========================================
142 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 // ==========================================
157 // Part 5: Test WITH Boundary
158 // ==========================================
159 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 // ==========================================
195 // Part 6: Boundary with Roles
196 // ==========================================
197 println!("📋 Part 6: Using Boundaries with Roles\n");
198
199 // Create a role with assume policy
200 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 // Create a read-only boundary
223 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 // Attach boundary to role
250 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 // Test role with boundary
261 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 // ==========================================
292 // Part 7: Removing Boundaries
293 // ==========================================
294 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 // ==========================================
316 // Part 8: Real-World Use Cases
317 // ==========================================
318 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}Sourcepub async fn update_role(&self, request: UpdateRoleRequest) -> Result<Role>
pub async fn update_role(&self, request: UpdateRoleRequest) -> Result<Role>
Update a role
Sourcepub async fn delete_role(&self, role_name: &str) -> Result<()>
pub async fn delete_role(&self, role_name: &str) -> Result<()>
Delete a role
Sourcepub async fn list_roles(
&self,
request: ListRolesRequest,
) -> Result<(Vec<Role>, bool, Option<String>)>
pub async fn list_roles( &self, request: ListRolesRequest, ) -> Result<(Vec<Role>, bool, Option<String>)>
List roles with optional filtering
Examples found in repository?
examples/12_provider_specific_features.rs (lines 140-143)
20async fn main() -> Result<(), Box<dyn std::error::Error>> {
21 println!("=== Provider-Specific Features ===\n");
22
23 let store = Arc::new(RwLock::new(InMemoryWamiStore::default()));
24
25 // === AWS: IAM ROLES WITH TRUST POLICIES ===
26 println!("Step 1: AWS IAM Role with Trust Policy...\n");
27
28 let _aws_provider = Arc::new(AwsProvider::new());
29 let aws_service = RoleService::new(store.clone(), "123456789012".to_string());
30
31 let aws_trust_policy = r#"{
32 "Version": "2012-10-17",
33 "Statement": [{
34 "Effect": "Allow",
35 "Principal": {"Service": "lambda.amazonaws.com"},
36 "Action": "sts:AssumeRole"
37 }]
38}"#;
39
40 let aws_role_req = CreateRoleRequest {
41 role_name: "lambda-execution-role".to_string(),
42 path: Some("/service-roles/".to_string()),
43 assume_role_policy_document: aws_trust_policy.to_string(),
44 description: Some("Role for Lambda function execution".to_string()),
45 max_session_duration: Some(3600),
46 permissions_boundary: None,
47 tags: None,
48 };
49
50 let aws_role = aws_service.create_role(aws_role_req).await?;
51 println!("✓ Created AWS Lambda execution role:");
52 println!(" - ARN: {}", aws_role.arn);
53 println!(" - Trust Policy: Allows lambda.amazonaws.com to assume");
54 println!(" - Use case: Serverless function execution");
55
56 // === GCP: SERVICE ACCOUNT PATTERN ===
57 println!("\n\nStep 2: GCP Service Account Pattern...\n");
58
59 let _gcp_provider = Arc::new(GcpProvider::new("my-gcp-project".to_string()));
60 let gcp_service = RoleService::new(store.clone(), "my-gcp-project".to_string());
61
62 let gcp_trust_policy = r#"{
63 "bindings": [{
64 "role": "roles/iam.serviceAccountUser",
65 "members": ["serviceAccount:compute@my-gcp-project.iam.gserviceaccount.com"]
66 }]
67}"#;
68
69 let gcp_role_req = CreateRoleRequest {
70 role_name: "compute-service-account".to_string(),
71 path: Some("/service-accounts/".to_string()),
72 assume_role_policy_document: gcp_trust_policy.to_string(),
73 description: Some("Service account for Compute Engine".to_string()),
74 max_session_duration: Some(3600),
75 permissions_boundary: None,
76 tags: None,
77 };
78
79 let gcp_role = gcp_service.create_role(gcp_role_req).await?;
80 println!("✓ Created GCP service account:");
81 println!(" - ARN: {}", gcp_role.arn);
82 println!(" - Bindings: Compute Engine service usage");
83 println!(" - Use case: VM instance identity");
84
85 // === AZURE: MANAGED IDENTITY PATTERN ===
86 println!("\n\nStep 3: Azure Managed Identity Pattern...\n");
87
88 let _azure_provider = Arc::new(AzureProvider::new(
89 "my-subscription".to_string(),
90 "default-rg".to_string(),
91 ));
92 let azure_service = RoleService::new(store.clone(), "my-subscription".to_string());
93
94 let azure_trust_policy = r#"{
95 "properties": {
96 "principalType": "ServicePrincipal",
97 "tenantId": "tenant-id",
98 "type": "SystemAssigned"
99 }
100}"#;
101
102 let azure_role_req = CreateRoleRequest {
103 role_name: "app-managed-identity".to_string(),
104 path: Some("/managed-identities/".to_string()),
105 assume_role_policy_document: azure_trust_policy.to_string(),
106 description: Some("Managed identity for App Service".to_string()),
107 max_session_duration: Some(3600),
108 permissions_boundary: None,
109 tags: None,
110 };
111
112 let azure_role = azure_service.create_role(azure_role_req).await?;
113 println!("✓ Created Azure managed identity:");
114 println!(" - ARN: {}", azure_role.arn);
115 println!(" - Type: System-assigned managed identity");
116 println!(" - Use case: App Service authentication");
117
118 // === COMPARE PATTERNS ===
119 println!("\n\nStep 4: Comparing provider identity patterns...\n");
120
121 println!("AWS IAM Roles:");
122 println!("- Trust policies define who can assume the role");
123 println!("- Used for cross-account and service-to-service access");
124 println!("- Temporary credentials via STS");
125 println!();
126 println!("GCP Service Accounts:");
127 println!("- Special type of account for applications");
128 println!("- IAM bindings control permissions");
129 println!("- Can be impersonated by other principals");
130 println!();
131 println!("Azure Managed Identities:");
132 println!("- Automatically managed by Azure");
133 println!("- System-assigned (bound to resource) or User-assigned");
134 println!("- No credential management required");
135
136 // === DEMONSTRATE UNIFIED VIEW ===
137 println!("\n\nStep 5: Unified view across providers...\n");
138
139 let (all_roles, _, _) = aws_service
140 .list_roles(ListRolesRequest {
141 path_prefix: None,
142 pagination: None,
143 })
144 .await?;
145 println!(
146 "✓ Total roles/identities across all providers: {}",
147 all_roles.len()
148 );
149 for role in &all_roles {
150 let provider = if role.arn.contains("aws") {
151 "AWS"
152 } else if role.arn.contains("gcp") {
153 "GCP"
154 } else {
155 "Azure"
156 };
157 println!(" - {} ({}) → {}", role.role_name, provider, role.arn);
158 }
159
160 println!("\n✅ Example completed successfully!");
161 println!("Key takeaways:");
162 println!("- Each provider has unique identity patterns");
163 println!("- WAMI abstracts differences while preserving provider semantics");
164 println!("- Trust policies define security boundaries");
165 println!("- Choose patterns based on provider strengths");
166
167 Ok(())
168}Auto Trait Implementations§
impl<S> Freeze for RoleService<S>
impl<S> !RefUnwindSafe for RoleService<S>
impl<S> Send for RoleService<S>
impl<S> Sync for RoleService<S>
impl<S> Unpin for RoleService<S>
impl<S> !UnwindSafe for RoleService<S>
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
Converts
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
Converts
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreCreates a shared type from an unshared type.