Skip to main content

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.

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​

  1. Environment variables (recommended)
    export JWT_SECRET_KEY="<256-bit secret>"
    export DATABASE_PASSWORD="<rotated password>"
    export STRIPE_SECRET_KEY="sk_live_..."
  2. Cloud secret managers — AWS Secrets Manager/Parameter Store, GCP Secret Manager, Azure Key Vault, Kubernetes Secrets + External Secrets Operator.
  3. 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​

  1. Immediate (≤1 hour) — rotate compromised secrets, revoke API keys, change database passwords, invalidate JWTs.
  2. Investigation (≤24 hours) — review access logs, scope the incident, document timeline.
  3. 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.