Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a13eab-1e6a-7b33-9c37-372e90ada3a2
101 lines
6.1 KiB
Markdown
101 lines
6.1 KiB
Markdown
# Bootstrap recovery transport check
|
|
|
|
Owner work: NK-WP-0049. Follow
|
|
[the exact recovery ceremony](../../docs/bootstrap-recovery-ceremony.md).
|
|
|
|
For an identity/custody outage, start with the
|
|
[Storage Share disaster recovery guide](../../docs/disaster-recovery-storage-share.md).
|
|
`retrieve-identity-offline.py` performs fixed-provider ciphertext retrieval from
|
|
privately entered independent provider access, without OpenBao/SSO. Its source
|
|
receipt pins the object, strong ETag, size and digest; failed downloads are removed.
|
|
`recovery-kit.py` builds an allowlisted standalone tools ZIP and can publish only
|
|
three new versioned guide/ZIP/checksum files beside the backups with exact
|
|
readback. `run-offline-recovery.sh` is the owner's private two-prompt handoff for
|
|
publication, outage-path retrieval and the existing archive recovery check.
|
|
Run secret prompts in the owner's own terminal, never an agent-captured PTY.
|
|
Actual owner publication/readback and outage-path archive recovery passed on
|
|
2026-10-16; see the [published location and receipts](../../docs/storage-share-recovery-publication.md).
|
|
Service restore admission remains in the
|
|
[isolated restore packet](../../docs/identity-service-restore-packet.md).
|
|
|
|
The first native-service stage is `run-isolated-lldap.sh USER TRANSFER_RECEIPT`.
|
|
It preflights the exact local Docker engine/images before asking privately for
|
|
the age key and backup-era existing-user password. `isolated-lldap.py` validates
|
|
the encrypted archive, restores original directory/key material only into
|
|
network-none/read-only/tmpfs containers, proves native LDAP bind and explicit
|
|
invalid-credential denial, compares durable identity rows and removes its owned
|
|
containers/plaintext. It uses no live Kubernetes/OpenBao endpoint or provider
|
|
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 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
|
|
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
|
|
an exact required-file list, unrelated wrong-key refusal, safe isolated file
|
|
publication/readback and staging removal. No service or cluster is contacted.
|
|
|
|
It refuses links, special/duplicate/unreviewed entries, oversized content, private
|
|
age keys in the bundle, wrong digest/recipient and existing receipt destinations.
|
|
Only a closed metadata receipt leaves the process. Current service credentials,
|
|
independent/off-host custody, production acceptance and revocation remain separate
|
|
owner evidence. Same-UID/process-memory isolation and forensic secure erasure are
|
|
not provided by this local checker.
|
|
|
|
Tests use real age encryption/decryption with disposable keys and malicious
|
|
archive fixtures, never production credentials:
|
|
|
|
```bash
|
|
python3 -m pytest -q tests/test_bootstrap_recovery_transport.py
|
|
```
|
|
|
|
|
|
`inventory-storage-share.py` is a silent read-only child of the existing
|
|
attended Platform Backup-account procedure. It checks the caller's OIDC/admin
|
|
scope, reuses the owner custody accessor, and exports only bounded DAV names and
|
|
sizes. Warden revokes and cleans up the session. It never reads an age key or
|
|
object content and contains provider errors/redirects/proxies.
|
|
|
|
`inventory-scaleway.py` lists bounded metadata in the fixed backup bucket/prefix
|
|
using the existing scoped runtime delivery and pinned primary cluster. It uses
|
|
neither the bootstrap API key nor object GET/write/delete operations. Run through
|
|
the already admitted caller with cached boto3 1.40.18; it emits only its safe
|
|
receipt. Both inventories explicitly state their bounds and cannot prove asset
|
|
absence outside them, ciphertext integrity, decryption or native recovery.
|
|
|
|
`fetch-privacyidea-backup.py` retrieves only the fixed reviewed PI ciphertext
|
|
under the same attended Platform Backup-account procedure. Strong ETag binding,
|
|
exact length, digest and private no-overwrite output are required. It reads no
|
|
age key. `check-privacyidea-database.py` then runs through temporary human custody,
|
|
checks the transfer lineage/digest and recipient, tests wrong-key refusal and
|
|
restores the decrypted custom-format dump into pinned local PostgreSQL with no
|
|
network, ports or host data mounts. Only three fixed table counts are exported.
|
|
It removes the disposable database and plaintext and records cleanup. It does
|
|
not prove token decryption, audit signing continuity or full identity recovery.
|
|
See the exact prepared command in the ceremony, rather than inventing new inputs.
|
|
|
|
```bash
|
|
NK49_RUN_DISPOSABLE_POSTGRES_TEST=1 python3 -m pytest -q \
|
|
tests/test_privacyidea_offhost_recovery.py \
|
|
tests/test_storage_share_inventory.py tests/test_scaleway_backup_inventory.py
|
|
```
|
|
|
|
`identity-backup-profile.json` prepares missing full service coverage and names
|
|
the exact current workload/PVC/credential dependencies, proposed provider paths
|
|
and remaining implementation/admission gates. It is a proposal, not a new live
|
|
publisher grant. `prepare-identity-coverage.py --receipt NEW_PATH` verifies the
|
|
primary cluster and current deployment/PVC/reference bindings using metadata
|
|
only. It refuses replacement resources, unobserved/unready deployments and new
|
|
unreviewed references. It has no Secret-data, pod-exec, mutation or upload route.
|
|
Its receipt says `prepared_not_admitted`; it cannot prove a backup exists.
|