fix(security): keep rotation credentials out of command output
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 2s

Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a12d13-27f2-7163-b8c0-f682af02772c
This commit is contained in:
tegwick 2026-10-12 12:54:10 +02:00
parent 681c5b0ea1
commit 6ae4708ea0
6 changed files with 429 additions and 104 deletions

View file

@ -224,3 +224,37 @@ signature verification or installed-toolchain promotion is claimed.
Source basis: [SOPS age identity loading](https://github.com/getsops/sops/blob/v3.13.3/age/keysource.go)
loads explicit and ambient identities together, so setting `SOPS_AGE_KEY_FILE`
alone is insufficient to exclude ambient credentials.
## Rotation output boundary (2026-10-12 source repair)
`creds-rotate.sh` keeps generated values out of stdout/stderr and disables shell
tracing. The selected plaintext secrets directory and service subdirectory must
be owned by the operator with no group/other access; `secrets.env` must be an
owned private regular file with one link and exactly one target assignment.
Symlink paths, missing keys and duplicate target assignments are refused before
cluster work. The helper replaces the file atomically with mode 0600 and never
places the new value in its command arguments. It accepts the generated
alphanumeric credential format. This is file hygiene, not process isolation.
Approved rotations preserve the new candidate in that private service file.
Transfer it through approved custody, verify real consumer authentication and
old-value refusal, refresh the encrypted recovery handoff, then remove plaintext.
A failed apply can leave a new local candidate while some services still use the
old value. Reconcile that partial state; do not infer completion from file contents.
Service-command diagnostics are suppressed because they can contain values;
use approved metadata-only diagnostics to investigate failures.
Database rotation stops before local mutation unless exactly one database pod
is discovered. SQL is sent on stdin with SQL-error failure enabled. Unattended
LLDAP admin-password rotation is refused because the server-update step is
manual. The attended path requires acknowledgment of that step before dependent
Secret updates; cancelling retains the local candidate and requires reconciliation.
Break-glass Secret creation reads the private file instead of a plaintext argv
literal and applies server-side without forcing field conflicts. This does not
remove historical client-side annotations or prove native consumer adoption.
The last-rotated timestamp records successful script steps only. No live rotation
was run for these source tests. CUST-WP-0073-T05 remains founder-deferred. RSA
rotation recovery/rollback, delegated helper argv/annotation handling and
`privacyidea/bootstrap-admin.sh` still require source and native acceptance.