Secrets_management
Chapter 38: Secrets Management
Section titled “Chapter 38: Secrets Management”Protecting Sensitive Data in Production
Section titled “Protecting Sensitive Data in Production”38.1 What Are Secrets?
Section titled “38.1 What Are Secrets?”Secrets are sensitive credentials that need special protection in your application.
What Counts as Secrets? ======================
┌─────────────────────────────────────────────────────────────┐ │ Authentication Credentials │ │ ─────────────────────────────────────────────────────────│ │ • Database passwords │ │ • API keys (AWS, Stripe, Twilio, etc.) │ │ • OAuth client secrets │ │ • Service account credentials │ │ • SSH private keys │ └─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐ │ Cryptographic Materials │ │ ─────────────────────────────────────────────────────────│ │ • Encryption keys (symmetric) │ │ • Private keys (certificates) │ │ • Signing keys │ │ • HMAC secrets │ └─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐ │ Application Secrets │ │ ─────────────────────────────────────────────────────────│ │ • Third-party API tokens │ │ • Integration passwords │ │ • Admin credentials │ │ • Seed data for applications │ └─────────────────────────────────────────────────────────────┘The Problem with Secrets
Section titled “The Problem with Secrets” BAD PRACTICE: Secrets in Code ============================
# config.js (COMMITTED TO GIT!) ───────────────────────────────── const config = { dbPassword: "my_secret_password_123", // 🚨 BAD! apiKey: "sk_live_abc123def456", // 🚨 BAD! stripeKey: "sk_live_xxx" // 🚨 BAD! };
What happens: 1. Developer commits to git 2. Pushed to GitHub 3. Attacker finds in history 4. Complete system compromise!
─────────────────────────────────
Search GitHub for "password=" and find thousands of real secrets!38.2 Secret Management Solutions
Section titled “38.2 Secret Management Solutions”HashiCorp Vault
Section titled “HashiCorp Vault” HashiCorp Vault Architecture ============================
┌─────────────────────────────────────────────────────────────┐ │ Applications │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ App 1 │ │ App 2 │ │ App 3 │ │ │ └────┬─────┘ └────┬─────┘ └────┬─────┘ │ │ │ │ │ │ └───────┼──────────────┼──────────────┼──────────────────────┘ │ │ │ ▼ ▼ ▼ ┌─────────────────────────────────────────────────────────────┐ │ Vault Server │ │ │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ Secrets │ │ Auth │ │ Audit │ │ │ │ Engine │ │ Methods │ │ Logs │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │ │ └─────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ Storage Backend │ │ (Consul, etcd, DB) │ └─────────────────────────────────────────────────────────────┘AWS Secrets Manager
Section titled “AWS Secrets Manager” AWS Secrets Manager =================
Features: ✓ Automatic rotation (Lambda) ✓ Fine-grained IAM access ✓ Encryption via KMS ✓ Cross-account access ✓ Integration with RDS, ECS, Lambda
─────────────────────────────────────────
Secret Structure: { "username": "admin", "password": "secret-password", "engine": "mysql", "host": "db.example.com", "port": 3306, "dbname": "mydb" }Comparison
Section titled “Comparison”| Feature | HashiCorp Vault | AWS Secrets Manager | Azure Key Vault |
|---|---|---|---|
| Self-hosted | ✓ | ✗ | ✗ |
| Auto-rotation | ✓ | ✓ | ✓ |
| Dynamic secrets | ✓ | ✓ | Limited |
| Encryption | Bring your own | KMS | MHSM |
| Cost | Open source | Pay per secret | Pay per operation |
38.3 Implementing Secrets Management
Section titled “38.3 Implementing Secrets Management”Using Vault in Applications
Section titled “Using Vault in Applications”# Python with hvac (HashiCorp Vault client)import hvacimport os
# Connect to Vaultclient = hvac.Client( url=os.environ['VAULT_ADDR'], token=os.environ['VAULT_TOKEN'])
# Read secretsecret = client.secrets.kv.v2.read_secret_version( path='database/creds/myapp', mount_point='secret')
db_password = secret['data']['data']['password']
# Use in connection# connection = connect_db(password=db_password)# AWS Secrets Manager with boto3import boto3import json
def get_db_credentials(): client = boto3.client('secretsmanager')
response = client.get_secret_value( SecretId='prod/db/credentials' )
secret = json.loads(response['SecretString']) return secret['username'], secret['password']Vault Policies
Section titled “Vault Policies”# Read-only policy for applicationpath "secret/data/myapp/*" { capabilities = ["read"]}
# Read and write for deploymentpath "secret/data/deploy/*" { capabilities = ["read", "create", "update"]}
# Admin policypath "secret/*" { capabilities = ["create", "read", "update", "delete", "list"]}38.4 Secret Rotation
Section titled “38.4 Secret Rotation” Secret Rotation Pattern ======================
┌─────────────────────────────────────────────────────────────┐ │ Before Rotation │ │ │ │ App uses: password_v1 │ │ DB stores: password_v1 │ └─────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ Rotation Process (triggered by schedule or event) │ │ │ │ 1. Generate new password (password_v2) │ │ 2. Update database with password_v2 │ │ 3. Update Vault with password_v2 │ │ 4. Invalidate password_v1 │ └─────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ After Rotation │ │ │ │ App automatically retrieves new credentials │ │ (with short TTL or on next request) │ │ │ │ Uses: password_v2 ✓ │ └─────────────────────────────────────────────────────────────┘AWS Secrets Manager Auto-Rotation
Section titled “AWS Secrets Manager Auto-Rotation”# CloudFormation for RDS secret with rotationResources: MyDBSecret: Type: AWS::SecretsManager::Secret Properties: Name: !Sub 'rds-db-credentials-${DBInstanceName}' Description: Credentials for RDS MySQL GenerateSecretString: SecretStringTemplate: '{"username": "admin"}' GeneratePasswordKey: "password" Tags: - Key: "managed-by" Value: "cloudformation"
MyDBInstance: Type: AWS::RDS::DBInstance Properties: DBInstanceIdentifier: mydb MasterUserSecret: SecretArn: !Ref MyDBSecret38.5 Best Practices
Section titled “38.5 Best Practices” Secrets Management Checklist ============================
✓ NEVER commit secrets to git ✓ Use a secrets manager (Vault, AWS Secrets Manager) ✓ Enable automatic rotation ✓ Use short TTL for dynamic secrets ✓ Implement audit logging ✓ Restrict access with IAM/policies ✓ Encrypt secrets at rest ✓ Use different secrets per environment ✓ Implement secret vending (dynamic creds) ✓ Regular security audits
─────────────────────────────────────────
Environment-Specific Secrets: ─────────────────────────────
Development: • Shared credentials OK for local dev • Use .env files (not committed)
Staging: • Production-like secrets • Rotation enabled
Production: • Unique per service • Automatic rotation required • Audit everythingThe 12-Factor App Approach
Section titled “The 12-Factor App Approach” 12-Factor: Config ================
Store config in the environment:
# .env (local, NOT committed) DATABASE_URL=postgres://user:pass@localhost/db API_KEY=sk_test_xxx
# In code: import os db_url = os.environ['DATABASE_URL']
─────────────────────────────────────────
For secrets, use: 1. Environment variables (for container orchestration) 2. Secrets manager (for centralized management) 3. Combined: Secrets manager + inject as env varsSummary
Section titled “Summary”- Never commit secrets - Use environment variables or secrets manager
- Centralize - Use HashiCorp Vault, AWS Secrets Manager
- Rotate - Automatic rotation is essential
- Dynamic secrets - Generate per-use credentials
- Audit - Log all access to secrets
- Encrypt - At rest and in transit