Backup and restore
Everything the operator knows lives in PostgreSQL and in cluster resources. Back those up and an installation can be rebuilt; there is no hidden state anywhere else.
What to back up
| What | Where | If you lose it |
|---|---|---|
| The database | The bundled PostgreSQL's volume, or the external database you pointed externalDsnExistingSecret at | Findings, decisions, exceptions, audit log, evidence archive, users and the licence certificate are gone. This is the backup that matters. |
| Policies | ImageSecurityPolicy resources — in the cluster, and ideally in git already | Re-apply from your repository; the chart reseeds a default if none exists. |
| The session key | Secret attestkeep-session (unless you supplied api.session.existingSecret) | Everyone is signed out and signs in again. Nothing else. |
The webhook's serving certificate is not on the list: the operator reissues it and republishes the CA bundle on its own. The activation key is not either — reinstalling into the same cluster produces the same fingerprint, so the existing licence slot is simply picked up again at activation, as Licensing describes.
Backing up the bundled PostgreSQL
If you brought your own database, your existing backup regime already covers it and this section is not for you. The bundled database is a single-replica StatefulSet named attestkeep-postgresql, and a plain SQL dump is the portable answer:
kubectl -n attestkeep exec statefulset/attestkeep-postgresql -- \
sh -c 'pg_dump -U "$POSTGRES_USER" "$POSTGRES_DB"' > attestkeep.sql
Schedule it with whatever already runs your cron jobs, and store the file with your other backups. A volume snapshot of the PVC works too, if your storage class offers one — the dump is simply the answer that restores anywhere, including into a different storage class or a different cluster.
Restoring
Install the chart, stop the operator so nothing writes or migrates mid-restore, load the dump, start it again:
kubectl -n attestkeep scale deploy/attestkeep deploy/attestkeep-scanner --replicas=0
kubectl -n attestkeep exec -i statefulset/attestkeep-postgresql -- \
sh -c 'psql -U "$POSTGRES_USER" -d postgres -c \
"DROP DATABASE \"$POSTGRES_DB\" WITH (FORCE); CREATE DATABASE \"$POSTGRES_DB\" OWNER \"$POSTGRES_USER\""'
kubectl -n attestkeep exec -i statefulset/attestkeep-postgresql -- \
sh -c 'psql -q -U "$POSTGRES_USER" "$POSTGRES_DB"' < attestkeep.sql
kubectl -n attestkeep scale deploy/attestkeep --replicas=2
kubectl -n attestkeep scale deploy/attestkeep-scanner --replicas=1
Restoring a dump into the same or a newer operator version is supported: migrations are recorded in the dump, and a newer operator applies only what the dump does not already carry. Restoring a newer dump into an older operator is not — migrations move forward only, which is the same rule Upgrade states for rollbacks.
What a restore means for your evidence
Everything recorded after the dump was taken is gone, and the evidence package does not pretend otherwise. The operator stamps a heartbeat as it runs; on the first pass after a restore it finds the last stamp at dump age and records the whole span since as a window in which the control was not operating. A period report covering it shows the gap, exactly as it shows any other outage.
That is the honest cost of restoring from backup: you get your history back up to the dump, and the document says plainly where history is missing. A restore that could silently paper over the lost window would be a way to rewrite the record, and this product's evidence would be worth less for having it.