Skip to main content

ADR-0008: Doppler for Secrets Management

Status

Accepted - 2025-01-26


Context

TVL Platform requires secure secrets management for sensitive credentials across all environments (development, staging, production):

Secrets to Manage

  • Database passwords (PostgreSQL connection strings)
  • API keys (Stripe, Hostaway, SendGrid, Linear)
  • OAuth secrets (Google OIDC client ID/secret)
  • Encryption keys (JWT signing keys, session secrets)
  • Third-party tokens (GitHub, Doppler itself)

Business Requirements

  • Fast developer onboarding (< 5 minutes to get secrets)
  • Team collaboration (shared secrets across team)
  • Fast secret rotation (security requirement)
  • Audit trail (who accessed what and when)
  • SOC 2 Type II compliance readiness

Technical Requirements

  • Secure storage (encryption at rest and in transit)
  • Automatic synchronization (no manual copying)
  • Environment separation (dev, staging, production)
  • CLI and UI access
  • Integration with CI/CD (GitHub Actions)
  • Works with Docker and DevContainers

Constraints

  • Small team (2-5 engineers initially)
  • Must be cost-effective for MVP (<$50/month)
  • Must work on macOS, Linux, Windows
  • Cannot commit secrets to git (security risk)

Decision

Doppler for cloud-based secrets management across all environments and team members.

Rationale

  1. SOC 2 Type II Certified: Meets compliance requirements
  2. Fast Onboarding: 5 minutes to setup vs. 30 minutes manually
  3. Automatic Sync: Secrets update when rotated (no manual copying)
  4. Audit Trail: Track who accessed which secrets when
  5. Free Tier: 5 users, unlimited secrets (perfect for MVP)
  6. Team Collaboration: Shared secrets automatically synchronized
  7. Fast Rotation: Rotate database passwords in 10 minutes vs. 2 hours manually

Alternatives Considered

Alternative 1: .env Files (Manual)

Rejected

Pros:

  • Simple (no external dependency)
  • Free
  • Works offline

Cons:

  • Manual copying of secrets (error-prone)
  • No audit trail (who accessed what?)
  • No rotation strategy (secrets become stale)
  • Risk of committing to git (happens accidentally)
  • Onboarding takes 30 minutes (find secrets, copy, verify)
  • No team collaboration (secrets in Slack/email - insecure)

Decision: Manual process doesn't scale, high security risk.


Alternative 2: AWS Secrets Manager

Rejected

Pros:

  • AWS-native (if using AWS)
  • Automatic rotation for RDS
  • Encryption with KMS

Cons:

  • Cost: $0.40/secret/month (~$20/month for 50 secrets)
  • AWS lock-in (we use Supabase, not RDS)
  • Complex IAM permissions
  • No UI (CLI only)
  • Requires AWS account setup
  • Not suitable for local development

Decision: Too expensive and complex for MVP, AWS-specific.


Alternative 3: HashiCorp Vault

Rejected

Pros:

  • Industry standard for large enterprises
  • Extremely flexible (dynamic secrets, encryption as a service)
  • Open source (self-hosted option)

Cons:

  • Operational Overhead: Requires dedicated Vault server, HA setup, backups
  • Complexity: Steep learning curve (policies, auth methods, seal/unseal)
  • Cost: HashiCorp Cloud Vault ~$50-200/month
  • Team Size: Overkill for 2-5 person team
  • No UI for secrets management (CLI or API only)

Decision: Too complex for small team, high ops burden.


Alternative 4: GitHub Secrets

Rejected

Pros:

  • Free
  • Built into GitHub Actions
  • Simple setup

Cons:

  • Only for CI/CD (not for local development)
  • No UI for local access
  • No audit trail
  • No automatic rotation
  • Secrets stored per-repository (not shared across team)

Decision: Solves CI/CD but not local development or team collaboration.


Alternative 5: Infisical

Rejected (for now)

Pros:

  • Open source (self-hosted option)
  • Similar to Doppler
  • Free tier (5 users)

Cons:

  • Less mature (founded 2022 vs. Doppler 2018)
  • Smaller community
  • Not SOC 2 certified (yet)
  • Less integrations

Decision: Doppler more mature and SOC 2 certified. Revisit if Infisical matures.


Consequences

Positive

  1. Security

    • SOC 2 Type II certified (third-party audited)
    • Encryption at rest (AES-256) and in transit (TLS 1.3)
    • Audit logs (who accessed which secrets when)
    • Role-based access control (RBAC)
    • No secrets in git (prevented by pre-commit hooks)
  2. Developer Experience

    • 5-minute onboarding (vs. 30 minutes manual)
    • Automatic sync (secrets update when rotated)
    • CLI and UI access
    • Works with Docker and DevContainers
    • IDE integration (VS Code extension available)
  3. Collaboration

    • Shared secrets across team (no Slack/email insecure sharing)
    • Team members automatically get updated secrets
    • Environment separation (dev, staging, production)
  4. Rotation

    • 10-minute rotation (vs. 2 hours manually)
    • Update in Doppler → All team members get new secrets automatically
    • Example: Rotate database password in 3 steps:
      1. Update password in Supabase
      2. Update DATABASE_URL in Doppler
      3. Done (all environments auto-sync)
  5. Compliance

    • SOC 2 Type II certified (required for enterprise customers)
    • Audit trail for compliance reports
    • Secret versioning (rollback if needed)
  6. Cost

    • Free tier: 5 users, unlimited secrets
    • Team tier: $12/user/month (if > 5 users)
    • Cost-effective for MVP and growth

Negative

  1. Vendor Lock-in

    • Dependent on Doppler (migration effort if switching)
    • Mitigation: Secrets stored in Doppler are exportable (JSON, .env format)
  2. External Dependency

    • Requires internet connection to fetch secrets
    • If Doppler down, cannot deploy or onboard
    • Mitigation: Doppler has 99.99% uptime SLA, can cache secrets locally
  3. Learning Curve

    • Team must learn Doppler CLI and UI
    • Mitigation: Simple CLI, team adapts quickly (~30 minutes)
  4. Cost at Scale

    • $12/user/month if > 5 users
    • 20 users = $240/month
    • Mitigation: Still cheaper than AWS Secrets Manager or Vault hosting

Doppler Setup

1. Install CLI

# macOS
brew install dopplerhq/cli/doppler

# Linux
curl -Ls https://cli.doppler.com/install.sh | sh

# Windows
scoop install doppler

2. Authenticate

# Login to Doppler
doppler login

# Verify authentication
doppler me

3. Setup Project

# Navigate to project directory
cd tvl-platform

# Link to Doppler project
doppler setup

# Select project: tvl-platform
# Select environment: development

4. Download Secrets

# Download to .env.local
doppler secrets download --no-file --format env > .env.local

# Or run commands with secrets injected
doppler run -- pnpm dev

5. CI/CD Integration

# .github/workflows/deploy.yml
name: Deploy

on:
push:
branches: [main]

jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Install Doppler CLI
uses: dopplerhq/cli-action@v3

- name: Deploy with secrets
run: doppler run -- ./deploy.sh
env:
DOPPLER_TOKEN: ${{ secrets.DOPPLER_TOKEN }}

Secrets Organization

Project Structure

tvl-platform/
├── development (local dev)
├── staging (pre-production)
└── production (live)

Secret Naming Convention

# Database
DATABASE_URL=postgresql://...
DATABASE_DIRECT_URL=postgresql://... # Supabase direct connection

# Redis
REDIS_URL=redis://...

# APIs
STRIPE_SECRET_KEY=sk_live_...
HOSTAWAY_API_KEY=...
SENDGRID_API_KEY=...
LINEAR_API_KEY=...

# OAuth
GOOGLE_CLIENT_ID=...
GOOGLE_CLIENT_SECRET=...

# Application
JWT_SECRET=...
SESSION_SECRET=...
NEXTAUTH_SECRET=...

# Environment (see ADR-0055 for details)
NODE_ENV=development|test|production # Build mode (set by framework)
APP_ENV=development|staging|production|preview # Deployment stage

Developer Workflow

Onboarding New Developer

  1. Install Doppler CLI (2 minutes)
  2. Login to Doppler (doppler login) (1 minute)
  3. Setup project (doppler setup) (1 minute)
  4. Download secrets (doppler secrets download) (1 minute)
  5. Start development (pnpm dev) ✅

Total: 5 minutes (vs. 30 minutes manually copying secrets)

Rotating a Secret

  1. Update secret in service (e.g., rotate Stripe API key in Stripe dashboard)
  2. Update in Doppler (UI or CLI)
    doppler secrets set STRIPE_SECRET_KEY=sk_live_new...
  3. Done ✅ (all team members and environments auto-sync)

Total: 10 minutes (vs. 2 hours manually updating all environments)

Adding a New Secret

# Add secret to current environment
doppler secrets set NEW_API_KEY=abc123

# Or use UI (doppler.com → project → secrets)

Security Best Practices

1. Never Commit Secrets

# .gitignore
.env
.env.local
.env.*.local
doppler.yaml

2. Use Service Tokens for CI/CD

# Create service token (read-only)
doppler configs tokens create ci-deploy --max-age 90d

# Use in GitHub Secrets
# DOPPLER_TOKEN = <service-token>

3. Rotate Secrets Regularly

  • High-Risk: Rotate every 30 days (API keys, database passwords)
  • Medium-Risk: Rotate every 90 days (OAuth secrets)
  • Low-Risk: Rotate every 180 days (JWT secrets)

4. Use Least Privilege

  • Developers: Read-only access to development environment
  • DevOps: Write access to staging and production
  • CI/CD: Service tokens (read-only, scoped to environment)

Validation Checklist

  • Doppler project created (tvl-platform)
  • Environments configured (dev, staging, production)
  • All secrets stored in Doppler (no .env files in git)
  • CLI installed on all developer machines
  • CI/CD integrated (GitHub Actions)
  • Audit logging enabled
  • Service tokens created for CI/CD
  • Team members have appropriate access levels
  • Secrets rotation schedule documented
  • Pre-commit hooks prevent committing .env files

References