Skip to main content

Secrets Management - TVL Platform

Status: Active Operational Guide Tool: Doppler (Cloud-based secrets management) SOC 2: Type II Certified Last Updated: 2025-10-25


Overview

This document outlines how the TVL Platform manages sensitive configuration (secrets) across all environments using Doppler.

Secrets include:

  • Database connection strings
  • API keys (Stripe, Hostaway, Airbnb, etc.)
  • OAuth client secrets
  • Webhook signing secrets
  • Service account credentials

Why Doppler?

RequirementManual .envDoppler
Team Onboarding30 min (manual sharing)5 min (invite to workspace)
Secret Rotation2 hours (update everywhere)10 min (update once, auto-sync)
Audit Trail❌ None✅ Yes (who accessed what when)
SOC 2 Compliance❌ Manual documentation✅ Built-in audit logs
Cost (5 users)$0$0 (free tier)
MaintenanceManualZero (fully managed)

Decision: Doppler provides enterprise-grade secrets management at zero cost for our team size.


Architecture

Environment Structure

tvl-platform/ (Doppler project)
├── development (local dev)
│ ├── DATABASE_ENVIRONMENT=local
│ ├── DATABASE_URL=postgresql://localhost:5432/tvl_dev
│ └── NODE_ENV=development

├── integration (Supabase dev)
│ ├── DATABASE_ENVIRONMENT=supabase-dev
│ ├── DATABASE_URL=postgresql://supabase-dev...
│ ├── SUPABASE_URL=https://[dev-ref].supabase.co
│ ├── SUPABASE_ANON_KEY=eyJh...
│ └── NODE_ENV=development

├── staging (Supabase staging)
│ ├── DATABASE_ENVIRONMENT=supabase-staging
│ ├── DATABASE_URL=postgresql://supabase-staging...
│ ├── SUPABASE_URL=https://[staging-ref].supabase.co
│ ├── STRIPE_SECRET_KEY=sk_test_... (test mode)
│ └── NODE_ENV=staging

└── production (Supabase production)
├── DATABASE_ENVIRONMENT=supabase-production
├── DATABASE_URL=postgresql://supabase-prod...
├── SUPABASE_URL=https://[prod-ref].supabase.co
├── STRIPE_SECRET_KEY=sk_live_... (live mode)
└── NODE_ENV=production

Access Control

RoleDevelopmentIntegrationStagingProduction
DeveloperRead/WriteRead/WriteRead❌ No Access
Tech LeadRead/WriteRead/WriteRead/WriteRead
DevOpsRead/WriteRead/WriteRead/WriteRead/Write
CI/CD (Service Token)❌ No AccessReadReadRead

Principle: Developers never have write access to production secrets.


Secrets Inventory

Database Credentials

SecretEnvironmentsRotation FrequencyOwner
DATABASE_URLAllQuarterlyDevOps
DATABASE_TEST_URLDevelopmentQuarterlyDevOps
POSTGRES_USERDevelopmentQuarterlyDevOps
POSTGRES_PASSWORDDevelopmentQuarterlyDevOps

Supabase Credentials

SecretEnvironmentsRotation FrequencyOwner
SUPABASE_URLIntegration, Staging, ProductionNever (project URL)DevOps
SUPABASE_ANON_KEYIntegration, Staging, ProductionQuarterlyDevOps
SUPABASE_SERVICE_ROLE_KEYIntegration, Staging, ProductionQuarterlyDevOps

Payment Processing (V1.0+)

SecretEnvironmentsRotation FrequencyOwner
STRIPE_PUBLISHABLE_KEYAllRarely (public key)Tech Lead
STRIPE_SECRET_KEYAllQuarterlyTech Lead
STRIPE_WEBHOOK_SECRETAllWhen compromisedTech Lead

Integration Partners

SecretEnvironmentsRotation FrequencyOwner
HOSTAWAY_CLIENT_IDAllRarelyTech Lead
HOSTAWAY_CLIENT_SECRETAllWhen team member leavesTech Lead
AIRBNB_WEBHOOK_SECRETAllWhen team member leavesTech Lead
VRBO_API_KEYAllQuarterlyTech Lead

Development Tools

SecretEnvironmentsRotation FrequencyOwner
LINEAR_API_KEYShared (all envs)When team member leavesTech Lead
GITHUB_TOKENCI/CD onlyAnnuallyDevOps

Total: ~25 secrets across 4 environments = 100 secret values


Developer Workflows

Onboarding New Developer

Time: 5 minutes

# 1. Tech lead invites developer to Doppler
# https://dashboard.doppler.com/workplace/[workplace]/members
# Click "Invite Member" → Enter email → Assign to "Developer" role

# 2. Developer receives email, accepts invite

# 3. Developer installs Doppler CLI
brew install dopplerhq/cli/doppler

# 4. Developer authenticates
doppler login

# 5. Developer selects project
cd the-villa-life
doppler setup
# Choose: tvl-platform → development

# 6. Developer syncs secrets
doppler secrets download --no-file --format env > .env.local

# 7. Developer opens devcontainer
# F1 → Dev Containers: Reopen in Container

# ✅ Done! Developer has all secrets

Daily Development

No manual steps required.

Secrets automatically loaded from .env.local:

# 1. Open VS Code
code .

# 2. Reopen in Container
# F1 → Dev Containers: Reopen in Container

# 3. Start coding
# ✅ Secrets available in environment

Switching Environments

Example: Switch from local to Supabase dev integration

# 1. Select environment
doppler setup
# Choose: tvl-platform → integration

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

# 3. Rebuild container
# F1 → Dev Containers: Rebuild Container

# ✅ Now using Supabase dev environment

Operational Procedures

Quarterly Secret Rotation

Frequency: Every 3 months Owner: DevOps Time: 30 minutes

Checklist:

  1. Generate new credentials:

    • Supabase: Reset project service role key
    • Stripe: Generate new secret key (test + live)
    • Database: Change PostgreSQL role passwords
  2. Update Doppler (all environments):

    # Development
    doppler secrets set DATABASE_URL="postgresql://service_role:NEW_PASSWORD@..." --config development

    # Integration
    doppler secrets set SUPABASE_SERVICE_ROLE_KEY="NEW_KEY" --config integration

    # Staging
    doppler secrets set STRIPE_SECRET_KEY="sk_test_NEW_KEY" --config staging

    # Production
    doppler secrets set STRIPE_SECRET_KEY="sk_live_NEW_KEY" --config production
  3. Notify team (Slack #engineering):

    🔐 Quarterly secret rotation completed.

    Action required: Update your local secrets
    1. Run: doppler secrets download > .env.local
    2. Rebuild container: F1 → Dev Containers: Rebuild

    If issues, see: docs/operations/secrets-management.md
  4. Update CI/CD service tokens (if needed):

    • Regenerate GitHub Actions DOPPLER_TOKEN_STAGING
    • Update GitHub repository secrets
  5. Audit access logs:

    • Review Doppler audit logs (last 90 days)
    • Check for unauthorized access
    • Document any anomalies

Team Member Offboarding

When: Developer leaves team Owner: Tech Lead Time: 20 minutes

Checklist:

  1. Revoke Doppler access:

  2. Rotate sensitive secrets:

    • LINEAR_API_KEY (shared across team)
    • HOSTAWAY_CLIENT_SECRET (integration access)
    • Any secrets the developer had write access to
  3. Update Doppler:

    doppler secrets set LINEAR_API_KEY="NEW_KEY" --config development
    doppler secrets set HOSTAWAY_CLIENT_SECRET="NEW_SECRET" --config production
  4. Notify team:

    🔐 Secrets rotated due to team change.

    Run: doppler secrets download > .env.local && rebuild container
  5. Revoke other access:

    • GitHub organization membership
    • Supabase dashboard access
    • Linear workspace access
    • AWS/GCP console (if applicable)
  6. Audit:

    • Review Doppler logs for departed member's last access
    • Verify no API keys created by departed member
    • Document in security log

Emergency: Compromised Secret

When: Secret suspected or confirmed leaked Owner: Tech Lead (escalate to DevOps if production) Time: 10 minutes

Example: STRIPE_SECRET_KEY accidentally committed to GitHub

Immediate Actions:

  1. Revoke compromised secret (< 2 minutes):

    # Stripe example:
    # 1. Login to Stripe dashboard
    # 2. Developers → API Keys → "..." → Revoke
    # 3. Generate new key
  2. Update Doppler (< 1 minute):

    doppler secrets set STRIPE_SECRET_KEY="sk_live_NEW_KEY" --config production
  3. Notify team (Slack #engineering-alerts):

    🚨 SECURITY ALERT: Stripe secret key compromised

    Status: ✅ Revoked and rotated
    Impact: Production API calls may fail for ~5 minutes

    Action required (all devs):
    1. Run: doppler secrets download > .env.local
    2. Rebuild container

    Incident: INC-2025-001
  4. Force redeploy services (< 5 minutes):

    # Production backend (uses new key)
    kubectl rollout restart deployment/backend -n production

    # Production frontend (may need new publishable key)
    kubectl rollout restart deployment/frontend -n production
  5. Post-incident:

    • Review Stripe audit logs (identify unauthorized charges)
    • Check Doppler logs (who accessed secret before compromise)
    • Update GitHub to detect secrets in commits (git-secrets, pre-commit hooks)
    • Document incident in security log
    • Schedule post-mortem (if significant impact)

Audit & Compliance

Monthly Audit Review

Owner: Tech Lead Time: 30 minutes

Checklist:

  1. Review Doppler audit logs:

    • Login to https://dashboard.doppler.com
    • Navigate to Workplace → Audit
    • Filter last 30 days
    • Check for:
      • ✅ Production secret access (should be rare)
      • ✅ Unusual access times (after hours)
      • ✅ Failed authentication attempts
      • ✅ Bulk secret downloads
  2. Anomaly investigation:

    Example findings:
    - Developer A accessed production secrets at 2am
    → Action: Ask Developer A (legitimate? debugging prod issue?)

    - Unknown IP accessed staging
    → Action: Check if VPN IP, escalate to DevOps

    - Service token used from new region
    → Action: Verify CI/CD runner, check GitHub Actions logs
  3. Document findings:

    • Create audit report in docs/operations/audit-logs/2025-10.md
    • Note any action items
    • Review with team in monthly security meeting

SOC 2 Compliance

Requirement: Demonstrate secure secrets management

Evidence provided by Doppler:

  1. Access Controls (CC6.1)

    • ✅ Role-based access (Developer, Tech Lead, DevOps)
    • ✅ Production secrets restricted to Tech Lead + DevOps only
    • ✅ Audit logs show who accessed what secret when
  2. Encryption (CC6.7)

    • ✅ Secrets encrypted at rest (AES-256)
    • ✅ Secrets encrypted in transit (TLS 1.3)
    • ✅ Doppler SOC 2 Type II report available
  3. Audit Logging (CC7.2)

    • ✅ All secret access logged
    • ✅ 30-day retention (free tier), 1-year (team tier)
    • ✅ Logs immutable (cannot be deleted)
  4. Incident Response (CC7.3)

    • ✅ Documented procedure (this doc: Emergency section)
    • ✅ Fast rotation capability (10 minutes)
    • ✅ Notification workflow (Slack alerts)

For SOC 2 audit:

  • Provide Doppler SOC 2 Type II report
  • Demonstrate quarterly rotation schedule
  • Show audit log review process (monthly)
  • Document offboarding procedure (this doc)

Backup & Disaster Recovery

Doppler Outage (Unlikely)

Doppler SLA: 99.9% uptime (Team tier)

Mitigation:

  1. Local cache (automatic):

    # Doppler CLI caches secrets locally
    ls ~/.doppler/cache/
    # Even if Doppler is down, cached secrets work
  2. Emergency fallback (.env.local):

    # .env.local already contains latest secrets
    # Container works normally during Doppler outage
    # ✅ No action needed
  3. If .env.local deleted:

    # 1. Use Doppler cache (if available)
    doppler secrets --fallback-readonly

    # 2. Contact team member for .env.local copy
    # 3. Or wait for Doppler to restore (typically < 1 hour)

Secrets Backup

Frequency: Weekly (automated) Owner: DevOps Storage: 1Password (encrypted team vault)

Process:

# Export all environments (weekly cron job)
doppler secrets download --no-file --format env --config development > backup-development.env
doppler secrets download --no-file --format env --config integration > backup-integration.env
doppler secrets download --no-file --format env --config staging > backup-staging.env
doppler secrets download --no-file --format env --config production > backup-production.env

# Encrypt backups
gpg --encrypt --recipient devops@thevillalife.com backup-*.env

# Upload to 1Password team vault
# Folder: "Doppler Backups" → Item: "2025-10-25"

# Delete local copies
rm backup-*.env backup-*.env.gpg

Restore process (if Doppler data loss):

  1. Download encrypted backup from 1Password
  2. Decrypt: gpg --decrypt backup-production.env.gpg > production.env
  3. Re-import to Doppler: doppler secrets upload production.env --config production

Cost Management

Current State (Free Tier)

MetricLimitUsageStatus
Users53✅ Under limit
SecretsUnlimited~100✅ OK
EnvironmentsUnlimited4✅ OK
ProjectsUnlimited1✅ OK

Cost: $0/month


Future (Team Tier)

When: Team grows past 5 users

MetricCostNotes
Base$12/user/monthUnlimited everything
10 users$120/month= $1,440/year
20 users$240/month= $2,880/year

ROI Analysis:

Cost TypeManualDoppler Team (10 users)
Time savings$1,500/yearSaved (automated)
Doppler subscription$0$1,440/year
Net Cost$1,500/year$1,440/year

Breakeven: Doppler pays for itself via time savings, even at Team tier.


Migration Plan (If Needed)

Scenario: Migrating to Infisical (Self-Hosted)

When: Team > 15 users, Doppler cost > self-hosted cost

Timeline: 1 week

Steps:

  1. Export from Doppler:

    doppler secrets download --no-file --format json > secrets-export.json
  2. Deploy Infisical:

    • Deploy Docker Compose/Kubernetes
    • Configure backups
    • Setup SSL/TLS
  3. Import to Infisical:

    infisical import secrets-export.json
  4. Update team:

    • Install Infisical CLI
    • Re-authenticate
    • Test sync
  5. Cutover:

    • Switch CI/CD to Infisical tokens
    • Archive Doppler account (keep for 1 month)

Estimated cost: 40 hours DevOps time = $4,000 one-time


Summary

Current Setup:

  • ✅ Doppler (free tier) for all secrets
  • ✅ 4 environments (development, integration, staging, production)
  • ✅ ~100 secret values managed
  • ✅ SOC 2 Type II certified (helps achieve compliance)

Key Workflows:

  • Onboarding: 5 minutes (vs 30 minutes manual)
  • Rotation: 10 minutes (vs 2 hours manual)
  • Offboarding: 20 minutes (revoke + rotate)
  • Emergency: 10 minutes (revoke + redeploy)

Compliance:

  • ✅ Quarterly rotation schedule
  • ✅ Monthly audit log review
  • ✅ Offboarding procedure documented
  • ✅ Emergency response plan

Next Steps:

  1. ✅ Setup Doppler account (Tech Lead)
  2. ✅ Add all secrets to Doppler
  3. ✅ Invite team members
  4. ✅ Test rotation workflow
  5. ✅ Schedule quarterly rotation reminder

Last Updated: 2025-10-25 Owner: Tech Lead Review Frequency: Quarterly (or when significant changes)