Immutable. This exact content is served forever at /api/v1/blob/8c4bcff5fab1d711.
---
name: Secrets Management
description: Secure credential access with tiered providers, output masking, and web UI
trigger: secrets, credentials, database password, api key, aws secrets, environment variables, .env, get credentials, connection string, secret management
metadata:
provenance:
class: cpp-authored
---
# Secrets Management Skill
When the user asks about accessing secrets, credentials, or database connections, follow these security principles and patterns.
## Security Rules (CRITICAL)
1. **NEVER log or display actual secret values**
2. **ALWAYS use masked representations** in output
3. **Use `SecretValue` wrapper** for any sensitive data
4. **Validate credentials without exposing them**
5. **Default to READ_ONLY** database access
## Tiered Architecture
| Tier | Provider | Storage | Use Case |
|------|----------|---------|----------|
| **0** | `dotenv-global` | `~/.config/claude-power-pack/secrets/{project_id}/.env` | Local dev (default) |
| **1** | `env-file` | Environment variables / `.env` in repo | Legacy compat |
| **2** | `aws-secrets-manager` | AWS Secrets Manager | Production |
## Project Identity
Secrets are scoped per-project using a stable ID derived from the git repo root:
```python
from lib.creds.project import get_project_id
project_id = get_project_id() # e.g., "claude-power-pack"
```
All worktrees for the same repo share the same project_id and secrets.
## Bundle API (Recommended)
```python
from lib.creds import get_bundle_provider
from lib.creds.project import get_project_id
provider = get_bundle_provider()
bundle = provider.get_bundle(get_project_id())
print(bundle) # Keys visible, values masked
# Set a secret
from lib.creds.base import SecretBundle
update = SecretBundle(project_id=get_project_id(), secrets={"API_KEY": "value"})
provider.put_bundle(update, mode="merge")
```
## Secret Injection
Run commands with secrets as environment variables (never in CLI args):
```bash
python -m lib.creds run -- make deploy
python -m lib.creds run -- ansible-playbook deploy.yaml
```
## Usage Patterns
### Getting Database Credentials
```python
from lib.creds import get_credentials
creds = get_credentials() # Auto-detect provider
print(creds.connection_string) # postgresql://user:****@host:5432/db
conn = await asyncpg.connect(**creds.dsn) # dsn has real password
```
### Masking Output
```python
from lib.creds import mask_output
safe = mask_output("password=secret123") # "password=****"
```
## Commands
| Command | Purpose |
|---------|---------|
| `/secrets:get [id]` | Get credentials (masked output) |
| `/secrets:set KEY VALUE` | Set or update a secret |
| `/secrets:list` | List all secret keys (masked) |
| `/secrets:run -- CMD` | Run command with secrets injected |
| `/secrets:validate` | Test credential configuration |
| `/secrets:ui` | Launch web UI for management |
| `/secrets:rotate KEY` | Rotate a secret value |
| `/secrets:help` | Overview of all commands |
## CLI Usage
```bash
PYTHONPATH="$HOME/Projects/claude-power-pack/lib:$PYTHONPATH"
python3 -m lib.creds <command> [options]
```
## Best Practices
1. **Store secrets in global config, not repo** - Use `creds set`
2. **Use get_credentials() helper** - Handles provider detection
3. **Inject with `creds run`** - Never pass secrets as CLI args
4. **Launch UI for bulk management** - `creds ui`
5. **Audit log tracks all actions** - `~/.config/claude-power-pack/audit.log`