From 8ae5150d4d43c8dd39175f0ba260198a3c022843 Mon Sep 17 00:00:00 2001 From: tegwick Date: Fri, 16 Oct 2026 21:14:23 +0200 Subject: [PATCH] docs(recovery): accept retained token material and audit continuity Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a13eab-1e6a-7b33-9c37-372e90ada3a2 --- docs/bootstrap-recovery-ceremony.md | 15 ++++++ .../actual-isolated-privacyidea-recovery.json | 54 +++++++++++++++++++ .../actual-isolated-privacyidea-review.json | 29 ++++++++++ docs/identity-service-restore-packet.md | 16 +++--- .../capability.security.bootstrap-recovery.md | 15 +++--- tools/bootstrap-recovery/README.md | 5 +- ...-bootstrap-secret-free-recovery-handoff.md | 37 +++++++------ 7 files changed, 141 insertions(+), 30 deletions(-) create mode 100644 docs/evidence/2026-10-16-identity-outage-recovery/actual-isolated-privacyidea-recovery.json create mode 100644 docs/evidence/2026-10-16-identity-outage-recovery/actual-isolated-privacyidea-review.json diff --git a/docs/bootstrap-recovery-ceremony.md b/docs/bootstrap-recovery-ceremony.md index d13a451..a9c3f94 100644 --- a/docs/bootstrap-recovery-ceremony.md +++ b/docs/bootstrap-recovery-ceremony.md @@ -520,3 +520,18 @@ plaintext were cleaned; failure markers and event outbox remain empty. This validates the actual hardened recurring-job path, beyond a direct CLI capture. Evidence: `recurring-job-review.json`. No further validation captures are needed before the next scheduled run absent a new failure or source change. + + +## Native token-material and audit acceptance — 2026-10-16 + +The independently retrieved identity generation passed native privacyIDEA checks +on the fixed isolated local engine: all five retained token materials were read +internally using the original enckey; unrelated-key results differed for all five. +All 279,209 stored historical signatures verified, with zero unsigned/invalid +rows. A new isolated entry verified with the preserved identity; tampering and +an unrelated public key were refused. Container/plaintext cleanup passed. +T20/T31 are done. Safe evidence and source/ciphertext/target bindings are in +`evidence/2026-10-16-identity-outage-recovery/actual-isolated-privacyidea-review.json`. +This accepts internal readback and stored-row signature continuity. Existing-token +MFA, Authelia and KeyCape authentication remain separate; event completeness is +not claimed. The published Storage Share kit remains its recorded version. diff --git a/docs/evidence/2026-10-16-identity-outage-recovery/actual-isolated-privacyidea-recovery.json b/docs/evidence/2026-10-16-identity-outage-recovery/actual-isolated-privacyidea-recovery.json new file mode 100644 index 0000000..972729c --- /dev/null +++ b/docs/evidence/2026-10-16-identity-outage-recovery/actual-isolated-privacyidea-recovery.json @@ -0,0 +1,54 @@ +{ + "schema": "netkingdom.isolated-privacyidea-recovery.v1", + "status": "isolated_privacyidea_checked", + "production_contacted": false, + "secret_values_exported": false, + "existing_token_mfa_proven": false, + "audit_signature_continuity_proven": true, + "container_cleanup_verified": true, + "temporary_plaintext_cleanup_verified": true, + "source_sha256": "4df7196678aac1ad594f32abf45c68dc21a9d2760d9e8a536a215a4a3c5d277f", + "target": { + "engine_id": "74f93783-6cef-43a8-a3c4-f62586cd3bc1", + "engine_name": "bnt-lap001", + "images": [ + { + "reference": "docker.io/lldap/lldap@sha256:9e605a66c02514bfcffd1b67cafb1e98d50992216bb2871d7ae44622047dd09d", + "image_id": "sha256:9e605a66c02514bfcffd1b67cafb1e98d50992216bb2871d7ae44622047dd09d" + }, + { + "reference": "ghcr.io/gpappsoft/privacyidea-docker@sha256:af7841adad262f129e0c1d4f553af13f21cb2f4dc713533f316cfe43ed0b4473", + "image_id": "sha256:af7841adad262f129e0c1d4f553af13f21cb2f4dc713533f316cfe43ed0b4473" + }, + { + "reference": "postgres@sha256:ff23cdce56cac62ada6f66013e1a50864c0abbe79d132d40b6e05bd80f378a70", + "image_id": "sha256:ff23cdce56cac62ada6f66013e1a50864c0abbe79d132d40b6e05bd80f378a70" + } + ], + "production_contacted": false, + "network_mode": "none", + "host_ports_published": false + }, + "ciphertext_sha256": "7117b3fe1e4840c86b301c94c85e6b16709e5626bb0884bd0580bde630e30e30", + "manifest_file_count": 36, + "all_manifest_hashes_verified": true, + "container_isolation_verified_before_private_import": true, + "retained_tokens_total": 5, + "retained_tokens_with_native_decryption": 5, + "different_key_cannot_reproduce_material_count": 5, + "retained_token_material_decrypted_inside_process": true, + "historical_audit_rows": 279209, + "historical_signed_rows": 279209, + "historical_unsigned_rows": 0, + "historical_invalid_signatures": 0, + "historical_legacy_signatures": 0, + "all_stored_audit_rows_checked": true, + "legacy_signature_verification_enabled": false, + "event_completeness_claimed": false, + "new_audit_entry_signed_verified": true, + "tampered_entry_refused": true, + "wrong_audit_public_key_refused": true, + "only_loopback_interface_verified": true, + "external_routes_absent": true, + "finished_at": "2026-10-16T19:10:46.010387+00:00" +} diff --git a/docs/evidence/2026-10-16-identity-outage-recovery/actual-isolated-privacyidea-review.json b/docs/evidence/2026-10-16-identity-outage-recovery/actual-isolated-privacyidea-review.json new file mode 100644 index 0000000..c17a7a9 --- /dev/null +++ b/docs/evidence/2026-10-16-identity-outage-recovery/actual-isolated-privacyidea-review.json @@ -0,0 +1,29 @@ +{ + "schema": "netkingdom.actual-isolated-privacyidea-review.v1", + "status": "verified", + "accepted_at": "2026-10-16T19:10:46.010387+00:00", + "receipt": "actual-isolated-privacyidea-recovery.json", + "source_commit": "3223039446dc92c692dafb587127e93701a3c230", + "source_sha256_matches": true, + "known_recovered_ciphertext_matches": true, + "exact_local_target_matches": true, + "manifest_files_verified": 36, + "retained_token_materials_read_internally": 5, + "wrong_key_material_refusals": 5, + "historical_signatures_verified": 279209, + "historical_unsigned_or_invalid_rows": 0, + "new_signature_and_negative_checks_verified": true, + "container_and_plaintext_cleanup_verified": true, + "existing_token_mfa_proven": false, + "event_completeness_claimed": false, + "agent_received_private_credentials": false, + "accepted_tasks": [ + "NK-WP-0049-T20", + "NK-WP-0049-T31" + ], + "knowledge_orientation": { + "version": "0.2.6", + "digest": "8d1d6a9d4d07fec7b619618de7dfe2be2254c1790f85f4198c7fe19db9751c02", + "source_status": "withheld; current repository security companion reviewed directly" + } +} diff --git a/docs/identity-service-restore-packet.md b/docs/identity-service-restore-packet.md index 58aaeff..0f5aead 100644 --- a/docs/identity-service-restore-packet.md +++ b/docs/identity-service-restore-packet.md @@ -1,8 +1,8 @@ # Isolated identity service restore packet NK-WP-0049-T15. Prepared 2026-10-16. **Actual LLDAP recovery accepted at -18:37 UTC. Native privacyIDEA token-material/audit stage is prepared for an -owner run; MFA, Authelia and KeyCape stages remain unexecuted.** +18:37 UTC; native privacyIDEA token-material/audit recovery accepted at +19:10 UTC. Existing-token MFA, Authelia and KeyCape remain unexecuted.** Accountable preparer: codex. Execution/acceptance: Railiance Platform and the LLDAP, Authelia, KeyCape and privacyIDEA service owners. @@ -143,7 +143,7 @@ current production password validity, MFA or audit continuity. Do not silently reset credentials or re-enroll tokens to pass. Historical audit verification failures must be reported, not hidden with replacement keys. -## Ready owner step: privacyIDEA token material and stored audit history +## Accepted privacyIDEA token-material and stored-audit stage ```bash bash tools/bootstrap-recovery/run-isolated-privacyidea.sh \ @@ -193,8 +193,12 @@ scan. Counts/signatures/keys are never replaced with a sample to claim success. Exit0 means these bounded checks and cleanup passed. Exit2 means checks completed but historical audit exceptions need owner disposition; T20 must stay open. Exit1 indicates another failure. All outcomes have a safe receipt in the printed -private evidence directory. Return only that directory and the outcome. Actual -owner results are still pending; native synthetic fixtures do not close T20/T31. +private evidence directory. Return only that directory and the outcome. Actual owner recovery passed at 19:10 UTC on 2026-10-16: five retained token +materials read internally, 279,209 historical signatures verified, no unsigned or +invalid rows, new-entry verification, both negative checks and cleanup passed. +T20/T31 are done. Source/ciphertext/target bindings and the safe receipt are in +`evidence/2026-10-16-identity-outage-recovery/actual-isolated-privacyidea-review.json`. +Existing-token MFA remains T19; event completeness is not claimed. ## Unresolved inputs before execution @@ -209,6 +213,6 @@ owner results are still pending; native synthetic fixtures do not close T20/T31. - Service-owner acceptance of network/config translations and all required grants. New grants or production effects require their own owner decisions. -Until resolved, T15 stays in progress and T17–T20 remain waiting; T16 is done. Production +Until resolved, T15 stays in progress and T17–T19 remain waiting; T16, T20 and T31 are done. Production cutover, full-host/OpenBao restoration and application database recovery are separate owner procedures. diff --git a/registry/capabilities/capability.security.bootstrap-recovery.md b/registry/capabilities/capability.security.bootstrap-recovery.md index 19e9b58..31321da 100644 --- a/registry/capabilities/capability.security.bootstrap-recovery.md +++ b/registry/capabilities/capability.security.bootstrap-recovery.md @@ -120,14 +120,14 @@ consumer_guidance: or recovery - 2026-10-14 architecture review estimates operational maturity separately; a registry entry does not authorize execution or establish deployment. - - Actual old privacyIDEA database recovery passed; full token decryption, audit - continuity and directory/issuer authentication remain open. + - Actual privacyIDEA internal token-material readback and stored audit continuity + passed; existing-token MFA, Authelia and KeyCape authentication remain open. - Storage Share initial destination only; no second-provider full identity copy or autonomous bare-VM restore is established. - Actual first full identity bundle captured, sealed and Storage Share readback verified on2026-10-16; both scoped readers passed native identity/namespace/audience/ESO checks. Independent human-key full archive recovery passed and daily backup/hourly - health are active. Complete service authentication/token decryption/audit continuity + health are active. Full service authentication, existing-token MFA and an unattended full-estate rebuild remain unproven. 56 focused implementation checks pass. --- @@ -172,12 +172,13 @@ with synthetic credentials passed, including an encrypted-bundle restore. All five pinned service images were saved/reloaded locally. T28/T29 record that preparation. Actual private real-backup LLDAP recovery passed on 2026-10-16; T16 is done, with original identity rows, positive/negative native bind, -isolation and cleanup accepted. Other service/MFA/audit lanes remain open. +isolation and cleanup accepted. Authelia, KeyCape and existing-token MFA remain open. -The next prepared stage is `run-isolated-privacyidea.sh TRANSFER_RECEIPT`, with +The token-material/audit stage is `run-isolated-privacyidea.sh TRANSFER_RECEIPT`, with only a hidden backup-key prompt. Its pinned native routines check internal token-material readback and stored audit signatures, preserve original keys, report history exceptions and remove the isolated database/worker/tmpfs. Native synthetic tests cover valid, tampered and unsigned history, malformed keys and -encrypted-bundle recovery. Actual owner evidence remains T20/T31; existing-token -MFA remains T19 and is not implied by token-material decryption. +encrypted-bundle recovery. Actual owner recovery passed on 2026-10-16: five token materials read internally, +279,209 stored signatures verified, new-entry/negative checks and cleanup passed. +T20/T31 are done; existing-token MFA remains T19 and is not implied by readback. diff --git a/tools/bootstrap-recovery/README.md b/tools/bootstrap-recovery/README.md index 0d7352c..5ae5946 100644 --- a/tools/bootstrap-recovery/README.md +++ b/tools/bootstrap-recovery/README.md @@ -29,7 +29,7 @@ grant. Actual-image synthetic tests and the real owner backup-recovery run passed on 2026-10-16; T16 is done. See the packet and actual LLDAP receipt for the exact target, resource limits, accepted scope and repeat-drill command. -`run-isolated-privacyidea.sh TRANSFER_RECEIPT` is the next prepared owner step. +`run-isolated-privacyidea.sh TRANSFER_RECEIPT` is the token-material/audit recovery step. It asks only for the existing backup age key. `isolated-privacyidea.py` restores the linked dump into a loopback-only PostgreSQL/container namespace, reads retained token material internally, and verifies all stored audit signatures @@ -37,6 +37,9 @@ plus one new isolated entry and wrong-public-key/tampering negatives. Original keys are preserved; audit exceptions are reported without rewriting history. No MFA code is consumed or native MFA acceptance claimed. Exit2 requires owner review of audit exceptions; see the packet for bounds and safe receipts. +The actual owner run passed on 2026-10-16: five retained token materials, +279,209 historical signatures, new-entry and negative checks, and cleanup. +T20/T31 are done; actual existing-token MFA remains T19. `verify-bundle.py` validates a digest-bound age-encrypted `secrets/` tar archive using an explicit private temporary key and registered `keys/age.pub`. It checks diff --git a/workplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.md b/workplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.md index ae327a6..fb558b3 100644 --- a/workplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.md +++ b/workplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.md @@ -28,8 +28,8 @@ These are retrospective task records of evidenced work, not additional delivery or newly granted authority. The earlier dated narrative remains in Git at `cc2dd01`; its evidence references are carried into the tasks below. -**Current position:** 20 tasks done; 2 in progress; 1 ready to start (`todo`); -8 waiting on explicit prerequisites. These are task counts, not an effort-based +**Current position:** 22 tasks done; 2 in progress; 1 ready to start (`todo`); +6 waiting on explicit prerequisites. These are task counts, not an effort-based completion percentage. Assignees are also written in task descriptions because the current Forge projector does not populate the dedicated Hub assignee field. The outage-retrieval tool and restore-packet draft are now prepared; independent outage retrieval and Storage Share publication are accepted; @@ -494,7 +494,7 @@ status: wait priority: high assignee: codex depends_on: [NK-WP-0049-T15, NK-WP-0049-T16, NK-WP-0049-T31] -blocking_reason: "LLDAP recovery T16 passed; await the exact isolated privacyIDEA adapter/procedure and owner-selected retained-token/MFA inputs." +blocking_reason: "LLDAP T16, token-material T31 and audit T20 passed; await the exact isolated MFA adapter and owner-selected retained-token/factor inputs." state_hub_task_id: "6f8af1a7-2a3f-5fa8-8202-83103ebd55b2" ``` @@ -521,11 +521,10 @@ selected user's private factor input and exact isolated MFA adapter remain T19. ```task id: NK-WP-0049-T20 -status: wait +status: done priority: high assignee: codex depends_on: [NK-WP-0049-T13, NK-WP-0049-T30] -blocking_reason: "Await the private owner run of the prepared T30 audit/token-material executor with the independent backup age key; exact local target, original-key preservation and native fixtures are prepared." state_hub_task_id: "375fa8f9-b8a5-5048-97a7-ec141aa7c45d" ``` @@ -542,14 +541,16 @@ for explicit owner disposition; do not regenerate keys to hide it. Matching RSA pairs from T13 are a prerequisite, not audit-history verification. -2026-10-16: the bounded audit stage is prepared in T30 independently of the full -multi-service T15 packet. **Unblock:** owner runs -`bash tools/bootstrap-recovery/run-isolated-privacyidea.sh /tmp/nk49-offline-handoff-1X660a5t/transfer.json` -in a private terminal and returns the safe outcome/receipt. It requests only the -backup age key, never MFA or provider credentials. All stored historical rows -are checked; unsigned/invalid history is reported for explicit owner disposition -and never rewritten. Exit2 is a review outcome, not completion. Existing-token -MFA and event completeness are not claimed by this audit stage. +Completed 2026-10-16 at 19:10 UTC using the actual independently retrieved +bundle and original audit identity on the fixed isolated local engine. All +279,209 stored rows were signed and verified; zero unsigned, invalid or legacy +signatures. A new isolated entry verified, and tampering/unrelated-public-key +checks were refused. Container/plaintext cleanup passed. Receipt and reviewed +source/ciphertext/target bindings: `actual-isolated-privacyidea-recovery.json` +and `actual-isolated-privacyidea-review.json` in +`docs/evidence/2026-10-16-identity-outage-recovery/`. +Stored-row continuity is accepted; event completeness and existing-token MFA +are separate and are not claimed. ## Prove restored KeyCape issuer, policy and consumer continuity @@ -882,11 +883,10 @@ material/audit acceptance remains T31/T20; actual MFA remains T19. ```task id: NK-WP-0049-T31 -status: wait +status: done priority: high assignee: codex depends_on: [NK-WP-0049-T13, NK-WP-0049-T30] -blocking_reason: "Await the owner's private age-key run of the prepared T30 executor against the independently retrieved actual bundle; synthetic native proof is complete." state_hub_task_id: "26383841-8076-5c53-bbd1-9db64e32544a" ``` @@ -894,7 +894,12 @@ state_hub_task_id: "26383841-8076-5c53-bbd1-9db64e32544a" key in the hidden helper. This task extracts actual material-readback scope from T19, preserving T19's existing-token MFA acceptance gate and historical identity. -**Unblock:** the same private `run-isolated-privacyidea.sh` run used for T20. +Completed 2026-10-16 at 19:10 UTC in the same actual run as T20. All five +retained token materials were decrypted internally with the original enckey; +an unrelated key could not reproduce any of the five. All 36 manifest hashes, +exact executor/ciphertext/target bindings, isolation and cleanup passed. Safe +receipts are the `actual-isolated-privacyidea-{recovery,review}.json` files +referenced under T20. No retained-factor authentication is claimed. **Done when:** exact ciphertext/source/target/manifest bindings pass; the native provider reads every nonempty encrypted token-key field using the original enckey without exporting material; an unrelated key cannot reproduce that