Skip to content

Back up and restore the cluster

Save a cluster snapshot before a risky change. The archive contains the replicated state: keys, budgets, configuration history, sealed secrets, certificates, and audit heads. Restore it through the admin API without copying a host volume.

Save an archive through the local admin socket:

Terminal window
$ pistra snapshot save -socket /run/pistra/admin.sock backup.snap
saved snapshot at index 10422 term 7 (48213 bytes)

Or over the network with the token pistra login cached:

Terminal window
$ pistra snapshot save -url https://gw.example - | aws s3 cp - s3://backups/pistra-$(date +%F).snap

The archive is a gzipped tar of three files: meta.json with raft’s snapshot metadata, state.bin with the state itself, and SHA256SUMS over both. A truncated download is refused on restore rather than restored in part. GET /admin/v1/cluster/snapshot is the same thing over plain HTTP, with the index and term in X-Pistra-Snapshot-Index and X-Pistra-Snapshot-Term.

Ask the leader. A follower’s state may trail the leader’s by a commit round, and a backup should not carry a caveat about which writes it might lack. A follower answers 409 naming the leader. GET /admin/v1/cluster says which node that is. -stale (the stale query parameter) takes the snapshot from a follower anyway. Use it for a cluster that has no leader to ask, where a backup taken before a recovery is better than none.

Secrets stay sealed. A stored secret is archived as the ciphertext it is stored as, wrapped by the keyring, which is wrapped by the cluster secret. The archive is safe to hold without that secret, and it can only be opened again by a cluster that has it. Restoring into a cluster with a different cluster.secret restores secrets nobody there can read. Providers that reference them fail to build until the secret is what it was, or the values are written again. See rotate the cluster secret for how the keyring can be carried on a key file instead.

Who may. saveClusterSnapshot and restoreClusterSnapshot are both in the write group on the cluster resource, and the first is there on purpose. An archive is every key hash, every sealed secret and every document, so “may read the membership” must not be the grant that lets it leave. Both are recorded in the audit trail as cluster.snapshot.save and cluster.snapshot.restore.

Restore the archive through any cluster node:

Terminal window
$ pistra snapshot restore -socket /run/pistra/admin.sock backup.snap
restored: {"index":10422,"term":7,"node":"pistra-0"}

Any node accepts the archive and forwards it to the leader, where raft consumes it as a snapshot. Every node installs the restored state at once and rebuilds from it, and the state they held before is gone. Take a snapshot first if there is any chance you want it back.

Membership is not restored. The archive carries state, not the list of nodes. The cluster you restore into keeps its own. A restore into a different cluster works for that reason, the reinstalled release with fresh volumes, the replacement fleet on new hosts. An archive also cannot bring back a lost quorum. For that, recover the cluster first, then restore into it if the recovery lost data.

What comes back. The store returns as it was: keys with their hashes and revocations, budgets and usage, sources at their revisions with their history, secrets and the keyring, certificates, suspensions, the reconciliation ledgers. Two things are deliberately dropped on the way in: the archived cluster’s own bookkeeping of which log index its state was at, and where its nodes accepted forwarded writes. Both are facts about the cluster the archive came from, and the one receiving it has its own.

The deployment document afterwards. A node whose deployment document has a version compares it against the restored default source like any other start. A document newer than what was restored is applied on the next restart or reload, and one behind it is reported as behind. See the file is still there.

The image has no shell, but it has pistra, and the chart puts the local socket on every pod:

Terminal window
$ kubectl exec -n pistra-system pistra-0 -- \
pistra snapshot save -socket /run/pistra/admin.sock - > backup.snap
$ kubectl exec -i -n pistra-system pistra-0 -- \
pistra snapshot restore -socket /run/pistra/admin.sock - < backup.snap

pistra-0 is not always the leader. If the save answers 409, use the pod it names, or add -stale. A restore can go to any pod.