Key management
You keep the private half. Loss is unrecoverable, deliberately.
View as MarkdownEverything in this section rests on one key pair. You give us the public half; the private half is yours alone, and we have no copy, no escrow and no override.
If you lose the private key, your backups are unreadable, by you and by us. There is no support request that recovers them. This is not a policy we could waive: there is no key on our side to waive it with.
That is the cost of the guarantee on the encryption page. It is worth paying, and it is worth taking seriously on the day you set it up rather than later.
Installing gpg
You need an OpenPGP implementation on the machine that generates the key and on any machine that will restore.
| Platform | Install |
|---|---|
| Debian/Ubuntu | sudo apt install gnupg |
| Fedora/RHEL | sudo dnf install gnupg2 |
| Alpine | apk add gnupg |
| macOS | brew install gnupg, or GPG Suite for a GUI |
| Windows | winget install GnuPG.Gpg4win, or Gpg4win |
Verify it works before you rely on it:
gpg --versionOn Windows, run the commands below in PowerShell or in the Git Bash shell that ships with
Git for Windows. The gpg commands themselves are identical on all three platforms; only the
surrounding shell syntax and paths differ, and both are noted where they matter.
Generating a key
The same command everywhere:
gpg --quick-generate-key "backups@example.com" default default never| Argument | Meaning |
|---|---|
"backups@example.com" | The user ID. An address you control, or any label |
default (algorithm) | The implementation's current recommendation |
default (usage) | Sign and encrypt |
never | No expiry |
Use never for a backup key. An expired key still decrypts existing artifacts, but gpg
refuses to encrypt to it, so every run starts failing on a date nobody wrote down. If your
policy requires expiry, put a calendar reminder well before it and
rotate deliberately.
You will be prompted for a passphrase. Use one, and store it in your password manager alongside a note saying which key it belongs to.
Export the public half to give to us:
gpg --armor --export backups@example.com > prod-public.ascOn Windows PowerShell, redirect with encoding control so the file is plain ASCII:
gpg --armor --export backups@example.com | Out-File -Encoding ascii prod-public.ascThat file is what goes into a backup definition or a worker config. It is not secret.
Backing up the private half
Do this immediately, before the first backup runs. A key that exists only in one
~/.gnupg is a single point of failure that will not announce itself.
gpg --armor --export-secret-keys backups@example.com > prod-private.ascgpg --armor --export-secret-keys backups@example.com | Out-File -Encoding ascii prod-private.ascThat file plus its passphrase is the whole of your recovery capability. Treat it accordingly:
| Where the key lives by default | Path |
|---|---|
| Linux, macOS | ~/.gnupg |
| Windows | %APPDATA%\gnupg |
Lock down the directory on Unix-like systems, which gpg mostly does for you:
chmod 700 ~/.gnupg
chmod 600 ~/.gnupg/*On Windows, the folder inherits your user profile's ACL. Confirm no other principal has read access if the machine is shared.
Where to keep it
The rule is one sentence: the private key must not share fate with the systems it protects.
| Good | Why |
|---|---|
| A password manager with attachments (1Password, Bitwarden) | Encrypted, replicated, already in your recovery process |
| A hardware token (YubiKey) | The key cannot be copied off it |
| Printed and in a safe | Survives every digital failure |
| An offline drive in a different building | Survives the site |
| Bad | Why |
|---|---|
| On the database server | The thing you are backing up |
| In the repo, or in the worker's config directory | Alongside the ciphertext |
| Only on one laptop | The laptop is the single point of failure |
| Only in the cloud account being backed up | Shares fate by definition |
At least two people, or two places. A key only one person can reach is an availability risk dressed as a security control. If that person is unreachable during the incident, the backups are gone in every way that matters.
Restoring on another machine
The point of the backup copy is that a restore works somewhere else. Import it:
gpg --import prod-private.asc
gpg --list-secret-keysOr hand the key to sctl directly, without importing it into your keyring at all:
sctl restore file <artifact-id> --path ./restored.tar --key ./prod-private.asc--key imports into a temporary keyring that is deleted when the command exits, which is the
right choice on a machine you do not own.
Which key opens which artifact
Every artifact records the fingerprint of the key it was encrypted to.
sctl artifact get <artifact-id> # shows Key
gpg --list-packets artifact | head -3 # shows keyid, with no account
gpg --list-secret-keys --keyid-format LONGMatch the ID from the middle command against the last. That is the whole of "do I have the right key", and it works offline.
Rotating a key
Rotation is additive. Nothing re-encrypts.
- Generate the new key pair, and back up the new private half.
- Set the new public key on the backup, or on the worker for a local backup.
- Future artifacts use the new key. Existing artifacts still need the old one.
- Keep the old private key until the last artifact carrying its ID has expired.
sctl artifact list --backup $BACKUP_IDNever destroy an old private key while artifacts encrypted to it still exist. Retention tells you exactly when that is safe: once no artifact lists the old key ID, it is dead weight. Until then, destroying it destroys those backups.
Rotate when someone with access to the key leaves, when you suspect exposure, or on whatever schedule your policy sets. There is no cost to rotating other than keeping one more key around for a retention window.
If the key is compromised
Assume every artifact encrypted to it is readable by whoever has it. You cannot revoke that, because the artifacts are already encrypted and the attacker may already hold copies.
What you can do, in order:
- Rotate the key so future artifacts are protected.
- Rotate the source credentials the backups used, since anyone reading an artifact reads the data those credentials protect.
- Check the audit log for
artifact.download_url_issuedentries you cannot account for. That is the only record of a copy leaving. - Consider expiring the old artifacts early, if your retention policy and locks allow it.
Passphrases and automation
A passphrase protects the key at rest. It also means an unattended restore prompts for input.
- For restores, that is fine: a human is present.
- For encryption, no passphrase is needed at all. Only the public key is used, and it is not secret.
So the worker never needs your passphrase, and you should never put it in a config file. There is no configuration option that takes one, deliberately.