Skip to main content

17_attribute_based_access_control/
17_attribute_based_access_control.rs

1//! Attribute-Based Access Control (ABAC)
2//!
3//! This example demonstrates:
4//! - Tagging resources with attributes
5//! - Creating tag-based policies
6//! - Dynamic access control based on attributes
7//!
8//! Scenario: Access control based on department and project tags.
9//!
10//! Run with: `cargo run --example 17_attribute_based_access_control`
11
12use std::sync::Arc;
13use tokio::sync::RwLock;
14use wami::arn::{TenantPath, WamiArn};
15use wami::context::WamiContext;
16use wami::service::{PolicyService, UserService};
17use wami::store::memory::InMemoryWamiStore;
18use wami::types::Tag;
19use wami::wami::identity::user::requests::CreateUserRequest;
20use wami::wami::policies::policy::requests::CreatePolicyRequest;
21
22#[tokio::main]
23async fn main() -> Result<(), Box<dyn std::error::Error>> {
24    println!("=== Attribute-Based Access Control (ABAC) ===\n");
25
26    let store = Arc::new(RwLock::new(InMemoryWamiStore::default()));
27
28    // Create context
29    let context = WamiContext::builder()
30        .instance_id("123456789012")
31        .tenant_path(TenantPath::single(0))
32        .caller_arn(
33            WamiArn::builder()
34                .service(wami::arn::Service::Iam)
35                .tenant_path(TenantPath::single(0))
36                .wami_instance("123456789012")
37                .resource("user", "admin")
38                .build()?,
39        )
40        .is_root(false)
41        .build()?;
42
43    let user_service = UserService::new(store.clone());
44    let policy_service = PolicyService::new(store.clone());
45
46    // === CREATE TAGGED USERS ===
47    println!("Step 1: Creating users with department/project tags...\n");
48
49    user_service
50        .create_user(
51            &context,
52            CreateUserRequest {
53                user_name: "alice".to_string(),
54                path: Some("/".to_string()),
55                permissions_boundary: None,
56                tags: Some(vec![
57                    Tag {
58                        key: "Department".to_string(),
59                        value: "Engineering".to_string(),
60                    },
61                    Tag {
62                        key: "Project".to_string(),
63                        value: "ProjectA".to_string(),
64                    },
65                ]),
66            },
67        )
68        .await?;
69    println!("✓ Created alice (Engineering, ProjectA)");
70
71    user_service
72        .create_user(
73            &context,
74            CreateUserRequest {
75                user_name: "bob".to_string(),
76                path: Some("/".to_string()),
77                permissions_boundary: None,
78                tags: Some(vec![
79                    Tag {
80                        key: "Department".to_string(),
81                        value: "Engineering".to_string(),
82                    },
83                    Tag {
84                        key: "Project".to_string(),
85                        value: "ProjectB".to_string(),
86                    },
87                ]),
88            },
89        )
90        .await?;
91    println!("✓ Created bob (Engineering, ProjectB)");
92
93    user_service
94        .create_user(
95            &context,
96            CreateUserRequest {
97                user_name: "charlie".to_string(),
98                path: Some("/".to_string()),
99                permissions_boundary: None,
100                tags: Some(vec![
101                    Tag {
102                        key: "Department".to_string(),
103                        value: "Sales".to_string(),
104                    },
105                    Tag {
106                        key: "Project".to_string(),
107                        value: "ProjectC".to_string(),
108                    },
109                ]),
110            },
111        )
112        .await?;
113    println!("✓ Created charlie (Sales, ProjectC)");
114
115    // === CREATE ABAC POLICY ===
116    println!("\n\nStep 2: Creating ABAC policy...\n");
117
118    let abac_policy_doc = r#"{
119  "Version": "2012-10-17",
120  "Statement": [{
121    "Effect": "Allow",
122    "Action": "s3:*",
123    "Resource": "arn:aws:s3:::${aws:PrincipalTag/Project}/*",
124    "Condition": {
125      "StringEquals": {
126        "s3:ExistingObjectTag/Department": "${aws:PrincipalTag/Department}"
127      }
128    }
129  }]
130}"#;
131
132    policy_service
133        .create_policy(
134            &context,
135            CreatePolicyRequest {
136                policy_name: "ABACPolicy".to_string(),
137                path: Some("/abac/".to_string()),
138                policy_document: abac_policy_doc.to_string(),
139                description: Some("ABAC policy using tags".to_string()),
140                tags: None,
141            },
142        )
143        .await?;
144    println!("✓ Created ABAC policy with tag-based conditions");
145    println!("  - Resource access based on PrincipalTag/Project");
146    println!("  - Object access requires matching Department tag");
147
148    println!("\n\n✅ Example completed successfully!");
149    println!("Key takeaways:");
150    println!("- ABAC uses tags for dynamic access control");
151    println!("- Policies reference ${{aws:PrincipalTag/Key}}");
152    println!("- Scales better than RBAC for large organizations");
153
154    Ok(())
155}