Skip to content

Secrets Management

Secure handling of sensitive configuration data across all Jubiloop environments.

Overview

Jubiloop uses a multi-layered approach to secrets management:

  1. GitHub Secrets - Primary storage for CI/CD secrets
  2. Environment Variables - Runtime injection of secrets
  3. 1Password - Team access and secret sharing
  4. Automated Discovery - Scripts to identify required secrets

Secret Storage

GitHub Secrets

All deployment secrets are stored in GitHub:

  • Repository-level secrets
  • Environment-specific secrets
  • Encrypted at rest
  • Access controlled by GitHub permissions

Adding Secrets:

bash
# Via GitHub UI
Settings Secrets and Variables Actions New repository secret

# Secret naming convention
{ENVIRONMENT}_{SERVICE}_{KEY_NAME}

1Password Vault

Team secrets are documented in 1Password:

  • Jubiloop vault for shared access
  • Environment-specific sections
  • Secure notes for context
  • API keys and credentials

Secret Types

Application Secrets

Database Credentials

  • PostgreSQL passwords
  • Redis passwords
  • Connection strings

API Keys

  • Third-party service keys
  • OAuth credentials
  • Webhook secrets

Encryption Keys

  • JWT secrets
  • Session keys
  • Encryption passwords

Infrastructure Secrets

Cloud Provider

  • DigitalOcean API tokens
  • Cloudflare API keys
  • Terraform state credentials

Deployment

  • SSH private keys
  • Ansible vault passwords
  • Container registry tokens

Secret Patterns

Auto-Generated Names

Using from_secrets in configuration:

yaml
DEV:
  server:
    APP_KEY: 'from_secrets'
    # Generates: DEV_SERVER_APP_KEY

Explicit References

For shared secrets between services:

yaml
DEV:
  server:
    DB_PASSWORD: '${{ secrets.DEV_POSTGRES_PASSWORD }}'
  postgres:
    POSTGRES_PASSWORD: '${{ secrets.DEV_POSTGRES_PASSWORD }}'

Secret Discovery

List Required Secrets

bash
cd infra/deploy

# All secrets
node scripts/extract-config.js list-secrets

# Environment-specific
node scripts/extract-config.js list-secrets --env dev

Verify Secret Configuration

bash
# Check missing secrets
node scripts/generate-env-files.js DEV --list-secrets

# Generate documentation
node scripts/extract-config.js documentation

Security Best Practices

Secret Generation

Strong Passwords:

bash
# Generate secure password
openssl rand -base64 32

# Generate hex string
openssl rand -hex 32

API Key Format:

  • Minimum 32 characters
  • Include special characters
  • Avoid predictable patterns

Access Control

Principle of Least Privilege:

  • Only necessary team members
  • Environment-specific access
  • Regular access reviews

Secret Sharing:

  • Never share via chat/email
  • Use 1Password for sharing
  • Document access in team wiki

Audit and Compliance

Secret Usage Tracking:

  • GitHub audit logs
  • Deployment logs
  • Access monitoring

Regular Audits:

  • Quarterly secret review
  • Access permission audit
  • Unused secret cleanup

Common Secret Patterns

Database URLs

yaml
# Pattern
DATABASE_URL: 'postgresql://user:${{ secrets.DB_PASS }}@host:5432/db'

# Separate components
DB_HOST: 'localhost'
DB_USER: 'app_user'
DB_PASSWORD: '${{ secrets.DEV_DB_PASSWORD }}'
DB_NAME: 'jubiloop_dev'

API Configuration

yaml
# External service pattern
STRIPE_PUBLIC_KEY: 'pk_test_...'
STRIPE_SECRET_KEY: '${{ secrets.DEV_STRIPE_SECRET }}'
STRIPE_WEBHOOK_SECRET: '${{ secrets.DEV_STRIPE_WEBHOOK }}'

Sanity Studio Deploy Token

For hosted Studio deployments in CI, use SANITY_STUDIO_DEPLOY_TOKEN (repo secret), mapped to SANITY_AUTH_TOKEN in the workflow step that runs:

yaml
- name: Deploy Sanity Studio
  env:
    SANITY_AUTH_TOKEN: ${{ secrets.SANITY_STUDIO_DEPLOY_TOKEN }}
  run: npx --yes sanity@latest deploy --non-interactive --tag $ENVIRONMENT

This token is only required for the CLI deployment step and is not used by the marketing site at runtime.

Troubleshooting

Secret Not Found

  1. Check exact secret name (case-sensitive)
  2. Verify secret exists in GitHub
  3. Check environment spelling
  4. Review deployment logs

Invalid Secret Format

  1. Check for special characters
  2. Verify encoding (base64 if needed)
  3. Check length requirements
  4. Test locally with dry-run

Access Denied

  1. Verify GitHub permissions
  2. Check environment access
  3. Contact team admin
  4. Review audit logs

Emergency Procedures

Compromised Secret

  1. Immediate Actions:

    • Revoke compromised secret
    • Generate new secret
    • Update all environments
  2. Investigation:

    • Review access logs
    • Identify exposure scope
    • Document incident
  3. Remediation:

    • Deploy new secrets
    • Monitor for misuse
    • Update security procedures

Recovery Process

  1. Access 1Password backup
  2. Regenerate from source
  3. Contact service provider
  4. Update all references

Documentation

Required Documentation

For each secret:

  • Purpose and usage
  • Format requirements
  • Source (if external service)
  • Dependencies

Secret Inventory

Maintain inventory in 1Password:

  • Service name
  • Environment
  • Last rotation date
  • Owner/contact

Built with ❤️ by the Jubiloop team