- Add statusline.sh and set-topic.sh for per-session status line topics - Update context-load with improved directory walking and output format - Update CLAUDE.md with status line docs and early-call safety note - Update MEMORY.md and README.md with new script/skill entries - Add memory files: script-statusline, skill-decompose, skill-orchestrate, gotchas-gitea - Add networking.md best practice (nftables, systemd sockets, Docker forwarding, TLS) - Update best practices from prior distill: documentation, kubernetes, scripting, secrets-management, skills-development - Prune reflected session logs, add new session logs - Update reflection state Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
54 lines
3.0 KiB
Markdown
54 lines
3.0 KiB
Markdown
# Secrets Management
|
|
|
|
## SOPS + age
|
|
|
|
SOPS with age encryption is the standard across all projects. A single `.sops.yaml` at the repo root defines path-based encryption rules.
|
|
|
|
### File Naming
|
|
|
|
- `.sops.yaml` path-based rules match specific filename patterns (e.g., `**/*secret*.yaml`)
|
|
- Non-secret files must NOT contain `secret` in their name, or the pre-commit hook will encrypt them
|
|
- KSOPS generator files should be named `ksops-generator.yaml`, not `secret-generator.yaml`
|
|
|
|
### encrypted_regex Gotcha
|
|
|
|
When using `encrypted_regex` for selective field encryption (e.g., Ansible group_vars), variable names must contain a keyword that matches the regex (e.g., `password|private_key|api_key|secret|token`). Arbitrary key names are silently left unencrypted.
|
|
|
|
### SOPS Vars Plugin
|
|
|
|
Each Ansible project needs `vars_plugins_enabled = host_group_vars,community.sops.sops` in `ansible.cfg`. Files in `group_vars/` must be named after a group (e.g., `all.sops.yaml`), not arbitrary names.
|
|
|
|
### Interactive Editor Pitfalls
|
|
|
|
- `sops <file>` opens an interactive editor — fails in non-interactive sessions
|
|
- `sops -e /tmp/file` fails when the temp path doesn't match `.sops.yaml` rules
|
|
- Multiple `sops --set` calls can corrupt files — use the interactive editor for multi-field edits
|
|
|
|
## Credential Handling
|
|
|
|
- **Never pass secrets via command-line arguments** — visible in `ps` output
|
|
- Use `@file` references, environment variables sourced at runtime, or stdin
|
|
- For Ansible, use temp files with `trap rm` cleanup: `-e "@${tmpfile}"`
|
|
- Read secrets at execution time and use them ephemerally — never cache or persist values
|
|
- Reference the **existence** of a secret file in docs, never its contents
|
|
|
|
## Bootstrap Secrets
|
|
|
|
Some secrets are chicken-and-egg (e.g., the age decryption key for ArgoCD's KSOPS). These must be created manually as a bootstrap step and documented clearly.
|
|
|
|
## Credential Lifecycle Management
|
|
|
|
- **Track credential expiry dates.** OAuth client secrets, API tokens, and certificates have expiry dates that can cause silent failures. Document expiry dates when creating credentials.
|
|
- **Set alerts before expiry.** For long-lived credentials (e.g., 720-day OAuth client secrets), set calendar reminders or automated monitoring alerts well before they expire.
|
|
- **Rotation plan.** Know the rotation procedure before you need it — some credential types (e.g., Azure app registrations) require coordinated updates across multiple systems.
|
|
|
|
## Multi-Field Secret Files
|
|
|
|
Secret files that contain multiple fields (e.g., repo URL, token, username) cannot be used as bare values. Consumers must parse individual fields (e.g., `grep + awk` or structured YAML/JSON parsing).
|
|
|
|
The multi-field format is preferable because it's self-documenting — all related credentials live together. But any automation reading the file needs extraction logic, not just `cat`.
|
|
|
|
## Backup Considerations
|
|
|
|
Backup plans must include encryption keys (age private keys, etc.) so that encrypted data in Git repos remains recoverable.
|