fix(auth): sign served decisions before recording and returning them
Some checks failed
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Build and Publish Container Image / build-and-push (push) Failing after 1m27s

Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a140c4-354a-7823-8f0d-8f717397f786
This commit is contained in:
tegwick 2026-10-16 07:51:43 +02:00
parent 62ac2b4e99
commit ec21518e25
11 changed files with 361 additions and 14 deletions

View file

@ -5,7 +5,7 @@ Date: 2026-09-14
Contract: additive on `flex-auth.decision-record.v1`
Does **not** change `request_digest`.
The response channel is unauthenticated today (`FLEX-DEC-2026-010`). Digests
The original response channel was unauthenticated (`FLEX-DEC-2026-010`). Digests
cannot fix that: every input to them is sent by the caller or published.
Fail-closed cannot fix that either: it covers a missing PDP, not a lying one.
@ -117,3 +117,52 @@ T03 adds the field, emits unsigned when unconfigured, and ships a fixture
pair: one genuine signed envelope and one whose payload was altered after
signing. It does **not** mint the production key and does **not** wait for
the OpenBao lane to exist before the code path is testable.
## NetKingdom target source follow-through (2026-10-16)
Owner source review of Secrets Engine R2 patch
`98c4300c42fe93759a55297fe6629f1d4aeed249c3625f7fd37c8ab523a08ca9`
verified unchanged `api`/`internal/sign` bytes and producer replay fixtures at
`62ac2b4e99dec2005c7c407fe633612578a7907d`. The consumer runs the Go producer
verifier and uses its returned typed envelope, then independently checks issuer,
policy package/version/digest, exact submitted request and lifetime. This avoids
another envelope canonicalization implementation or PDP.
That revision implemented `Sign` only for fixtures: `serve` could not load a key
or sign responses. The follow-through adds `serve --envelope-signing-key-file`
and `--envelope-signing-kid`. Configure both or neither. The mounted file contains
one unpadded base64url 32-byte Ed25519 seed, optionally with trailing whitespace;
it must be regular and have no group-write or world permissions (0440 is accepted). No production key is supplied
or minted here. Configuration failures abort startup. The key is read once:
rotation requires an owner rollout/restart, not an assumed hot reload.
Signing occurs after the complete envelope is constructed and before the durable
recorder, for check, batch and list decisions alike. Returned and recorded objects
therefore agree. Existing unsigned developer mode remains explicit; authenticated
Secrets Engine production refuses it. The signature schema, canonical bytes and
request digest are unchanged, so this patch does not require a consumer vendored
source refresh.
Both retained `flex-auth` and new `access-engine` charts expose an inert
`envelopeSigning` block. Enabling requires `kid`, `secretName`, `secretKey`, and an
absolute `mountPath`. They mount an existing custody-owned Secret read-only;
they do not provision it. The existing Secrets pin values remain unchanged and
unsigned until an exact reviewed image/values rollout is admitted.
The `/v1/keys` route described earlier is a discovery design, **not an implemented
route**. It must never bootstrap independent trust. For this first consumer, the
owner transports reviewed public keys plus exact issuer/policy pins independently
into the consumer's admission file. No runtime discovery dependency is needed.
Rotation admits new public key alongside old in every consumer, proves new-key
acceptance, rolls producer to new seed/kid, waits past the maximum outstanding
allow lifetime plus bounded clock uncertainty, removes old key, and proves old-key
refusal. A revoked/compromised old key is removed immediately rather than retained
for overlap. Retain public verification material in audit custody for historic
records without treating it as current runtime authority.
Rollout remains blocked on independent public-key and policy-pin admission;
OpenBao/Platform custody and exact secret mount; reviewed producer image/digest;
owner-bound loopback tunnel and caller audience; installation of the reviewed
consumer verifier binary (the Python wheel alone omits it); exact consumer source
and hash drift check; and native positive/negative/rotation plus record-custody
receipts. Local fixtures and chart renders do not establish those outcomes.