Files
bootstrap/guides/VAULT-SECRETS.md
2026-02-21 09:55:34 -06:00

5.2 KiB

Vault Secrets Management Guide

This guide applies when the project uses HashiCorp Vault for secrets management.

Before Starting

  1. Verify Vault access: vault status
  2. Authenticate: vault login (method depends on environment)
  3. Check your permissions for the required paths

Canonical Structure

ALL Vault secrets MUST follow this structure:

{mount}/{service}/{component}/{secret-name}

Components

  • mount: Environment-specific mount point
  • service: The service or application name
  • component: Logical grouping (database, api, oauth, etc.)
  • secret-name: Specific secret identifier

Environment Mounts

Mount Environment Usage
secret-dev/ Development Local dev, CI
secret-staging/ Staging Pre-production testing
secret-prod/ Production Live systems

Examples

# Database credentials
secret-prod/postgres/database/app
secret-prod/mysql/database/readonly
secret-staging/redis/auth/default

# API tokens
secret-prod/authentik/admin/token
secret-prod/stripe/api/live-key
secret-dev/sendgrid/api/test-key

# JWT/Authentication
secret-prod/backend-api/jwt/signing-key
secret-prod/auth-service/session/secret

# OAuth providers
secret-prod/backend-api/oauth/google
secret-prod/backend-api/oauth/github

# Internal services
secret-prod/loki/read-auth/admin
secret-prod/grafana/admin/password

Standard Field Names

Use consistent field names within secrets:

Purpose Fields
Credentials username, password
Tokens token
OAuth client_id, client_secret
Connection url, host, port
Keys public_key, private_key

Example Secret Structure

// secret-prod/postgres/database/app
{
  "username": "app_user",
  "password": "secure-password-here",
  "host": "db.example.com",
  "port": "5432",
  "database": "myapp"
}

Rules

  1. DO NOT GUESS secret paths - Always verify the path exists
  2. Use helper scripts in scripts/vault/ when available
  3. All lowercase, hyphenated (kebab-case) for all path segments
  4. Standard field names - Use the conventions above
  5. No sensitive data in path names - Path itself should not reveal secrets
  6. Environment separation - Never reference prod secrets from dev

Deprecated Paths (DO NOT USE)

These legacy patterns are deprecated and should be migrated:

Deprecated Migrate To
secret/infrastructure/* secret-{env}/{service}/...
secret/oauth/* secret-{env}/{service}/oauth/{provider}
secret/database/* secret-{env}/{service}/database/{user}
secret/credentials/* secret-{env}/{service}/{component}/{name}

Reading Secrets

CLI

# Read a secret
vault kv get secret-prod/postgres/database/app

# Get specific field
vault kv get -field=password secret-prod/postgres/database/app

# JSON output
vault kv get -format=json secret-prod/postgres/database/app

Application Code

Python (hvac):

import hvac

client = hvac.Client(url='https://vault.example.com')
secret = client.secrets.kv.v2.read_secret_version(
    path='postgres/database/app',
    mount_point='secret-prod'
)
password = secret['data']['data']['password']

Node.js (node-vault):

const vault = require('node-vault')({ endpoint: 'https://vault.example.com' });
const secret = await vault.read('secret-prod/data/postgres/database/app');
const password = secret.data.data.password;

Go:

secret, err := client.Logical().Read("secret-prod/data/postgres/database/app")
password := secret.Data["data"].(map[string]interface{})["password"].(string)

Writing Secrets

Only authorized personnel should write secrets. If you need a new secret:

  1. Request through proper channels (ticket, PR to IaC repo)
  2. Follow the canonical structure
  3. Document the secret's purpose
  4. Set appropriate access policies
# Example (requires write permissions)
vault kv put secret-dev/myapp/database/app \
  username="dev_user" \
  password="dev-password" \
  host="localhost" \
  port="5432"

Troubleshooting

Permission Denied

Error: permission denied
  • Verify your token has read access to the path
  • Check if you're using the correct mount point
  • Confirm the secret path exists

Secret Not Found

Error: no value found at secret-prod/data/service/component/name
  • Verify the exact path (use vault kv list to explore)
  • Check for typos in service/component names
  • Confirm you're using the correct environment mount

Token Expired

Error: token expired
  • Re-authenticate: vault login
  • Check token TTL: vault token lookup

Security Best Practices

  1. Least privilege - Request only the permissions you need
  2. Short-lived tokens - Use tokens with appropriate TTLs
  3. Audit logging - All access is logged; act accordingly
  4. No local copies - Don't store secrets in files or env vars long-term
  5. Rotate on compromise - Immediately rotate any exposed secrets