Secrets Management
Secure secret handling keeps Relay deployments compliant and breach-resistant. Follow these practices across development, staging, and production.
Never Commit Secrets to Git
Production secrets, API keys, passwords, certificates, and .env files with real values must never appear in version control. Treat even short-lived credentials as sensitive.
Recommended Workflow
Environment File Layout
.env.example # Template with placeholders (committed)
.env # Local development secrets (gitignored)
.env.production # Production secrets (never committed)
.env.staging # Staging secrets (never committed)
Secret Generator
Use the provided helper to mint high-entropy values:
python scripts/security/generate_secrets.py # single secrets
python scripts/security/generate_secrets.py --generate-env # full .env template
Production Storage Options
- Environment variables (recommended)
export JWT_SECRET_KEY="<256-bit secret>"
export DATABASE_PASSWORD="<rotated password>"
export STRIPE_SECRET_KEY="sk_live_..." - Cloud secret managers — AWS Secrets Manager/Parameter Store, GCP Secret Manager, Azure Key Vault, Kubernetes Secrets + External Secrets Operator.
- HashiCorp Vault for rotation + audit trails:
vault kv put secret/relay-protocol jwt_secret="..." db_password="..."
vault kv get -field=jwt_secret secret/relay-protocol
Best Practices
- Generate secrets with cryptographically secure randomness (≥256-bit entropy for signing keys).
- Use distinct secrets per environment and service.
- Rotate secrets on defined cadences (JWT every 90 days, DB passwords every 180 days, API keys per provider guidance, certificates before expiry).
- Enforce least privilege and audit access regularly.
- Monitor for exposure via security scans (
python scripts/security/vulnerability_scanner.py) and alert on unusual key usage.
Validation Hooks
At startup, Relay validates required secrets and aborts if any are missing:
required = ['JWT_SECRET_KEY', 'DATABASE_URL']
missing = [s for s in required if not os.getenv(s)]
if missing:
raise ConfigurationError(f"Missing required secrets: {missing}")
Production runs also guard against default secrets:
if settings.ENVIRONMENT == "production" and settings.JWT_SECRET_KEY == "change-me-in-production":
raise SecurityError("Default JWT secret detected in production")
Incident Response
- Immediate (≤1 hour) — rotate compromised secrets, revoke API keys, change database passwords, invalidate JWTs.
- Investigation (≤24 hours) — review access logs, scope the incident, document timeline.
- Recovery (≤48 hours) — deploy new secrets, verify system integrity, update monitoring, capture post-incident review.
If secrets reach git history, coordinate a cleanup (git filter-branch or bfg) and rotate all affected credentials.
Compliance Notes
- GDPR/CCPA — encrypt personal data in transit/at rest, maintain deletion workflows, log access.
- SOC 2 Type II — document secret management procedures, enforce access control, schedule recurring security assessments.