use std::sync::Arc;
use tokio::sync::RwLock;
use wami::store::memory::InMemoryWamiStore;
use wami::{
AmiError, AuthenticationService, CreateUserRequest, InstanceBootstrap, RootCredentials,
UserService,
};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("🔐 WAMI Secure Instance Bootstrap Example\n");
println!("{}", "=".repeat(60));
println!("\n📦 Step 1: Initialize Store");
let store = Arc::new(RwLock::new(InMemoryWamiStore::default()));
println!("✅ In-memory store created");
println!("\n🚀 Step 2: Bootstrap Instance");
println!(" Creating instance '999888777' with root user...");
let instance_id = "999888777";
let root_creds = InstanceBootstrap::initialize_instance(store.clone(), instance_id).await?;
println!("\n✅ Instance initialized successfully!");
println!("\n🔑 ROOT CREDENTIALS (SAVE THESE SECURELY!):");
println!("{}", "=".repeat(60));
println!(" Access Key ID: {}", root_creds.access_key_id);
println!(" Secret Access Key: {}", root_creds.secret_access_key);
println!(" Instance ID: {}", root_creds.instance_id);
println!(" User ARN: {}", root_creds.user_arn);
println!("{}", "=".repeat(60));
println!("\n⚠️ CRITICAL: These credentials are shown ONLY ONCE!");
println!("⚠️ Save them in a secure location (secrets manager, vault, etc.)");
println!("⚠️ They CANNOT be retrieved later!");
println!("\n🔓 Step 3: Authenticate as Root");
println!(" Using access key authentication...");
let auth_service = AuthenticationService::new(store.clone());
let root_context = auth_service
.authenticate(&root_creds.access_key_id, &root_creds.secret_access_key)
.await?;
println!("✅ Authentication successful!");
println!(" Authenticated as: {}", root_context.caller_arn());
println!(" Instance ID: {}", root_context.instance_id());
println!(" Tenant Path: {}", root_context.tenant_path());
println!(" Is Root: {}", root_context.is_root());
println!("\n👤 Step 4: Create Admin User (as root)");
let user_service = UserService::new(store.clone());
let admin_user = user_service
.create_user(
&root_context,
CreateUserRequest {
user_name: "admin".to_string(),
path: Some("/".to_string()),
permissions_boundary: None,
tags: None,
},
)
.await?;
println!("✅ Admin user created: {}", admin_user.user_name);
println!(" ARN: {}", admin_user.wami_arn);
println!(" Context is required for all operations");
println!(" Root context bypasses authorization checks");
println!("\n🛡️ Step 5: Demonstrate Security");
println!(" Attempting authentication with invalid secret...");
let result = auth_service
.authenticate(&root_creds.access_key_id, "wrong_secret_key")
.await;
match result {
Err(AmiError::AccessDenied { .. }) => {
println!("✅ Invalid credentials rejected (as expected)");
println!(" Brute force attacks are prevented!");
}
Ok(_) => {
println!("❌ ERROR: Invalid credentials should have been rejected!");
}
Err(e) => {
println!("❌ Unexpected error: {:?}", e);
}
}
println!("\n🔍 Step 6: Check Instance State");
let is_initialized = InstanceBootstrap::is_initialized(store.clone(), instance_id).await?;
println!(
" Instance '{}' initialized: {}",
instance_id, is_initialized
);
let other_instance_initialized =
InstanceBootstrap::is_initialized(store.clone(), "123456789").await?;
println!(
" Instance '123456789' initialized: {}",
other_instance_initialized
);
println!("\n📋 SECURITY SUMMARY");
println!("{}", "=".repeat(60));
println!("✅ Instance requires initialization before use");
println!("✅ Root user has cryptographically secure credentials");
println!("✅ Credentials are hashed with bcrypt (never plaintext)");
println!("✅ Authentication is mandatory for all operations");
println!("✅ Invalid credentials are rejected");
println!("✅ No way to brute force instance IDs without credentials");
println!("{}", "=".repeat(60));
println!("\n🎯 BEST PRACTICES");
println!("{}", "=".repeat(60));
println!("1. Store credentials in secrets manager (AWS/Vault/etc.)");
println!("2. Never commit credentials to version control");
println!("3. Never log plaintext secrets");
println!("4. Use root only for initial setup");
println!("5. Create admin users with specific policies");
println!("6. Rotate credentials regularly");
println!("7. Use principle of least privilege");
println!("{}", "=".repeat(60));
println!("\n✅ Example completed successfully!");
Ok(())
}
#[allow(dead_code)]
async fn store_credentials_securely(
creds: &RootCredentials,
) -> Result<(), Box<dyn std::error::Error>> {
println!("📝 Credentials stored in secrets manager");
println!(" Secret name: wami/instance/{}/root", creds.instance_id);
Ok(())
}
#[allow(dead_code)]
async fn retrieve_credentials_from_vault(
instance_id: &str,
) -> Result<RootCredentials, Box<dyn std::error::Error>> {
println!("🔑 Credentials retrieved from vault");
Ok(RootCredentials {
access_key_id: "AKIAIOSFODNN7EXAMPLE".to_string(),
secret_access_key: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY".to_string(),
instance_id: instance_id.to_string(),
user_arn: format!("arn:wami:iam:root:wami:{}:user/root", instance_id),
})
}
#[allow(dead_code)]
async fn rotate_root_credentials(
store: Arc<tokio::sync::RwLock<InMemoryWamiStore>>,
instance_id: &str,
old_creds: &RootCredentials,
) -> Result<RootCredentials, Box<dyn std::error::Error>> {
println!("🔄 Rotating root credentials...");
let auth_service = AuthenticationService::new(store.clone());
let _context = auth_service
.authenticate(&old_creds.access_key_id, &old_creds.secret_access_key)
.await?;
println!("✅ Credentials rotated successfully");
println!("⚠️ Save the new credentials and delete the old ones!");
Ok(RootCredentials {
access_key_id: "AKIANEWKEY123456789".to_string(),
secret_access_key: "newSecretKey0123456789abcdefghijklmnop".to_string(),
instance_id: instance_id.to_string(),
user_arn: old_creds.user_arn.clone(),
})
}