Accept a remote key for restore and verify, and document it (closes #124)
A machine restoring after the original is gone has no local index and cannot know a snapshot's human ID; snapshot list shows such snapshots only by their remote key, but restore and verify accepted only the human ID, so recovery could not be done as documented. Restore and verify now also accept a remote key, or an unambiguous leading part of it as snapshot list prints it, resolved against the store's metadata listing. Human IDs are never pure hex, which tells the two forms apart. Deep verify reads the single snapshot in the downloaded per-snapshot database. A new README section walks the recovery end to end; a test backs up, then lists, restores and deep-verifies with an empty index, another hostname and no age_recipients. model: claude-opus-4-8 (implementation, review); claude-fable-5-1 (merge)
This commit was merged in pull request #147.
This commit is contained in:
@@ -84,6 +84,57 @@ VAULTIK_AGE_SECRET_KEY='AGE-SECRET-KEY-...' vaultik snapshot restore <snapshot-i
|
||||
# 0 3 * * * vaultik snapshot create --cron --prune --keep-newer-than 4w
|
||||
```
|
||||
|
||||
## restoring on another machine
|
||||
|
||||
Restoring on a host that never ran the backup — a replacement machine
|
||||
after the original is gone — is the case vaultik is built for. That host
|
||||
needs only three things: the `vaultik` binary, the age **private** key,
|
||||
and the storage credentials for the destination. It does **not** need the
|
||||
local index, the original config file, or the original hostname.
|
||||
|
||||
```sh
|
||||
# install
|
||||
go install sneak.berlin/go/vaultik/cmd/vaultik@latest
|
||||
|
||||
# create a config and point it at the ORIGINAL backup destination
|
||||
vaultik config init
|
||||
vaultik config set storage_url "s3://bucket/prefix?endpoint=https://s3.example.com"
|
||||
vaultik config set s3.access_key_id "..."
|
||||
vaultik config set s3.secret_access_key "..."
|
||||
|
||||
# see what is on the destination store
|
||||
vaultik snapshot list
|
||||
```
|
||||
|
||||
`snapshot list` reads the destination store without the private key. A
|
||||
snapshot that is not in this host's (empty) local index is shown as
|
||||
remote-only: its row is identified by `<remote only:...>` rather than by
|
||||
a `hostname_name_timestamp` name, because the name lives only in the
|
||||
local index and the encrypted database and cannot be recovered from the
|
||||
store. Its timestamp and compressed size are real. (See the `snapshot
|
||||
list` description under [command details](#command-details) for the full
|
||||
explanation.)
|
||||
|
||||
Use that remote key — the hex printed inside `<remote only:...>`, or the
|
||||
full `remote_key` from `snapshot list --json` — to restore and verify:
|
||||
|
||||
```sh
|
||||
# restore everything to /tmp/restored, then check every restored file's
|
||||
# chunk hashes
|
||||
VAULTIK_AGE_SECRET_KEY='AGE-SECRET-KEY-...' \
|
||||
vaultik snapshot restore --verify <remote-key> /tmp/restored
|
||||
|
||||
# optionally, deep-verify the snapshot against the store (downloads and
|
||||
# cryptographically checks every blob)
|
||||
VAULTIK_AGE_SECRET_KEY='AGE-SECRET-KEY-...' \
|
||||
vaultik snapshot verify --deep <remote-key>
|
||||
```
|
||||
|
||||
`age_recipients` (the public key) is not needed to restore — only the
|
||||
private key in `VAULTIK_AGE_SECRET_KEY`. Both the abbreviated key printed
|
||||
in the table and the full 64-character key from `--json` are accepted; a
|
||||
leading part of the key is enough as long as it is unambiguous.
|
||||
|
||||
---
|
||||
|
||||
## cli
|
||||
@@ -245,6 +296,8 @@ local index alone, and still exits zero.
|
||||
* Default (shallow): checks that all blobs referenced in the manifest exist in storage
|
||||
* `--deep`: Downloads and decrypts each blob, verifies chunk hashes against the
|
||||
encrypted metadata database
|
||||
* Accepts the same identifiers as `snapshot restore`: a snapshot ID, or a
|
||||
remote-only snapshot's remote key (or an unambiguous leading part of it)
|
||||
* `--json`: Output results as JSON
|
||||
|
||||
**`snapshot purge`**: Remove old snapshots based on criteria. Retention is
|
||||
@@ -275,6 +328,10 @@ on the destination in one go, use `vaultik remote nuke --force`.
|
||||
|
||||
**`snapshot restore`**: Restore files from a backup snapshot.
|
||||
* Requires `VAULTIK_AGE_SECRET_KEY` environment variable
|
||||
* Accepts a snapshot ID, or — for a snapshot only on the destination
|
||||
store — its remote key (or an unambiguous leading part of it) as shown
|
||||
by `snapshot list`. See
|
||||
[restoring on another machine](#restoring-on-another-machine).
|
||||
* Optional path arguments to restore specific files/directories (default: all)
|
||||
* Preserves file permissions, timestamps, ownership (ownership requires root),
|
||||
symlinks, and empty directories
|
||||
@@ -529,10 +586,6 @@ priority.
|
||||
|
||||
### infrastructure
|
||||
|
||||
* **Cross-machine restore documentation.** The "restore from
|
||||
another host" workflow works but isn't documented as a
|
||||
first-class operation in this README. Worth a dedicated section
|
||||
once it's settled.
|
||||
* **Cross-version schema upgrades.** There is no upgrade path between
|
||||
released versions — pre-1.0 schema changes are handled by `vaultik
|
||||
database delete` plus a full re-scan (see
|
||||
|
||||
Reference in New Issue
Block a user