aws_utils_secretsmanager

Crates.ioaws_utils_secretsmanager
lib.rsaws_utils_secretsmanager
version0.3.0
created_at2025-07-23 23:15:50.061803+00
updated_at2025-09-16 23:46:02.837648+00
descriptionAWS Secrets Manager utilities for retrieving secret values
homepagehttps://github.com/UniqueVision/utilities.aws-utils
repositoryhttps://github.com/UniqueVision/utilities.aws-utils
max_upload_size
id1765361
size74,894
Kouhei Aoyagi (aoyagikouhei)

documentation

https://docs.rs/aws_utils_secretsmanager

README

aws_utils_secretsmanager

AWS Secrets Manager utilities for retrieving secret values from AWS Secrets Manager.

Features

  • Simple interface for retrieving secrets from AWS Secrets Manager
  • Support for secret versioning with version ID and version stage
  • Custom error handling with detailed error types
  • Support for custom AWS endpoints (useful for testing with LocalStack)
  • Support for AWS SDK's default credential chain

Installation

Add this to your Cargo.toml:

[dependencies]
aws_utils_secretsmanager = "0.1.0"

Usage

Basic Example

use aws_utils_secretsmanager::{make_client_with_timeout_default, secretsmanager::get_secret_value};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Create Secrets Manager client with default timeout configuration
    let client = make_client_with_timeout_default(None).await;
    
    // Get secret value
    let secret = get_secret_value(&client, "my-secret-name").await?;
    println!("Secret value: {}", secret);
    
    Ok(())
}

Using Custom Endpoint

use aws_utils_secretsmanager::{make_client_with_timeout_default, secretsmanager::get_secret_value};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Create client with custom endpoint (e.g., LocalStack)
    let client = make_client_with_timeout_default(Some("http://localhost:4566".to_string())).await;
    
    let secret = get_secret_value(&client, "test-secret").await?;
    println!("Secret value: {}", secret);
    
    Ok(())
}

Using Custom Timeout Configuration

use std::time::Duration;
use aws_utils_secretsmanager::{make_client_with_timeout, secretsmanager::get_secret_value};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Create client with custom timeout settings
    let client = make_client_with_timeout(
        None,
        Some(Duration::from_secs(5)),      // 5 second connect timeout
        Some(Duration::from_secs(30)),     // 30 second operation timeout
        Some(Duration::from_secs(25)),     // 25 second operation attempt timeout
        Some(Duration::from_secs(20)),     // 20 second read timeout
    ).await;
    
    let secret = get_secret_value(&client, "test-secret").await?;
    println!("Secret value: {}", secret);
    
    Ok(())
}

Using with TimeoutConfig

use aws_config::timeout::{TimeoutConfig, TimeoutConfigBuilder};
use aws_utils_secretsmanager::{make_client, secretsmanager::get_secret_value};
use std::time::Duration;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Build custom timeout configuration
    let timeout_config = TimeoutConfigBuilder::new()
        .connect_timeout(Duration::from_secs(10))
        .operation_timeout(Duration::from_secs(120))
        .build();
    
    // Create client with custom timeout configuration
    let client = make_client(None, Some(timeout_config)).await;
    
    let secret = get_secret_value(&client, "long-running-secret").await?;
    println!("Secret value: {}", secret);
    
    Ok(())
}

Getting Raw Secret Output with Versioning

use aws_utils_secretsmanager::{make_client_with_timeout_default, secretsmanager::get_secret_value_raw};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = make_client_with_timeout_default(None).await;
    
    // Get specific version of secret
    let output = get_secret_value_raw(
        &client,
        Some("my-secret-name"),
        Some("version-uuid"),      // Version ID
        Some("AWSCURRENT")         // Version stage
    ).await?;
    
    if let Some(secret_string) = output.secret_string() {
        println!("Secret: {}", secret_string);
    }
    
    if let Some(version_id) = output.version_id() {
        println!("Version ID: {}", version_id);
    }
    
    Ok(())
}

Getting Latest Secret Version

use aws_utils_secretsmanager::{make_client_with_timeout_default, secretsmanager::get_secret_value_raw};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = make_client_with_timeout_default(None).await;
    
    // Get current version (default behavior)
    let output = get_secret_value_raw(
        &client,
        Some("my-secret-name"),
        None::<String>,           // No specific version ID
        Some("AWSCURRENT")        // Get current version
    ).await?;
    
    println!("Current secret: {:?}", output.secret_string());
    
    Ok(())
}

API Reference

Functions

make_client_with_timeout_default(endpoint_url: Option<String>) -> Client

Creates an AWS Secrets Manager client with default timeout configuration.

  • endpoint_url: Optional custom endpoint URL for testing (e.g., LocalStack)
  • Returns: Configured AWS Secrets Manager Client with default timeouts
  • Default timeouts:
    • Connect timeout: 3100 seconds
    • Operation timeout: 60 seconds
    • Operation attempt timeout: 55 seconds
    • Read timeout: 50 seconds

make_client_with_timeout(endpoint_url: Option<String>, connect_timeout: Option<Duration>, operation_timeout: Option<Duration>, operation_attempt_timeout: Option<Duration>, read_timeout: Option<Duration>) -> Client

Creates an AWS Secrets Manager client with custom timeout configuration.

  • endpoint_url: Optional custom endpoint URL for testing (e.g., LocalStack)
  • connect_timeout: Optional timeout for establishing connections
  • operation_timeout: Optional timeout for entire operations
  • operation_attempt_timeout: Optional timeout for individual operation attempts
  • read_timeout: Optional timeout for reading responses
  • Returns: Configured AWS Secrets Manager Client with custom timeouts

make_client(endpoint_url: Option<String>, timeout_config: Option<TimeoutConfig>) -> Client

Creates an AWS Secrets Manager client with optional custom endpoint URL and timeout configuration.

  • endpoint_url: Optional custom endpoint URL for testing (e.g., LocalStack)
  • timeout_config: Optional timeout configuration
  • Returns: Configured AWS Secrets Manager Client

get_secret_value(client: &Client, secret_id: &str) -> Result<String, Error>

Retrieves a secret value as a string from the current version.

  • client: AWS Secrets Manager client
  • secret_id: Secret identifier (name or ARN)
  • Returns: Secret value as String

get_secret_value_raw(client: &Client, secret_id: Option<impl Into<String>>, version_id: Option<impl Into<String>>, version_stage: Option<impl Into<String>>) -> Result<GetSecretValueOutput, Error>

Retrieves raw secret output from AWS Secrets Manager with version control.

  • client: AWS Secrets Manager client
  • secret_id: Optional secret identifier (name or ARN)
  • version_id: Optional version UUID to retrieve specific version
  • version_stage: Optional version stage (e.g., "AWSCURRENT", "AWSPENDING")
  • Returns: Raw GetSecretValueOutput from AWS SDK

Error Types

The crate defines custom error types:

  • Error::BuildError: AWS SDK build errors
  • Error::AwsSdk: AWS SDK service errors
  • Error::ValidationError: Validation errors
  • Error::NotFound: Secret not found

Secret Versioning

AWS Secrets Manager supports versioning of secrets. You can:

  • Get the current version using "AWSCURRENT" stage
  • Get the pending version using "AWSPENDING" stage
  • Get a specific version using the version UUID
  • Let AWS choose the version by omitting version parameters

Version Stages

  • AWSCURRENT: The current version of the secret
  • AWSPENDING: The version that will become current after rotation completes
  • Custom stages: You can define custom version stages for your workflow

Testing

Set up your test environment:

# Optional: Custom Secrets Manager endpoint (e.g., LocalStack)
export SECRETSMANAGER_ENDPOINT_URL=http://localhost:4566

# Run tests
cargo test

Test Commands

# Run all tests
cargo test

# Run with logging
RUST_LOG=info cargo test -- --nocapture

# Run specific test
cargo test test_get_secret_value -- --nocapture

Authentication

The client uses the AWS SDK's default credential chain for authentication:

  • Environment variables (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION)
  • ECS task role (for Fargate/ECS)
  • EC2 instance profile
  • AWS credentials file
  • Other configured credential providers

Use Cases

Database Credentials

use aws_utils_secretsmanager::{make_client_with_timeout_default, secretsmanager::get_secret_value};
use serde_json::Value;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = make_client_with_timeout_default(None).await;
    let secret_json = get_secret_value(&client, "prod/db/credentials").await?;
    
    let credentials: Value = serde_json::from_str(&secret_json)?;
    let username = credentials["username"].as_str().unwrap();
    let password = credentials["password"].as_str().unwrap();
    
    // Use credentials to connect to database
    println!("Connecting as user: {}", username);
    
    Ok(())
}

API Keys

use aws_utils_secretsmanager::{make_client_with_timeout_default, secretsmanager::get_secret_value};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = make_client_with_timeout_default(None).await;
    let api_key = get_secret_value(&client, "prod/external-api/key").await?;
    
    // Use API key for external service calls
    println!("API Key retrieved successfully");
    
    Ok(())
}

License

MIT

Commit count: 84

cargo fmt