diff --git a/docs/operations.md b/docs/operations.md index 142fe9a..7a6e254 100644 --- a/docs/operations.md +++ b/docs/operations.md @@ -145,6 +145,12 @@ read it first. The parts that apply to KeyCape's objects in `sso` and `mfa`: with `kubectl replace`. To test for the annotation without printing it: `kubectl get secret -n sso -o go-template='{{ if index .metadata.annotations "kubectl.kubernetes.io/last-applied-configuration" }}HAS-ANNOTATION{{ else }}clean{{ end }}'`. +- **Never run any other go-template or jsonpath against a Secret.** When a + template fails, for example `len` on an absent field, kubectl prints the whole + raw object as debugging output, `.data` included. The presence check above is + the only tested template. This leaked `sso/keycape-config` into an agent + session on 2026-09-23 (see below). + **Open finding, 2026-09-23:** `sso/keycape-config`, `sso/authelia-secrets`, `sso/lldap-secrets` and `mfa/privacyidea-config` all carry that annotation. The earlier rotation script wrote them with `apply`; it now uses `replace`. Anyone @@ -155,6 +161,13 @@ is a live change and waits for the founder's go-ahead: for each of the four. It prints no value and leaves `.data` untouched, so pods need no restart. Re-check with the template above afterwards. +**Superseded the same day by an exposure.** While checking these Secrets' owners +before the cleanup, an agent ran an untested template. It failed and printed +`keycape-config` in full into the session transcript: the signing key, the LLDAP +bind password and the Authelia client secret. The other three Secrets were +probably printed as well. All four must be treated as exposed and rotated; the +annotation cleanup folds into that rotation. + ## Unreleased fail-closed startup changes (read before the next rollout) The deployed image at the time of writing is