llm_shield_cloud_aws/
lib.rs

1//! AWS cloud integrations for LLM Shield.
2//!
3//! This crate provides AWS-specific implementations of the cloud abstraction traits
4//! defined in `llm-shield-cloud`:
5//!
6//! - **Secrets Management**: AWS Secrets Manager via `AwsSecretsManager`
7//! - **Object Storage**: AWS S3 via `AwsS3Storage`
8//! - **Metrics**: CloudWatch Metrics via `CloudWatchMetrics`
9//! - **Logging**: CloudWatch Logs via `CloudWatchLogger`
10//!
11//! # Features
12//!
13//! - Automatic credential discovery (environment → file → IAM role → IRSA)
14//! - Built-in caching for secrets (TTL-based)
15//! - Multipart uploads for large S3 objects (>5MB)
16//! - Batched metrics and log export for efficiency
17//! - Full support for AWS SDK retry and timeout policies
18//!
19//! # Architecture
20//!
21//! ```text
22//! ┌─────────────────────────────────────┐
23//! │   LLM Shield Application            │
24//! └─────────────────────────────────────┘
25//!                 │
26//!                 ▼
27//! ┌─────────────────────────────────────┐
28//! │   llm-shield-cloud (traits)         │
29//! │   - CloudSecretManager              │
30//! │   - CloudStorage                    │
31//! │   - CloudMetrics/Logger             │
32//! └─────────────────────────────────────┘
33//!                 │
34//!                 ▼
35//! ┌─────────────────────────────────────┐
36//! │   llm-shield-cloud-aws (impl)       │
37//! │   - AwsSecretsManager               │
38//! │   - AwsS3Storage                    │
39//! │   - CloudWatchMetrics/Logger        │
40//! └─────────────────────────────────────┘
41//!                 │
42//!                 ▼
43//! ┌─────────────────────────────────────┐
44//! │   AWS Services                      │
45//! │   - Secrets Manager                 │
46//! │   - S3                              │
47//! │   - CloudWatch                      │
48//! └─────────────────────────────────────┘
49//! ```
50//!
51//! # Usage Examples
52//!
53//! ## Secret Management
54//!
55//! ```no_run
56//! use llm_shield_cloud_aws::AwsSecretsManager;
57//! use llm_shield_cloud::CloudSecretManager;
58//!
59//! #[tokio::main]
60//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
61//!     // Initialize with default configuration (uses AWS credential chain)
62//!     let secrets = AwsSecretsManager::new().await?;
63//!
64//!     // Fetch a secret (automatically cached for 5 minutes)
65//!     let api_key = secrets.get_secret("llm-shield/openai-api-key").await?;
66//!     println!("API Key: {}", api_key.as_string());
67//!
68//!     // List all secrets
69//!     let secret_names = secrets.list_secrets().await?;
70//!     println!("Found {} secrets", secret_names.len());
71//!
72//!     Ok(())
73//! }
74//! ```
75//!
76//! ## Object Storage
77//!
78//! ```no_run
79//! use llm_shield_cloud_aws::AwsS3Storage;
80//! use llm_shield_cloud::{CloudStorage, PutObjectOptions};
81//!
82//! #[tokio::main]
83//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
84//!     let storage = AwsS3Storage::new("llm-shield-models").await?;
85//!
86//!     // Upload a model (automatically uses multipart for files >5MB)
87//!     let model_data = tokio::fs::read("toxicity-model.onnx").await?;
88//!     storage.put_object("models/toxicity.onnx", &model_data).await?;
89//!
90//!     // Upload with options
91//!     let options = PutObjectOptions {
92//!         content_type: Some("application/octet-stream".to_string()),
93//!         storage_class: Some("INTELLIGENT_TIERING".to_string()),
94//!         encryption: Some("AES256".to_string()),
95//!         ..Default::default()
96//!     };
97//!     storage.put_object_with_options("models/model.onnx", &model_data, &options).await?;
98//!
99//!     // Download and verify
100//!     let downloaded = storage.get_object("models/toxicity.onnx").await?;
101//!     assert_eq!(model_data, downloaded);
102//!
103//!     Ok(())
104//! }
105//! ```
106//!
107//! ## Metrics
108//!
109//! ```no_run
110//! use llm_shield_cloud_aws::CloudWatchMetrics;
111//! use llm_shield_cloud::{CloudMetrics, Metric};
112//! use std::collections::HashMap;
113//!
114//! #[tokio::main]
115//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
116//!     let metrics = CloudWatchMetrics::new("LLMShield").await?;
117//!
118//!     let mut dimensions = HashMap::new();
119//!     dimensions.insert("Environment".to_string(), "Production".to_string());
120//!     dimensions.insert("Scanner".to_string(), "Toxicity".to_string());
121//!
122//!     let metric = Metric {
123//!         name: "ScanDuration".to_string(),
124//!         value: 123.45,
125//!         timestamp: std::time::SystemTime::now()
126//!             .duration_since(std::time::UNIX_EPOCH)?
127//!             .as_secs(),
128//!         dimensions,
129//!         unit: Some("Milliseconds".to_string()),
130//!     };
131//!
132//!     metrics.export_metric(&metric).await?;
133//!
134//!     Ok(())
135//! }
136//! ```
137//!
138//! ## Logging
139//!
140//! ```no_run
141//! use llm_shield_cloud_aws::CloudWatchLogger;
142//! use llm_shield_cloud::{CloudLogger, LogLevel, LogEntry};
143//! use std::collections::HashMap;
144//!
145//! #[tokio::main]
146//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
147//!     let logger = CloudWatchLogger::new(
148//!         "/llm-shield/api",
149//!         "production-instance-1"
150//!     ).await?;
151//!
152//!     // Simple logging
153//!     logger.log("API server started", LogLevel::Info).await?;
154//!
155//!     // Structured logging
156//!     let mut labels = HashMap::new();
157//!     labels.insert("request_id".to_string(), "req-123".to_string());
158//!     labels.insert("user_id".to_string(), "user-456".to_string());
159//!
160//!     let entry = LogEntry {
161//!         timestamp: std::time::SystemTime::now(),
162//!         level: LogLevel::Info,
163//!         message: "Request processed successfully".to_string(),
164//!         labels,
165//!         trace_id: Some("trace-789".to_string()),
166//!         span_id: Some("span-012".to_string()),
167//!     };
168//!
169//!     logger.log_structured(&entry).await?;
170//!
171//!     Ok(())
172//! }
173//! ```
174//!
175//! # AWS Credentials
176//!
177//! This crate uses the AWS SDK's default credential provider chain:
178//!
179//! 1. **Environment variables**: `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`
180//! 2. **AWS credentials file**: `~/.aws/credentials`
181//! 3. **ECS container credentials**: IAM role for ECS tasks
182//! 4. **EC2 instance profile**: IAM role for EC2 instances
183//! 5. **EKS pod identity**: IAM Roles for Service Accounts (IRSA)
184//!
185//! # IAM Permissions
186//!
187//! Required IAM permissions are documented in `iam-policies/` directory:
188//!
189//! - `secrets-manager-policy.json`: Secrets Manager permissions
190//! - `s3-policy.json`: S3 bucket access permissions
191//! - `cloudwatch-policy.json`: CloudWatch metrics and logs permissions
192//!
193//! # Configuration
194//!
195//! Configure AWS integrations via `CloudConfig`:
196//!
197//! ```yaml
198//! cloud:
199//!   provider: aws
200//!   aws:
201//!     region: us-east-1
202//!     secrets_manager:
203//!       enabled: true
204//!       cache_ttl_seconds: 300
205//!     s3:
206//!       bucket: llm-shield-models
207//!       models_prefix: models/
208//!       results_prefix: scan-results/
209//!     cloudwatch:
210//!       enabled: true
211//!       namespace: LLMShield
212//!       log_group: /llm-shield/api
213//!       log_stream: production
214//! ```
215//!
216//! # Performance
217//!
218//! - **Secret caching**: >90% cache hit rate reduces API calls
219//! - **Multipart uploads**: Automatically used for objects >5MB
220//! - **Batch export**: Metrics and logs are batched for efficiency
221//! - **Async operations**: All I/O is fully asynchronous with tokio
222//!
223//! # Error Handling
224//!
225//! All operations return `Result<T, CloudError>` from the `llm-shield-cloud` crate:
226//!
227//! ```rust
228//! use llm_shield_cloud::{CloudError, Result};
229//! use llm_shield_cloud_aws::AwsSecretsManager;
230//!
231//! async fn fetch_secret(name: &str) -> Result<String> {
232//!     let secrets = AwsSecretsManager::new().await?;
233//!
234//!     match secrets.get_secret(name).await {
235//!         Ok(value) => Ok(value.as_string().to_string()),
236//!         Err(CloudError::SecretNotFound(name)) => {
237//!             eprintln!("Secret '{}' not found", name);
238//!             Err(CloudError::SecretNotFound(name))
239//!         }
240//!         Err(e) => {
241//!             eprintln!("Failed to fetch secret: {}", e);
242//!             Err(e)
243//!         }
244//!     }
245//! }
246//! ```
247//!
248//! # Testing
249//!
250//! Run unit tests:
251//!
252//! ```bash
253//! cargo test -p llm-shield-cloud-aws
254//! ```
255//!
256//! Run integration tests (requires AWS credentials):
257//!
258//! ```bash
259//! cargo test -p llm-shield-cloud-aws --test integration -- --ignored
260//! ```
261//!
262//! # License
263//!
264//! MIT OR Apache-2.0
265
266pub mod observability;
267pub mod secrets;
268pub mod storage;
269
270// Re-export main types
271pub use observability::{CloudWatchLogger, CloudWatchMetrics};
272pub use secrets::AwsSecretsManager;
273pub use storage::AwsS3Storage;
274
275// Re-export cloud abstractions for convenience
276pub use llm_shield_cloud::{
277    CloudError, CloudLogger, CloudMetrics, CloudSecretManager, CloudStorage, GetObjectOptions,
278    LogEntry, LogLevel, Metric, ObjectMetadata, PutObjectOptions, Result, SecretMetadata,
279    SecretValue,
280};
281
282/// Crate version
283pub const VERSION: &str = env!("CARGO_PKG_VERSION");
284
285/// Crate name
286pub const LIB_NAME: &str = env!("CARGO_PKG_NAME");
287
288#[cfg(test)]
289mod tests {
290    use super::*;
291
292    #[test]
293    fn test_version() {
294        assert!(!VERSION.is_empty());
295        assert_eq!(LIB_NAME, "llm-shield-cloud-aws");
296    }
297}