# 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 ```bash # 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 ```json // 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 ```bash # 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):** ```python 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):** ```javascript 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:** ```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 ```bash # 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