Skip to content

Sawabona - Secrets Management Guide

Version: 2.0 Last Updated: 2026-01-28 Architecture: Single-Tenant Rust

Introduction

Secrets management is critical for production security. Sawabona implements a tiered approach supporting three deployment scenarios:

  1. Development: Environment variables with .env files
  2. Self-Hosted: Docker secrets with encrypted files
  3. Production: AWS Secrets Manager or Azure Key Vault with automatic rotation

Compliance Considerations

  • SOC 2: Requires encryption at rest and audit logging
  • PCI-DSS: Requires secure storage of payment provider credentials
  • GDPR: Requires encryption of sensitive data

Secrets Inventory

Core Secrets

Secret Purpose Rotation Required For
JWT_SECRET Authentication tokens 90 days All deployments
ADMIN_API_KEY Admin operations 90 days All deployments
SAWABONA_ENCRYPTION_KEY Data encryption (AES-256-GCM) 90 days All deployments
DATABASE_URL PostgreSQL connection 90 days All deployments

Note: SAWABONA_ENCRYPTION_KEY accepts both standard and URL-safe base64 encoding. It must decode to exactly 32 bytes.

Payment Provider Secrets

Secret Provider Purpose Rotation Required For
SAWABONA_STRIPE_SECRET_KEY Stripe Payment processing As needed Stripe integration
SAWABONA_STRIPE_WEBHOOK_SECRET Stripe Webhook verification As needed Stripe webhooks
ADYEN_API_KEY Adyen Payment processing As needed Adyen integration
ADYEN_WEBHOOK_SECRET Adyen Webhook verification As needed Adyen webhooks
FLUTTERWAVE_SECRET_KEY Flutterwave Payment processing As needed Flutterwave integration
PAYSTACK_SECRET_KEY PayStack Payment processing As needed PayStack integration
MERCADOPAGO_ACCESS_TOKEN MercadoPago Payment processing As needed MercadoPago integration
PAGSEGURO_TOKEN PagSeguro Payment processing As needed PagSeguro integration
BRAINTREE_PRIVATE_KEY Braintree Payment processing As needed Braintree integration

Important: Payment provider API keys are encrypted at rest using AES-256-GCM before storage in the database. For Stripe, the API key is auto-seeded from SAWABONA_STRIPE_SECRET_KEY on startup (encrypted with SAWABONA_ENCRYPTION_KEY).

Backend Comparison

Feature Env Vars Docker Secrets AWS Secrets Manager Azure Key Vault
Cost Free Free $0.40/secret/month $0.03/10k ops
Rotation Manual Manual Automatic Automatic
Audit Logs No No Yes Yes
Encryption at Rest No No Yes (KMS) Yes (HSM)
Complexity Low Medium High High

Setup Instructions

Environment Variables (Development)

# Copy template
cp .env.example .env

# Edit with your values
nano .env

# Validate
make validate-secrets

Docker Secrets (VPS)

# Create secrets directory
mkdir -p secrets

# Generate secrets
openssl rand -base64 64 > secrets/jwt_secret.txt
openssl rand -base64 32 > secrets/admin_api_key.txt
openssl rand -base64 32 > secrets/postgres_encryption_key.txt

# Set permissions
chmod 600 secrets/*

# Deploy
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d

AWS Secrets Manager (Production)

# Create secret
aws secretsmanager create-secret \
  --name sawabona/production/secrets \
  --secret-string '{
    "jwt_secret": "...",
    "admin_api_key": "...",
    "stripe_secret_key": "..."
  }' \
  --region us-east-1

# Configure IAM role for ECS/EC2
# Attach policy: SecretsManagerReadSecretPolicy

# Set environment variables
export SAWABONA_SECRETS_BACKEND=aws_secrets_manager
export AWS_SECRETS_MANAGER_SECRET_NAME=sawabona/production/secrets
export AWS_SECRETS_MANAGER_REGION=us-east-1

Azure Key Vault (Production)

# Create Key Vault
az keyvault create \
  --name sawabona-vault \
  --resource-group sawabona-rg

# Add secrets
az keyvault secret set \
  --vault-name sawabona-vault \
  --name jwt-secret \
  --value "..."

# Configure managed identity
# Assign role: Key Vault Secrets User

# Set environment variables
export SAWABONA_SECRETS_BACKEND=azure_keyvault
export AZURE_KEYVAULT_URL=https://sawabona-vault.vault.azure.net/

Rotation Procedures

JWT Secret Rotation

# Generate new secret
NEW_SECRET=$(openssl rand -base64 64)

# Rotate (with grace period)
sawabona rotate-jwt-secret --new-secret $NEW_SECRET

# Verify rotation
sawabona verify-jwt-rotation

Payment Provider Key Rotation

Coordinate with payment provider:

  • Stripe: Rotate in Stripe Dashboard
  • PayStack: Rotate in PayStack Dashboard
  • Others: Follow provider's rotation procedure

Database Encryption Key Rotation

Complex operation requiring downtime:

# 1. Backup database
pg_dump sawabona > backup.sql

# 2. Rotate key (requires application restart)
# 3. Re-encrypt data
# 4. Verify encryption

# 5. Restore if needed
psql sawabona < backup.sql

Security Best Practices

  1. Never log secrets - Sanitize logs to remove sensitive data
  2. Use separate secrets per environment - Dev, staging, production
  3. Implement least-privilege access - Restrict who can access secrets
  4. Monitor secret access - Enable audit logging
  5. Rotate regularly - Every 90 days for long-lived secrets
  6. Incident response - Have a plan for leaked secrets

Troubleshooting

Secrets not loading

# Check environment variables
env | grep SAWABONA

# Validate secrets file
python scripts/validate_secrets.py --env-file .env

# Check Docker secrets
docker exec sawabona-server cat /run/secrets/jwt_secret

Encryption errors

# Verify pgcrypto is enabled
psql -c "CREATE EXTENSION pgcrypto;"

# Check encryption key
echo $POSTGRES_ENCRYPTION_KEY | wc -c  # Should be 44+ chars

AWS Secrets Manager errors

# Check IAM permissions
aws iam get-user

# Verify secret exists
aws secretsmanager get-secret-value \
  --secret-id sawabona/production/secrets \
  --region us-east-1