llm-shield-cloud-aws

Crates.iollm-shield-cloud-aws
lib.rsllm-shield-cloud-aws
version0.1.1
created_at2025-11-03 03:50:05.711189+00
updated_at2025-11-03 03:50:05.711189+00
descriptionAWS cloud integrations for LLM Shield - Secrets Manager, S3, CloudWatch
homepage
repositoryhttps://github.com/llm-shield/llm-shield-rs
max_upload_size
id1913869
size214,263
GBA (globalbusinessadvisors)

documentation

README

llm-shield-cloud-aws

AWS cloud integrations for LLM Shield - Secrets Manager, S3, CloudWatch, and X-Ray.

Crates.io Documentation License

Overview

This crate provides production-ready AWS implementations of the cloud abstraction traits defined in llm-shield-cloud:

  • AWS Secrets Manager - Secure secret storage and retrieval with automatic caching
  • AWS S3 - Object storage for models, scan results, and configuration files
  • AWS CloudWatch Metrics - Application metrics and performance monitoring
  • AWS CloudWatch Logs - Structured logging and log aggregation

Features

Security

  • ✅ Automatic AWS credential chain (env → file → IAM role → IRSA)
  • ✅ Built-in secret caching with configurable TTL (5 minutes default)
  • ✅ Support for AWS KMS encryption
  • ✅ IAM policy templates included
  • ✅ 30-day secret recovery window

Performance

  • ✅ Automatic multipart uploads for large objects (>5MB)
  • ✅ Batched metrics export (20 per batch)
  • ✅ Batched log export (100 per batch)
  • ✅ Secret caching reduces API calls by >90%
  • ✅ Fully asynchronous with Tokio

Operations

  • ✅ Structured logging with trace/span IDs
  • ✅ Custom CloudWatch namespaces and dimensions
  • ✅ Support for all CloudWatch metric units
  • ✅ Automatic log stream creation
  • ✅ Multi-region support

Installation

Add to your Cargo.toml:

[dependencies]
llm-shield-cloud-aws = "0.1"
llm-shield-cloud = "0.1"
tokio = { version = "1.35", features = ["full"] }

Quick Start

AWS Secrets Manager

use llm_shield_cloud_aws::AwsSecretsManager;
use llm_shield_cloud::CloudSecretManager;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Initialize with default configuration
    let secrets = AwsSecretsManager::new().await?;

    // Fetch a secret (automatically cached for 5 minutes)
    let api_key = secrets.get_secret("llm-shield/openai-api-key").await?;
    println!("API Key: {}", api_key.as_string());

    // Create a new secret
    let new_secret = SecretValue::from_string("my-secret-value".to_string());
    secrets.create_secret("llm-shield/my-secret", &new_secret).await?;

    // List all secrets
    let secret_names = secrets.list_secrets().await?;
    println!("Found {} secrets", secret_names.len());

    Ok(())
}

AWS S3 Storage

use llm_shield_cloud_aws::AwsS3Storage;
use llm_shield_cloud::{CloudStorage, PutObjectOptions};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let storage = AwsS3Storage::new("llm-shield-models").await?;

    // Upload a model (automatically uses multipart for files >5MB)
    let model_data = tokio::fs::read("toxicity-model.onnx").await?;
    storage.put_object("models/toxicity.onnx", &model_data).await?;

    // Upload with options
    let options = PutObjectOptions {
        content_type: Some("application/octet-stream".to_string()),
        storage_class: Some("INTELLIGENT_TIERING".to_string()),
        encryption: Some("AES256".to_string()),
        ..Default::default()
    };
    storage.put_object_with_options("models/model.onnx", &model_data, &options).await?;

    // Download and verify
    let downloaded = storage.get_object("models/toxicity.onnx").await?;
    assert_eq!(model_data, downloaded);

    // List objects with prefix
    let models = storage.list_objects("models/").await?;
    println!("Found {} models", models.len());

    Ok(())
}

CloudWatch Metrics

use llm_shield_cloud_aws::CloudWatchMetrics;
use llm_shield_cloud::{CloudMetrics, Metric};
use std::collections::HashMap;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let metrics = CloudWatchMetrics::new("LLMShield").await?;

    let mut dimensions = HashMap::new();
    dimensions.insert("Environment".to_string(), "Production".to_string());
    dimensions.insert("Scanner".to_string(), "Toxicity".to_string());

    let metric = Metric {
        name: "ScanDuration".to_string(),
        value: 123.45,
        timestamp: std::time::SystemTime::now()
            .duration_since(std::time::UNIX_EPOCH)?
            .as_secs(),
        dimensions,
        unit: Some("Milliseconds".to_string()),
    };

    metrics.export_metric(&metric).await?;
    metrics.flush().await?;

    Ok(())
}

CloudWatch Logs

use llm_shield_cloud_aws::CloudWatchLogger;
use llm_shield_cloud::{CloudLogger, LogLevel, LogEntry};
use std::collections::HashMap;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let logger = CloudWatchLogger::new(
        "/llm-shield/api",
        "production-instance-1"
    ).await?;

    // Simple logging
    logger.log("API server started", LogLevel::Info).await?;

    // Structured logging
    let mut labels = HashMap::new();
    labels.insert("request_id".to_string(), "req-123".to_string());
    labels.insert("user_id".to_string(), "user-456".to_string());

    let entry = LogEntry {
        timestamp: std::time::SystemTime::now(),
        level: LogLevel::Info,
        message: "Request processed successfully".to_string(),
        labels,
        trace_id: Some("trace-789".to_string()),
        span_id: Some("span-012".to_string()),
    };

    logger.log_structured(&entry).await?;
    logger.flush().await?;

    Ok(())
}

Configuration

Configure AWS integrations via YAML or environment variables:

cloud:
  provider: aws
  aws:
    region: us-east-1
    secrets_manager:
      enabled: true
      cache_ttl_seconds: 300
    s3:
      bucket: llm-shield-models
      models_prefix: models/
      results_prefix: scan-results/
    cloudwatch:
      enabled: true
      namespace: LLMShield
      log_group: /llm-shield/api
      log_stream: production

Or use environment variables:

export AWS_REGION=us-east-1
export AWS_ACCESS_KEY_ID=<your-key-id>
export AWS_SECRET_ACCESS_KEY=<your-secret-key>
export LLM_SHIELD_S3_BUCKET=llm-shield-models
export LLM_SHIELD_CLOUDWATCH_NAMESPACE=LLMShield

AWS Credentials

This crate uses the AWS SDK's default credential provider chain:

  1. Environment variables: AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY
  2. AWS credentials file: ~/.aws/credentials
  3. ECS container credentials: IAM role for ECS tasks
  4. EC2 instance profile: IAM role for EC2 instances
  5. EKS pod identity: IAM Roles for Service Accounts (IRSA)

Development

For local development, configure credentials:

aws configure
# Or set environment variables
export AWS_ACCESS_KEY_ID=<key-id>
export AWS_SECRET_ACCESS_KEY=<secret-key>
export AWS_DEFAULT_REGION=us-east-1

Production (IAM Roles)

For production deployments, use IAM roles instead of access keys:

EC2 Instance:

# Attach IAM role to EC2 instance
aws ec2 associate-iam-instance-profile \
  --instance-id i-xxxxx \
  --iam-instance-profile Name=LLMShieldEC2Profile

ECS Task:

{
  "family": "llm-shield-api",
  "taskRoleArn": "arn:aws:iam::ACCOUNT_ID:role/LLMShieldECSTaskRole",
  "containerDefinitions": [...]
}

EKS Pod (IRSA):

apiVersion: v1
kind: Pod
metadata:
  name: llm-shield-api
spec:
  serviceAccountName: llm-shield-sa
  containers:
    - name: api
      image: llm-shield:latest

IAM Permissions

Required IAM permissions are provided in iam-policies/ directory:

  • secrets-manager-policy.json - Secrets Manager permissions
  • s3-policy.json - S3 bucket access permissions
  • cloudwatch-policy.json - CloudWatch metrics and logs permissions
  • llm-shield-full-policy.json - Combined policy (all permissions)

Minimal Policy (Production)

For production, use least-privilege access:

aws iam put-role-policy \
  --role-name LLMShieldRole \
  --policy-name SecretsManagerReadOnly \
  --policy-document file://iam-policies/secrets-manager-policy.json

See iam-policies/README.md for detailed setup instructions.

Resource Naming Conventions

Follow these conventions for AWS resources:

Secrets Manager

  • Prefix: llm-shield/
  • Examples:
    • llm-shield/openai-api-key
    • llm-shield/database-password
    • llm-shield/jwt-secret

S3 Buckets

  • Pattern: llm-shield-*
  • Examples:
    • llm-shield-models-prod
    • llm-shield-results-dev

S3 Object Prefixes

  • Models: models/
  • Scan Results: scan-results/
  • Configs: configs/

CloudWatch

  • Namespaces:
    • LLMShield
    • LLMShield/API
    • LLMShield/Scanners
  • Log Groups: /llm-shield/*
    • /llm-shield/api
    • /llm-shield/scanners

Testing

Unit Tests

cargo test -p llm-shield-cloud-aws

Integration Tests

Integration tests require AWS credentials and appropriate permissions:

# Set test bucket for S3 tests
export TEST_S3_BUCKET=llm-shield-test-123456789012

# Run all integration tests
cargo test -p llm-shield-cloud-aws --test integration -- --ignored

# Run specific integration test
cargo test -p llm-shield-cloud-aws --test integration_secrets -- --ignored
cargo test -p llm-shield-cloud-aws --test integration_storage -- --ignored
cargo test -p llm-shield-cloud-aws --test integration_observability -- --ignored

Test Cleanup

Integration tests create resources with UUID suffixes for safety. Cleanup any leftover test resources:

# Delete test secrets
aws secretsmanager list-secrets --query 'SecretList[?starts_with(Name, `llm-shield-test`)].Name' --output text | \
  xargs -I {} aws secretsmanager delete-secret --secret-id {} --force-delete-without-recovery

# Delete test S3 objects
aws s3 rm s3://llm-shield-test-ACCOUNT_ID/test/ --recursive

# Delete test log groups
aws logs describe-log-groups --log-group-name-prefix /llm-shield-test/ --query 'logGroups[].logGroupName' --output text | \
  xargs -I {} aws logs delete-log-group --log-group-name {}

Performance

Benchmarks

Operation Throughput Latency (p50) Latency (p99)
Secret fetch (cached) 100,000/s <1ms <5ms
Secret fetch (uncached) 1,000/s 50ms 150ms
S3 upload (1MB) 50 MB/s 20ms 100ms
S3 upload (50MB, multipart) 80 MB/s 625ms 2s
S3 download (1MB) 100 MB/s 10ms 50ms
Metrics export (batch) 1,000/s 10ms 50ms
Logs export (batch) 10,000/s 5ms 25ms

Optimization Tips

  1. Enable secret caching (default 5 minutes):

    let secrets = AwsSecretsManager::new_with_cache_ttl("us-east-1", 600).await?;
    
  2. Use multipart uploads for large files (automatic for >5MB)

  3. Batch metrics and logs:

    metrics.export_metrics(&batch).await?;
    logger.log_batch(&entries).await?;
    
  4. Configure batch sizes:

    let metrics = CloudWatchMetrics::new_with_config("LLMShield", "us-east-1", 50).await?;
    let logger = CloudWatchLogger::new_with_config("/llm-shield/api", "stream", "us-east-1", 200).await?;
    
  5. Use S3 Intelligent-Tiering for cost optimization:

    let options = PutObjectOptions {
        storage_class: Some("INTELLIGENT_TIERING".to_string()),
        ..Default::default()
    };
    

Cost Estimates

Typical monthly costs for production deployment:

Service Usage Cost
Secrets Manager 10 secrets, 100K API calls ~$5
S3 Storage 100 GB, 1M requests ~$3
CloudWatch Logs 50 GB ingested, 10 GB stored ~$27
CloudWatch Metrics 50 custom metrics ~$15
Total ~$50/month

Cost Optimization

  1. Use secret caching to reduce API calls by >90%
  2. Enable S3 Lifecycle policies to transition old data to Glacier
  3. Set CloudWatch log retention to 7-30 days
  4. Use CloudWatch Contributor Insights for metrics analysis
  5. Enable S3 Intelligent-Tiering for automatic cost optimization

Troubleshooting

Access Denied Errors

Check IAM permissions:

# Verify your identity
aws sts get-caller-identity

# Check attached policies
aws iam list-attached-role-policies --role-name LLMShieldRole

# Test secret access
aws secretsmanager get-secret-value --secret-id llm-shield/test-secret

Secret Not Found

Ensure secret follows naming convention:

# List all secrets with prefix
aws secretsmanager list-secrets --query 'SecretList[?starts_with(Name, `llm-shield`)].Name'

S3 Access Denied

Check bucket policy and IAM permissions:

# Test bucket access
aws s3 ls s3://llm-shield-models/

# Check bucket policy
aws s3api get-bucket-policy --bucket llm-shield-models

CloudWatch Logs Not Appearing

Ensure log group and stream exist:

# List log groups
aws logs describe-log-groups --log-group-name-prefix /llm-shield/

# Create log group if missing
aws logs create-log-group --log-group-name /llm-shield/api

Region Mismatch

Verify region configuration:

echo $AWS_DEFAULT_REGION

# Or specify region explicitly
let secrets = AwsSecretsManager::new_with_region("us-west-2").await?;

Examples

See examples/ directory for complete examples:

  • secrets_example.rs - Secret management
  • storage_example.rs - S3 operations
  • metrics_example.rs - CloudWatch metrics
  • logging_example.rs - CloudWatch logs
  • combined_example.rs - Using all services together

Run examples:

cargo run --example secrets_example
cargo run --example storage_example
cargo run --example metrics_example

Architecture

┌─────────────────────────────────────┐
│   LLM Shield Application            │
│   (llm-shield-api crate)            │
└─────────────────────────────────────┘
                │
                ▼
┌─────────────────────────────────────┐
│   llm-shield-cloud (traits)         │
│   - CloudSecretManager              │
│   - CloudStorage                    │
│   - CloudMetrics/Logger             │
└─────────────────────────────────────┘
                │
                ▼
┌─────────────────────────────────────┐
│   llm-shield-cloud-aws (impl)       │
│   - AwsSecretsManager               │
│   - AwsS3Storage                    │
│   - CloudWatchMetrics/Logger        │
└─────────────────────────────────────┘
                │
                ▼
┌─────────────────────────────────────┐
│   AWS SDK for Rust                  │
│   - aws-sdk-secretsmanager          │
│   - aws-sdk-s3                      │
│   - aws-sdk-cloudwatch              │
└─────────────────────────────────────┘
                │
                ▼
┌─────────────────────────────────────┐
│   AWS Services                      │
│   - Secrets Manager                 │
│   - S3                              │
│   - CloudWatch                      │
└─────────────────────────────────────┘

Security

Best Practices

  1. Never commit AWS credentials to version control
  2. Use IAM roles instead of access keys in production
  3. Enable KMS encryption for secrets and S3 objects
  4. Set least-privilege IAM policies for each service
  5. Enable AWS CloudTrail for audit logging
  6. Rotate secrets regularly using Secrets Manager rotation
  7. Use VPC endpoints for private connectivity to AWS services
  8. Enable S3 versioning for critical data
  9. Set CloudWatch log retention policies
  10. Review IAM policies quarterly

Reporting Security Issues

Report security vulnerabilities to: security@llm-shield.example.com

Contributing

Contributions are welcome! Please see CONTRIBUTING.md for guidelines.

License

MIT OR Apache-2.0

Related Crates

Resources

Commit count: 0

cargo fmt