RoleService

Struct RoleService 

Source
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>

Source

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
Hide additional 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}
Source

pub fn with_provider(&self, provider: Arc<dyn CloudProvider>) -> Self

Returns a new service instance with different provider

Source

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
Hide additional 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}
Source

pub async fn get_role(&self, role_name: &str) -> Result<Option<Role>>

Get a role by name

Source

pub async fn update_role(&self, request: UpdateRoleRequest) -> Result<Role>

Update a role

Source

pub async fn delete_role(&self, role_name: &str) -> Result<()>

Delete a role

Source

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>
where S: Send + Sync,

§

impl<S> Sync for RoleService<S>
where S: Send + Sync,

§

impl<S> Unpin for RoleService<S>

§

impl<S> !UnwindSafe for RoleService<S>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

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 more
Source§

impl<Unshared, Shared> IntoShared<Shared> for Unshared
where Shared: FromUnshared<Unshared>,

Source§

fn into_shared(self) -> Shared

Creates a shared type from an unshared type.
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more