Finish AUDIT-WP-0005: walk restore and close T06
Logical dump of live audit_core restored locally in 4.1s; counts and sample triples match the rapp-postgres drill. Retention is platform backup, not an audit-core deletion window. Workplan finished.
This commit is contained in:
parent
f30faec660
commit
c4dbb92a8a
4 changed files with 85 additions and 48 deletions
|
|
@ -142,52 +142,48 @@ behind the read privilege). Watch:
|
|||
|
||||
## Restore
|
||||
|
||||
audit-core declares `custody_class=archive` and `immutable=True` (the
|
||||
append-only trigger). It does **not** declare a retention window shorter
|
||||
than the platform's, because it currently declares none (`retention_days`
|
||||
unset = keep). That is only honest if the platform's backup retention is
|
||||
also unbounded or is an explicit accepted loss.
|
||||
audit-core does **not** expire events (`retention_days` unset). Recovery is
|
||||
bounded by what rapp-postgres can restore, not by an audit-core deletion
|
||||
window. The platform's planned Barman window is 30 days. Production Barman
|
||||
is still fail-closed (no governed off-host target). Do not promise an RPO
|
||||
until that target exists. Local WAL on the node is not an off-host copy.
|
||||
|
||||
As of 2026-08-13, `RAPP-POSTGRES-WP-0002-T06` is `wait`. Production backup
|
||||
is fail-closed until an S3-compatible Barman target exists. The governed
|
||||
Nextcloud logical-dump lane cannot provide WAL archiving or PITR. Do not
|
||||
claim an RPO/RTO for audit-core until those drills have been recorded in
|
||||
rapp-postgres.
|
||||
Physical restore is instance-wide. A consumer-only restore is a logical
|
||||
export of `audit_core` from a scratch physical restore, then a controlled
|
||||
import. Never recover in place. Procedure: `rapp-postgres/docs/restore.md`.
|
||||
|
||||
When the platform restore path is open, the audit-core walk is:
|
||||
Walked 2026-08-13:
|
||||
|
||||
1. Restore `platform-pg` to a scratch cluster (`platform-pg-restore-full` or
|
||||
PITR). Never recover in place.
|
||||
2. Physical restore is instance-wide. A single-consumer restore is a logical
|
||||
dump of `audit_core` from the scratch cluster, then a controlled import.
|
||||
3. Verify: event counts, a sample of `event_id`/`payload_hash`/`accepted_at`
|
||||
triples, and that the append-only trigger is still installed
|
||||
(`SELECT tgname FROM pg_trigger WHERE tgname = 'events_append_only'`).
|
||||
4. Record elapsed time. That number is what this service can promise.
|
||||
| Path | Evidence | Elapsed | Result |
|
||||
| --- | --- | --- | --- |
|
||||
| Platform full restore + PITR of live `audit_core` (21 events) | `rapp-postgres/docs/evidence/backup-restore-20260813T111651Z-remote.json` | 51.0s / 52.5s | triples + `events_append_only` |
|
||||
| Platform logical single-consumer export/import | same | 3.5s | 21 events |
|
||||
| audit-core logical dump of live `audit_core` → local PG 16 | `evidence/restore-walk-20260813T121200Z.json` | 4.1s | 21/3/1 counts, 5 triples, trigger present |
|
||||
|
||||
Until that walk exists, a workstation-side logical dump of an empty
|
||||
`audit_core` is not evidence of recovery.
|
||||
Verify after any restore:
|
||||
|
||||
```sql
|
||||
SELECT count(*) FROM audit_core.events;
|
||||
SELECT event_id, payload_hash, accepted_at FROM audit_core.events
|
||||
WHERE event_id IN (/* sample from pre-restore */);
|
||||
SELECT tgname FROM pg_trigger WHERE tgname = 'events_append_only';
|
||||
```
|
||||
|
||||
## Rollback
|
||||
|
||||
The Deployment annotation `audit-core.railiance.io/rollback-note` is the
|
||||
source of truth. Migrations 0001-0004 are additive; `kubectl -n audit-core
|
||||
source of truth. Migrations 0001-0005 are additive; `kubectl -n audit-core
|
||||
rollout undo deploy/audit-core` returns to the previous digest and an older
|
||||
image runs against the newer schema. A future migration that drops or
|
||||
narrows a column must replace that note before release.
|
||||
|
||||
## Deploy order
|
||||
|
||||
1. Image published, digest pinned in `deploy/audit-core.yaml` and
|
||||
`deploy/migrate-job.yaml`.
|
||||
2. Attended `scripts/openbao-eso-token-apply.sh`.
|
||||
3. `bao kv put platform/workloads/audit-core/senders senders.json=@file`
|
||||
from a mode-0600 file; shred the file.
|
||||
4. Apply namespace (carries `railiance.io/postgres-client: platform-pg`),
|
||||
NetworkPolicies, ClusterSecretStore, VaultDynamicSecrets, ExternalSecrets.
|
||||
5. Wait until Secrets `audit-core-database`, `audit-core-database-migrate`,
|
||||
and `audit-core-senders` exist.
|
||||
6. Apply and wait for Job `audit-core-migrate`.
|
||||
7. Apply the Deployment. Confirm `/readyz` reports `custody_class=archive`.
|
||||
8. Run `MODE=remote BASE_URL=… make failure-matrix` and hand the JSON to
|
||||
NK-WP-0024.
|
||||
1. Image published and digest-pinned.
|
||||
2. Namespace (label `railiance.io/postgres-client: platform-pg`),
|
||||
NetworkPolicies, ClusterSecretStores, ExternalSecrets.
|
||||
3. Sender registry is Secret `audit-core-senders` (in-cluster mint).
|
||||
Database leases come from `openbao-audit-core-database`.
|
||||
4. Job `audit-core-migrate` with `AUDIT_CORE_MIGRATE_ROLE=audit_core_migrate`.
|
||||
5. Deployment. `/readyz` must report `custody_class=archive`.
|
||||
6. In-pod `MODE=remote DISRUPT=0` failure matrix. Evidence goes to NK-WP-0024.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue