# 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
