iam-rs 0.0.5

Complete Rust library for parsing, validating, and evaluating IAM policies. Provider-agnostic authorization engine with full AWS IAM compatibility.
Documentation

iam-rs

STILL IN DEVELOPMENT AND VERIFICATION - DO NOT USE YET

STILL IN DEVELOPMENT AND VERIFICATION - DO NOT USE YET

STILL IN DEVELOPMENT AND VERIFICATION - DO NOT USE YET

STILL IN DEVELOPMENT AND VERIFICATION - DO NOT USE YET

STILL IN DEVELOPMENT AND VERIFICATION - DO NOT USE YET

STILL IN DEVELOPMENT AND VERIFICATION - DO NOT USE YET

STILL IN DEVELOPMENT AND VERIFICATION - DO NOT USE YET

Crates.io Documentation License: MIT

A complete Rust library for parsing, validating, and evaluating IAM (Identity and Access Management) policies. Provider-agnostic and designed for building flexible authorization systems with full AWS IAM compatibility.

Features

  • ๐Ÿ”’ Provider-agnostic: Works with any AWS IAM-compatible JSON-based policy format
  • ๐Ÿ“ Full IAM Support: Complete implementation of IAM policy including conditions, principals, actions, and resources
  • ๐Ÿท๏ธ ARN Validation: Comprehensive ARN parsing, validation, and wildcard matching
  • โš–๏ธ Policy Evaluation: Complete policy evaluation engine with Allow/Deny decisions
  • ๐ŸŽฏ Condition Engine: Support for all AWS condition operators (String, Numeric, Date, Boolean, IP, ARN, Null)
  • ๐Ÿš€ Type-safe: Strong typing with comprehensive enums and structs
  • ๐Ÿ”ง Builder Pattern: Fluent API for constructing policies programmatically
  • ๐Ÿ“ฆ Serde Integration: Built-in JSON serialization and deserialization
  • โšก Zero Dependencies: Minimal dependencies (only serde and serde-libs)
  • ๐Ÿงช Well Tested: Comprehensive test suite with 100+ tests

Installation

Add iam-rs to your Cargo project:

cargo add iam-rs

Quick Start

Policy Evaluation (Authorization)

use iam_rs::{evaluate_policy, AuthorizationRequest, IAMPolicy, IAMStatement, Effect, Action, Resource, Decision};

// Create a policy
let policy = IAMPolicy::new()
    .add_statement(
        IAMStatement::new(Effect::Allow)
            .with_action(Action::Single("s3:GetObject".to_string()))
            .with_resource(Resource::Single("arn:aws:s3:::my-bucket/*".to_string()))
    );

// Create an authorization request
let request = AuthorizationRequest::simple(
    "arn:aws:iam::123456789012:user/alice",
    "s3:GetObject",
    "arn:aws:s3:::my-bucket/file.txt"
);

// Evaluate the request against the policy
match evaluate_policy(&policy, &request)? {
    Decision::Allow => println!("โœ“ Access granted"),
    Decision::Deny => println!("โœ— Access denied"),
    Decision::NotApplicable => println!("? No applicable policy (implicit deny)"),
}

Creating a Policy

use iam_rs::{IAMPolicy, IAMStatement, Effect, Action, Resource, Operator};
use serde_json::json;

let policy = IAMPolicy::new()
    .with_id("MyPolicy")
    .add_statement(
        IAMStatement::new(Effect::Allow)
            .with_sid("AllowS3Read")
            .with_action(Action::Single("s3:GetObject".to_string()))
            .with_resource(Resource::Single("arn:aws:s3:::my-bucket/*".to_string()))
            .with_condition(
                Operator::StringEquals,
                "s3:prefix".to_string(),
                json!("uploads/")
            )
    );

// Serialize to JSON
let policy_json = policy.to_json().unwrap();
println!("{}", policy_json);

Parsing from JSON

use iam_rs::IAMPolicy;

let json_policy = r#"
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::example-bucket/*"
    }
  ]
}
"#;

let policy = IAMPolicy::from_json(json_policy).unwrap();
println!("Policy has {} statements", policy.statement.len());

Core Types

IAMPolicy

The root policy document containing version, optional ID, and statements.

use iam_rs::{IAMPolicy, IAMVersion};

let policy = IAMPolicy::new()
    .with_version(IAMVersion::V20121017)
    .with_id("my-policy-id");

IAMStatement

Individual policy statements with effect, principals, actions, resources, and conditions.

use iam_rs::{IAMStatement, Effect, Action, Resource, Principal, PrincipalType};
use std::collections::HashMap;

let mut principal_map = HashMap::new();
principal_map.insert(PrincipalType::Aws, serde_json::json!("arn:aws:iam::123456789012:user/username"));

let statement = IAMStatement::new(Effect::Allow)
    .with_sid("ExampleStatement")
    .with_principal(Principal::Mapped(principal_map))
    .with_action(Action::Multiple(vec![
        "s3:GetObject".to_string(),
        "s3:PutObject".to_string()
    ]))
    .with_resource(Resource::Single("arn:aws:s3:::my-bucket/*".to_string()));

Policy Evaluation Engine

The library includes a complete policy evaluation engine that implements AWS IAM logic for authorization decisions.

Simple Evaluation

use iam_rs::{evaluate_policy, AuthorizationRequest, Decision};

// Simple authorization check
let decision = evaluate_policy(&policy, &request)?;
match decision {
    Decision::Allow => println!("Access granted"),
    Decision::Deny => println!("Access denied"),
    Decision::NotApplicable => println!("No applicable policy"),
}

Advanced Evaluation with Context

use iam_rs::{PolicyEvaluator, RequestContext, ContextValue, EvaluationOptions};

// Create request context for condition evaluation
let mut context = RequestContext::empty();
context.insert("aws:userid".to_string(), ContextValue::String("alice".to_string()));
context.insert("aws:CurrentTime".to_string(), ContextValue::String("2024-01-15T10:00:00Z".to_string()));

let request = AuthorizationRequest::new(
    "arn:aws:iam::123456789012:user/alice",
    "s3:GetObject",
    "arn:aws:s3:::private-bucket/file.txt",
    context
);

// Advanced evaluation with multiple policies
let evaluator = PolicyEvaluator::with_policies(vec![policy1, policy2])
    .with_options(EvaluationOptions {
        collect_match_details: true,
        stop_on_explicit_deny: true,
        max_statements: 100,
    });

let result = evaluator.evaluate(&request)?;
println!("Decision: {:?}", result.decision);
for statement_match in result.matched_statements {
    println!("Matched: {:?}", statement_match);
}

IAM Logic Support

The evaluation engine properly implements AWS IAM precedence rules:

  • Explicit Deny always overrides Allow
  • Conditions must be satisfied for statement to apply
  • Wildcard matching for actions, resources, and principals
  • Multiple policies are combined with proper precedence

ARN (Amazon Resource Name)

Comprehensive ARN parsing, validation, and wildcard matching.

use iam_rs::Arn;

// Parse an ARN
let arn = Arn::parse("arn:aws:s3:::my-bucket/folder/file.txt")?;
println!("Service: {}", arn.service);
println!("Resource: {}", arn.resource);

// Validate ARN format
assert!(arn.is_valid());

// Wildcard matching
let pattern = "arn:aws:s3:::my-bucket/*";
assert!(arn.matches(pattern)?);

// Extract resource information
if let Some(resource_type) = arn.resource_type() {
    println!("Resource type: {}", resource_type);
}
if let Some(resource_id) = arn.resource_id() {
    println!("Resource ID: {}", resource_id);
}

Advanced Usage

ARN Validation and Matching

use iam_rs::Arn;

// Parse and validate ARNs
let arn = Arn::parse("arn:aws:s3:::my-bucket/uploads/file.txt")?;

// Wildcard pattern matching
let patterns = vec![
    "arn:aws:s3:::my-bucket/*",           // โœ“ Matches
    "arn:aws:s3:::my-bucket/uploads/*",   // โœ“ Matches
    "arn:aws:s3:::other-bucket/*",        // โœ— No match
    "arn:aws:s3:::my-bucket/*/file.txt",  // โœ“ Matches
    "arn:aws:s3:::my-bucket/uploads/file.???", // โœ“ Matches
];

for pattern in patterns {
    if arn.matches(pattern)? {
        println!("โœ“ ARN matches pattern: {}", pattern);
    } else {
        println!("โœ— ARN does not match pattern: {}", pattern);
    }
}

// Extract resource components
if let Some(resource_type) = arn.resource_type() {
    println!("Resource type: {}", resource_type); // "my-bucket"
}
if let Some(resource_id) = arn.resource_id() {
    println!("Resource ID: {}", resource_id);     // "uploads/file.txt"
}

Multiple Actions and Resources

use iam_rs::{Action, Resource};

let actions = Action::Multiple(vec![
    "s3:GetObject".to_string(),
    "s3:PutObject".to_string(),
    "s3:DeleteObject".to_string(),
]);

let resources = Resource::Multiple(vec![
    "arn:aws:s3:::bucket1/*".to_string(),
    "arn:aws:s3:::bucket2/*".to_string(),
]);

Complex Conditions

use iam_rs::{Operator};
use serde_json::json;

let statement = IAMStatement::new(Effect::Allow)
    .with_action(Action::Single("s3:GetObject".to_string()))
    .with_resource(Resource::Single("arn:aws:s3:::secure-bucket/*".to_string()))
    .with_condition(
        Operator::StringEquals,
        "aws:username".to_string(),
        json!("${aws:userid}")
    )
    .with_condition(
        Operator::DateGreaterThan,
        "aws:CurrentTime".to_string(),
        json!("2024-01-01T00:00:00Z")
    );

Principal Types

use iam_rs::{Principal, PrincipalType};
use std::collections::HashMap;

// Wildcard principal (allows any principal)
let wildcard = Principal::Wildcard;

// AWS principal mapping
let mut aws_map = HashMap::new();
aws_map.insert(PrincipalType::Aws, serde_json::json!("arn:aws:iam::123456789012:user/alice"));
let aws_principal = Principal::Mapped(aws_map);

// Multiple principals in a service mapping
let mut service_map = HashMap::new();
service_map.insert(PrincipalType::Aws, serde_json::json!([
    "arn:aws:iam::123456789012:user/alice",
    "arn:aws:iam::123456789012:user/bob"
]));
let multiple_principals = Principal::Mapped(service_map);
    "arn:aws:iam::123456789012:user/bob".to_string(),
]);

// Wildcard (anyone)
let wildcard = Principal::Wildcard;

// Service principal with mapping
let mut service_map = HashMap::new();
service_map.insert(PrincipalType::Service, json!("lambda.amazonaws.com"));
let service = Principal::Mapped(service_map);

Examples

The library includes comprehensive examples demonstrating all features:

Running Examples

# ARN parsing and validation
cargo run --example arn_demo

# Policy validation
cargo run --example validation_demo

# Policy evaluation engine
cargo run --example evaluation_demo

Example Scenarios

The evaluation demo showcases:

  • โœ… Simple Allow/Deny policies
  • โœ… Wildcard action and resource matching
  • โœ… Condition-based authorization (String, Numeric, Date)
  • โœ… Explicit deny precedence (IAM compliance)
  • โœ… Multiple policy evaluation
  • โœ… Detailed evaluation with match information
  • โœ… Resource pattern matching
  • โœ… Context-aware authorization

JSON Schema Compatibility

This library follows the standard IAM policy JSON schema and is compatible with:

  • AWS IAM policies
  • AWS resource-based policies
  • Custom authorization systems using IAM-like policies

Example of a complete policy:

{
  "Version": "2012-10-17",
  "Id": "ExamplePolicy",
  "Statement": [
    {
      "Sid": "AllowUserToSeeAccountConfigurationInConsole",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::123456789012:user/username"
      },
      "Action": ["iam:GetAccountPasswordPolicy", "iam:ListVirtualMFADevices"],
      "Resource": "*",
      "Condition": {
        "StringEquals": {
          "aws:RequestedRegion": "us-east-1"
        }
      }
    }
  ]
}

Contributing

Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

This project is licensed under the MIT License - see the LICENSE file for details.