NK-WP-0049: redraft T17 Authelia acceptance and add T41 adapter preparation
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s

Design review 2026-10-24: KeyCape's source confirms the KeyCape->Authelia->LLDAP
human-login chain. T17 now checks the durable Authelia secrets and the keycape
client verifier rather than leaning on storage decryption. T41 prepares the
stage in the existing anchor-namespace pattern, reusing pinned modules unedited.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 328925@bnt-lap001
Assistant-Session: 14b795fd-c632-4c01-8d28-e7e490c7b0ed
This commit is contained in:
tegwick 2026-10-24 16:51:20 +02:00
parent acf961ad84
commit b2de807d7d
3 changed files with 64 additions and 4 deletions

View file

@ -290,6 +290,7 @@
| task | NK-WP-0049-T38 | done | — | workplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.md |
| task | NK-WP-0049-T39 | done | — | workplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.md |
| task | NK-WP-0049-T40 | done | — | workplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.md |
| task | NK-WP-0049-T41 | progress | — | workplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.md |
| task | NK-WP-0050-T01 | done | — | workplans/NK-WP-0050-playwright-consumer-registration.md |
| task | NK-WP-0050-T02 | progress | — | workplans/NK-WP-0050-playwright-consumer-registration.md |
| task | NK-WP-0050-T03 | wait | — | workplans/NK-WP-0050-playwright-consumer-registration.md |

View file

@ -135,7 +135,7 @@ current production password validity, MFA or audit continuity.
| Task / owner lane | Positive check | Negative check | Safe evidence |
| --- | --- | --- | --- |
| T16 / LLDAP | Preserved user/group/membership identities; existing-user bind/login | Wrong password rejected | Image/target IDs, aggregate comparisons and booleans |
| T17 / Authelia | Native storage decryption; same signing identity/client configs; isolated authentication | Wrong credentials or unregistered client refused | Public key thumbprint, test outcome, notification suppression |
| T17 / Authelia | Original config validates; storage key opens store; issuer JWKS equals archived key; `keycape` client verifier accepts KeyCape's archived secret; existing-user first factor against restored LLDAP | Wrong password and wrong client secret refused; no grant issued | Public key thumbprint, outcomes, file-notifier only (stage prepared in T41) |
| T19 / privacyIDEA MFA | Existing retained token decrypts internally and actual existing-token MFA succeeds | Wrong enckey and invalid code refused in disposable copies | Token material never exported; bounded outcomes only |
| T20 / privacyIDEA audit | Verify historical signatures; create and verify one isolated entry with original key | Mismatched public key/tampered disposable record rejected | Signature counts, continuity result, cleanup |
| T18 / KeyCape | Same issuer/JWKS, registry/policy/receipt continuity; named current consumer authenticates | Wrong secret and denied scope rejected | Public fingerprints, owner-selected test IDs and outcomes |

View file

@ -8,7 +8,7 @@ status: active
owner: codex
topic_slug: netkingdom
created: "2026-10-12"
updated: "2026-10-17"
updated: "2026-10-24"
flavor: implementation
depends_on: []
state_hub_workstream_id: "17d315f0-829e-57c7-85cc-3a7914152804"
@ -508,8 +508,8 @@ id: NK-WP-0049-T17
status: wait
priority: high
assignee: codex
depends_on: [NK-WP-0049-T15, NK-WP-0049-T16]
blocking_reason: "LLDAP recovery T16 passed; await the exact isolated Authelia adapter/procedure and private authentication-flow inputs from T15."
depends_on: [NK-WP-0049-T15, NK-WP-0049-T16, NK-WP-0049-T41]
blocking_reason: "LLDAP recovery T16 passed. Await the T41 adapter (prepared and fixture-tested), then a founder-attended run with the age key and an existing-user password."
state_hub_task_id: "b47f9975-d6d7-5bb8-93ce-886deb1dfa70"
```
@ -525,6 +525,25 @@ positive/negative results using the restored directory. Disable outbound
notifications and verify cleanup. Archive integrity/RSA parsing alone are not
native Authelia acceptance.
2026-10-24 redraft, after design review with the founder. KeyCape's source
(`key-cape/src/internal`, `config/dev-config.yaml`) confirms the human-login chain:
KeyCape delegates first factor to Authelia as upstream OIDC with the `keycape`
client secret, Authelia binds against LLDAP, and KeyCape adds MFA through
privacyIDEA. The durable Authelia state that matters is in the Secret and config:
the OIDC issuer key, HMAC secret, `keycape` client verifier, storage encryption key
and LDAP bind password. The SQLite store holds little under `one_factor`, so
storage decryption is a cheap check here, not the main proof. T17 acceptance is:
(1) the original configuration validates with the original secrets, notifier
switched to a tmpfs file notifier; (2) the storage encryption key opens the
restored store; (3) the issuer JWKS public key equals the archived issuer key;
(4) the restored `keycape` client verifier accepts KeyCape's archived client
secret and refuses a wrong one, at the token endpoint, with no grant issued;
(5) first-factor login through Authelia against the restored LLDAP succeeds for
an existing user, a wrong password is refused. The full KeyCape→Authelia→LLDAP→
privacyIDEA human-login chain is not part of T17. T18's selected consumer
(SECRETS-WP-0015-T04) is a workload login and does not pass through Authelia;
a human-login consumer acceptance would need its own selection and admission.
## Prove retained privacyIDEA token decryption and existing-token MFA
```task
@ -1448,6 +1467,46 @@ attempt readiness, T18 actual recovery/consumer acceptance and T19 retained-fact
MFA remain open. No actual archive, private key, Secret object, token exchange,
OpenBao login, rotation, production action or owner assent was exercised.
## Prepare and fixture-test the isolated Authelia restore stage
```task
id: NK-WP-0049-T41
status: progress
priority: high
assignee: claude-code
depends_on: [NK-WP-0049-T16, NK-WP-0049-T29]
```
**Accountable worker:** claude-code; the founder retains the actual private
recovery inputs and runs the T17 stage.
Add `isolated-authelia.py` and `run-isolated-authelia.sh` to
`tools/bootstrap-recovery/`, the Authelia counterpart of T29. Design, from the
2026-10-24 review:
- Topology: the anchor-namespace pattern already used by the KeyCape session.
Restored LLDAP is the `--network none` anchor; Authelia and the probe client
join `container:<anchor>` and talk over loopback only. No new network.
- Reuse without edits: import helpers from `isolated-lldap.py` and the other
existing modules. Do not modify `isolated-lldap.py` or the KeyCape files;
they are in the pinned source-hash list of the T38/T40 attempt.
- Inputs: the verified transfer receipt, the age key via
`sops-custody-unlock.sh`, an existing-user password by private prompt.
Original Authelia secrets and the `keycape` client secret come from the
archive, never from argv, environment listings or files outside tmpfs.
- Confinement: LDAP URL rewritten to loopback, SMTP notifier replaced by a
tmpfs file notifier, `authelia-smtp` not imported. Containment inspection
before private import; container and tmpfs cleanup verified on every exit.
- Checks: the five T17 acceptance items. Receipt records booleans, counts, the
issuer key thumbprint and image IDs only.
**Done when:** unit tests cover config assembly (original secrets kept, notifier
and LDAP rewritten, path escape refused, missing secret refused), and an opt-in
synthetic-fixture test (`NK49_RUN_ISOLATED_AUTHELIA_TEST=1`) passes on the pinned
local images with disposable credentials only. The packet in
`docs/identity-service-restore-packet.md` names the stage and its exact command.
This prepares T17; it is not T17 acceptance and touches no production service.
## Accept remaining recovery and caller evidence and close the G08 handoff
```task