Generate the rotation-authority key¶
The rotation-authority key is your break-glass key. It's never used in normal operation. It exists so that β if the primary signing key is ever lost or compromised β you can authorise a new signing key without breaking the chain of trust for installs that already have your tool.
This is a 5-minute one-off operation. Do it now, store the private half offline, and forget about it (until you don't have to).
Prerequisites¶
gtbinstalled.- A trusted workstation. Anywhere is fine β the private key is
encrypted and the operator's workstation is the only place it
briefly exists in memory. No
gpginstall, noopenssl, no external tools. - A safe place to put the private half. A home safe with an encrypted USB stick and a printed paper backup is the standard pattern.
The command¶
gtb keys generate \
--algorithm ed25519 \
--name "MyTool Rotation Authority" \
--email [email protected] \
--output rotation-authority.asc
Two files appear in the current directory:
rotation-authority.ascβ the armored OpenPGP public half. Safe to commit. You'll embed this in your tool'sinternal/trustkeys/keys/and publish it alongside your signing key via WKD.rotation-authority.priv.ascβ the armored OpenPGP secret half. Compatible withgpg --importfor inspection. This file is what needs to go offline.
No silent overwrites
gtb keys generate refuses to overwrite an existing key file (public or
private). A private key on disk is irreplaceable, so the default is to
fail rather than clobber it in place. Pass --force only when you
deliberately want to overwrite an existing key. The private half is always
written with 0600 permissions.
A successful run logs:
INFO Generated OpenPGP keypair algorithm=ed25519 public_output=rotation-authority.asc
private_output=rotation-authority.priv.asc
creation_time=2026-06-08T12:00:00Z
fingerprint=A1B2C3D4...
WARN Move the private-half file to offline storage now. private_output=rotation-authority.priv.asc
Move the private half offline¶
Take the recommended belt-and-braces approach β two storage locations to survive a single-medium failure:
1. Encrypted USB stick (covers USB bit-rot via the paper backup)¶
# Plug in a USB stick. Find its device name via `lsblk`. CAREFULLY.
# This wipes the device.
sudo cryptsetup luksFormat /dev/sdX # set a strong passphrase
sudo cryptsetup luksOpen /dev/sdX rotation-usb
sudo mkfs.ext4 /dev/mapper/rotation-usb
sudo mkdir -p /mnt/rotation
sudo mount /dev/mapper/rotation-usb /mnt/rotation
# Copy. The .asc file is small β milliseconds.
sudo cp rotation-authority.priv.asc /mnt/rotation/
# Tidy up.
sudo umount /mnt/rotation
sudo cryptsetup luksClose rotation-usb
Label the USB stick with the fingerprint (top 8 hex chars are enough) so future-you can match the stick to the right key without unlocking it first.
2. Paper backup (covers USB bit-rot)¶
Install paperkey once on your operating system (Debian/Ubuntu:
apt install paperkey; macOS: brew install paperkey). It also
needs gpg available, only to strip ASCII armor from the input β
no keyring is created.
# paperkey only accepts binary OpenPGP packets, not ASCII armor, so
# dearmor on the fly. No intermediate file touches disk.
gpg --dearmor < rotation-authority.priv.asc \
| paperkey --output rotation-authority.paperkey.txt
lpr rotation-authority.paperkey.txt # or any printer; print it on paper
shred -u rotation-authority.paperkey.txt # wipe the temporary file
Tape the printout into a notebook or laminate it into a sleeve. Put it next to the USB stick in the safe. Write the fingerprint on the outside of the sleeve too.
3. Wipe the local copy¶
The file is now in two physically-redundant places. If anyone asks, the answer to "where's the rotation key" should be "in the safe", not "let me grep my home directory".
What to put in your password manager¶
Two entries, both clearly labelled "DO NOT USE except for key rotation":
- The LUKS passphrase for the encrypted USB.
- The fingerprint of the rotation-authority key.
Both are needed to recover. Don't put them in the same vault folder as your everyday secrets β clutter is the enemy of "I know what this is when I haven't looked at it in 3 years".
Test the paper backup once, before you walk away¶
It's much easier to discover that your printer eats a stripe of pixels
now than 18 months from now when you actually need to recover.
With a different offline machine (or a fresh $GNUPGHOME on the
same one):
mkdir -p /tmp/test-recovery
export GNUPGHOME=/tmp/test-recovery
chmod 700 $GNUPGHOME
# Type the paperkey output back in by hand. Yes, all of it.
cat > retyped.txt
# ... type the printed bytes; Ctrl-D when done ...
# paperkey --pubring also wants binary, so dearmor the public half
# the same way as during backup.
gpg --dearmor < rotation-authority.asc > rotation-authority.pub.gpg
paperkey --pubring rotation-authority.pub.gpg --secrets retyped.txt | gpg --import
shred -u rotation-authority.pub.gpg retyped.txt
# Compare:
gpg --list-secret-keys --keyid-format long
# Should show the same fingerprint as `rotation-authority.asc`.
If the fingerprints match, the paper backup is recoverable. Wipe
/tmp/test-recovery and forget it ever happened.
If the fingerprints don't match, your printer or your typing introduced an error. Reprint and retest before declaring the paper backup good.
Embed the public half¶
Drop rotation-authority.asc into your tool's internal/trustkeys/keys/
directory alongside the signing key. Go's //go:embed all:keys
directive picks it up; it ships baked into every binary.
mytool/
βββ internal/
βββ trustkeys/
βββ trustkeys.go β uses //go:embed all:keys
βββ keys/
βββ release.asc β the signing key
βββ rotation-authority.asc β this file
Publish via WKD too¶
The verifier cross-checks the embedded key against the WKD-served copy, so the rotation key needs to be at the WKD endpoint as well. See the phase2-signing-prep doc for the Cloudflare Pages Direct Upload recipe.
What happens when you need to use it¶
(Hopefully never. But: signing-key compromise, lost KMS access, deliberate algorithm migration.)
The rotation flow itself is operational and lives outside this
how-to. The short version: you sign a rotate-keys.json manifest
with the rotation-authority key naming the new signing key, ship it
alongside your next release, and existing installs adopt the new key
on next update. Detailed runbook: TBD (Phase 4 of the parent
remote-update-checksum-verification
spec).
The whole point of generating the rotation key now is that it exists before you need it. The runbook can come later.
See also¶
- Mint the signing key β the everyday signing key flow, paired with this rotation key in the trust set.
- Release-binary signing concept β why two keys, what each protects against.