Using a separate signing key per device Jump to heading
The instinct when setting up signing on a second machine is to copy the key from the first. It works immediately and it doubles the exposure: the key now lives in two places, and losing either device means revoking the key everywhere, including on the machine you still have. Per-device keys invert that. Each laptop, workstation, cloud development environment and hardware token generates its own key, which never leaves it. Losing a device costs exactly one revocation. The trust file grows by a line per device, and audits can tell which machine produced a commit. This page sets that up and keeps it manageable, as part of protecting and rotating signing keys.
When to use this approach Jump to heading
- Engineers sign from more than one machine — a laptop and a workstation, or a laptop and a cloud development environment.
- You use SSH signing, where adding another key is a line in a file rather than a ceremony.
- You want a lost or decommissioned device to be a non-event for signing.
- You would like audits to show which device made a commit, not just which person.
- For GPG, the equivalent is one signing subkey per device under a shared primary, described in setting up GPG commit signing with subkeys.
Step 1 — Generate a key on each device, with a descriptive comment Jump to heading
Generate on the device itself. The comment is how you will recognise the key in a forge’s key list and in the trust file a year from now, so make it say what and where.
# Run on each device
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_signing \
-C "signing:$(whoami)@$(hostname -s):$(date +%Y-%m)"
git config --global user.signingKey ~/.ssh/id_ed25519_signing.pub
git config --global gpg.format ssh
git config --global commit.gpgSign true Step 2 — Register each key with the forge under a clear title Jump to heading
Each key is registered as a signing key with a title that matches its comment. Forges allow many signing keys per account.
gh ssh-key add ~/.ssh/id_ed25519_signing.pub --type signing \
--title "signing $(hostname -s) $(date +%Y-%m)"
gh api /user/ssh_signing_keys --jq '.[] | "\(.id)\t\(.title)\t\(.created_at[:10])"' # Verification: a commit from this device shows as verified on the forge
git commit --allow-empty -m "device key test" && git push origin HEAD:refs/heads/device-key-test
gh api "repos/$OWNER/$REPO/commits/$(git rev-parse HEAD)" --jq '.commit.verification.verified' Step 3 — Add every device key to the trust file Jump to heading
In the team’s allowed signers file, one person gets one line per device key, all with the same principal. If the file is generated from the forge’s API, this happens automatically because the generator fetches every registered signing key.
[email protected] namespaces="git" ssh-ed25519 AAAA...laptop signing:alice@lt-0412:2026-10
[email protected] namespaces="git" ssh-ed25519 AAAA...ws signing:alice@ws-0098:2026-03
[email protected] namespaces="git" [email protected] AAAA...token signing:alice@token:2026-01 Step 4 — Identify which device signed a commit Jump to heading
Git can print the key fingerprint used for a signature. Matching that against registered keys tells you the device, which is useful when investigating a suspicious commit or confirming a lost laptop was not used after it went missing.
# Fingerprint of the key that signed each recent commit
git log -20 --format='%h %G? %GF %GS'
# Map fingerprints to device comments using the trust file
while read -r principal opts keytype key comment; do
fp=$(printf '%s %s\n' "$keytype" "$key" | ssh-keygen -lf - | awk '{print $2}')
echo "$fp $comment"
done < allowed_signers Step 5 — Retire a device’s key when the device goes Jump to heading
When a device is lost, stolen or decommissioned, close its key in three places: the forge account, the trust file, and the device itself if you still have it.
# 1. Forge: remove the signing key by its ID
gh api -X DELETE "/user/ssh_signing_keys/$KEY_ID"
# 2. Trust file: close the window rather than deleting the line, so history still verifies
# [email protected] namespaces="git",valid-before="20261002" ssh-ed25519 AAAA...laptop
# 3. Device, if recovered: destroy the key
shred -u ~/.ssh/id_ed25519_signing ~/.ssh/id_ed25519_signing.pub ⚠️ SAFETY WARNING: If the device was lost rather than retired, set
valid-beforeto the time it went missing, not the time you noticed. Commits signed between those two moments may be forgeries and should be reviewed. Pick the earliest plausible time; a too-early date only forces a few legitimate commits to be re-signed, while a too-late one trusts a stolen key.
Validation checklist Jump to heading
Frequently Asked Questions Jump to heading
Does this make the trust file unmanageable? Jump to heading
It roughly doubles or triples its length, which is still small — a hundred-person team with three devices each has three hundred lines. Generating the file from the forge API keeps it accurate without anyone editing it by hand.
What about cloud development environments that are recreated often? Jump to heading
Either generate a key per environment and register it automatically on creation, or — usually better — have the environment forward signing requests to the agent on the engineer’s laptop. Forwarding means no key ever lives in the ephemeral environment.
Is a hardware token one device or many? Jump to heading
One. A token’s key is tied to that token. If you carry two tokens, each has its own key and its own trust-file line.
Related Jump to heading
- Protecting & Rotating Signing Keys — the parent topic.
- Keeping SSH Signing Keys in an OS Keychain Agent — protecting each device’s key at rest.
- Rotating a Compromised Commit-Signing Key — the full runbook when loss means compromise.
- Backing Up Signing Keys Without Creating a Leak — why per-device keys need no backup.