chore: replace em dashes with hyphens, add no-em-dash rule to CLAUDE.md
Deploy / deploy (push) Successful in 2m47s

This commit is contained in:
mrhid6 committed 2026-09-10 09:18:57 +00:00
1 parent e8455c99fe
commit 7762629634
22 files changed
+126 -122

No files matched your search

+26 -26
View File
@@ -7,16 +7,16 @@ sidebar_label: Backup and restore
`vantagectl` is a separate command-line tool that backs up and restores the
MongoDB database behind a Vantage control plane. It talks to MongoDB directly,
never to the Vantage API, so it works against a control plane that is down,
half-migrated, or gone — exactly the situation a backup tool has to survive.
half-migrated, or gone - exactly the situation a backup tool has to survive.
For the store-level overview — what holds what, and why the database alone is
not a backup — see [Backups](./backups.md). This page covers the tool.
For the store-level overview - what holds what, and why the database alone is
not a backup - see [Backups](./backups.md). This page covers the tool.
:::danger The key comes first
Vantage encrypts SSH private keys, key passphrases, vault secrets, SSO client
secrets and console credentials with `KEY_ENCRYPTION_KEY`. **It is not in your
backup, and it is not recoverable.** A database restored without it is
permanently unreadable — not degraded, not partially readable, unreadable.
permanently unreadable - not degraded, not partially readable, unreadable.
Store it wherever you store the credentials you could not rebuild: a password
manager, a secrets vault outside this control plane, a piece of paper in a
@@ -26,7 +26,7 @@ safe. Anywhere but next to the archive.
## What a backup holds
Every collection in the database, the index definitions each one needs to be
useful again, and a SHA-256 **fingerprint** of `KEY_ENCRYPTION_KEY` — never the
useful again, and a SHA-256 **fingerprint** of `KEY_ENCRYPTION_KEY` - never the
key itself. The fingerprint is what lets a later `restore` or `verify` tell you
that the key you are holding is the wrong one, before it writes a database
nobody can read.
@@ -37,8 +37,8 @@ nobody can read.
true whenever Redis itself restarts.
- **The vulnerability database.** It is re-pulled automatically on next boot.
- **Agent state on managed servers.** Nothing needs re-enrolling: agents
reconnect on their own, because `servers.agent_token_hash` — the thing an
agent authenticates with — is itself in the backup.
reconnect on their own, because `servers.agent_token_hash` - the thing an
agent authenticates with - is itself in the backup.
:::note Pin the version
The image is published on each `vantagectl/v*` release and tagged with that
@@ -80,7 +80,7 @@ backup:
```
`backup.enabled` defaults to `false`, and the chart refuses to render if it is
turned on without both `backup.image` and `backup.pvcName` — a backup needs a
turned on without both `backup.image` and `backup.pvcName` - a backup needs a
known image and somewhere durable to land, and guessing at either is worse than
refusing to start. `backup.exclude` names collections to leave out (recorded in
the archive's manifest, so an archive never claims to be complete when it is
@@ -88,13 +88,13 @@ not), and `backup.successfulJobsHistoryLimit` / `backup.failedJobsHistoryLimit`
/ `backup.resources` behave exactly as they do on any other `CronJob`.
`backup` refuses to run without `KEY_ENCRYPTION_KEY` set in the environment,
unless you pass `--allow-no-key` — for a deployment that genuinely stores no
unless you pass `--allow-no-key` - for a deployment that genuinely stores no
encrypted data. Everywhere else, treat the refusal as the tool doing its job.
## Where to put the archive
`--out -` streams the tarball to stdout instead of writing a file, and every
line of progress output goes to stderr — so piping the archive into something
line of progress output goes to stderr - so piping the archive into something
else is always safe, nothing progress-related lands in the stream.
Into `restic`:
@@ -109,7 +109,7 @@ Into S3:
vantagectl backup --out - | aws s3 cp - s3://my-backups/vantage-$(date +%F).tar.gz
```
An archive is as sensitive as a raw database dump — it carries every SSH key
An archive is as sensitive as a raw database dump - it carries every SSH key
assignment, every secret group, every session-adjacent setting, in a form the
right `KEY_ENCRYPTION_KEY` can decrypt. Whatever you pipe it into should
encrypt it at rest; `vantagectl` itself does not.
@@ -123,23 +123,23 @@ vantagectl verify /backups/vantage-backup-vantage-20260907T020000Z.tar.gz \
Each line of output answers a different question:
- **`Archive`** — every member's checksum still matches; the tarball has not
- **`Archive`** - every member's checksum still matches; the tarball has not
been truncated or corrupted.
- **`Archive key`** / **`Your key`** — the fingerprint stored in the archive
- **`Archive key`** / **`Your key`** - the fingerprint stored in the archive
next to the fingerprint of the `KEY_ENCRYPTION_KEY` in your environment.
- **`Key match`** — whether those two fingerprints agree.
- **`Live probe`** — given `--mongo-uri`, `verify` goes one step further and
- **`Key match`** - whether those two fingerprints agree.
- **`Live probe`** - given `--mongo-uri`, `verify` goes one step further and
decrypts a real ciphertext value from that database with the key you hold.
A fingerprint match proves two archives agree about a key; only the probe
proves the key in your hand actually reads the data.
`verify` exits non-zero the moment anything above is wrong, which is what makes
it worth putting on a schedule — a backup job that "succeeded" last night is
it worth putting on a schedule - a backup job that "succeeded" last night is
not the same claim as a backup that will actually restore.
## Looking inside an archive
`inspect` prints an archive's manifest and touches no database at all — no
`inspect` prints an archive's manifest and touches no database at all - no
`--mongo-uri`, no key. It is what to run against an archive of unknown origin,
before deciding whether it is the one you want:
@@ -173,8 +173,8 @@ collection named in the archive before loading it. `--force` always needs a
second assurance, in one of two forms:
- `--confirm-db NAME`, naming the target exactly. A mismatch is refused. This
works everywhere — on a terminal and in a Kubernetes Job, a CI step or a cron
entry alike — and is the form to script.
works everywhere - on a terminal and in a Kubernetes Job, a CI step or a cron
entry alike - and is the form to script.
- Nothing, on a terminal: `--force` alone prompts you to type the target
database's name back, a deliberate pause before something destructive.
@@ -190,7 +190,7 @@ log lines are still there, joined to freshly restored runs. Dropping them
instead would delete data you never asked to delete.
`restore` also refuses when the archive's key fingerprint does not match the
`KEY_ENCRYPTION_KEY` in your environment — see "When the key is wrong" below.
`KEY_ENCRYPTION_KEY` in your environment - see "When the key is wrong" below.
## The restore drill
@@ -210,7 +210,7 @@ monthly:
```
3. Drop the scratch database. It served its purpose.
The failure this catches is not "the archive is corrupt" — `verify` alone
The failure this catches is not "the archive is corrupt" - `verify` alone
catches that. It is "the archive is fine but nobody can actually stand a
control plane back up from it," which only a real restore proves.
@@ -221,13 +221,13 @@ If `restore` finds the archive's key fingerprint does not match the
`--ignore-key-mismatch` proceeds anyway, but says plainly which collections
will come back with ciphertext nobody can read:
- `keys` — SSH private keys and passphrases
- `secrets` — the vault
- `auth_providers` — OIDC/SSO client secrets
- `console_sessions` — RDP/VNC credentials
- `keys` - SSH private keys and passphrases
- `secrets` - the vault
- `auth_providers` - OIDC/SSO client secrets
- `console_sessions` - RDP/VNC credentials
There is no way to recover that ciphertext afterwards. If you have reached
this point, the right key was lost along with the chance to read those rows —
this point, the right key was lost along with the chance to read those rows -
the fix is to re-enter each of them by hand (re-upload SSH keys, re-save vault
secrets, reconfigure SSO), not to keep searching for a way to decrypt what is
already in the database.
+2 -2
View File
@@ -27,7 +27,7 @@ Store the key somewhere other than the server it protects.
:::info Use `vantagectl`
[**Backup and restore**](./backup-and-restore.md) is the supported way to take
and restore a backup. It writes an archive that carries a fingerprint of
`KEY_ENCRYPTION_KEY` — never the key — so a restore taken with the wrong key
`KEY_ENCRYPTION_KEY` - never the key - so a restore taken with the wrong key
**refuses** rather than silently producing a database whose secrets nobody can
read. It also checksums every archive member before writing anything, and
refuses to restore into a database that already holds data. A plain
@@ -52,7 +52,7 @@ docker compose exec -T mongo mongodump --archive --gzip --db vantage \
:::warning
This archive records nothing about which `KEY_ENCRYPTION_KEY` it was taken
under. Restoring it with the wrong key produces a database that looks intact
and is not — every secret in it is silently unreadable until something tries
and is not - every secret in it is silently unreadable until something tries
to decrypt one.
:::