✍️ Git commit signing with 1Password¶
Commits and tags are signed with an SSH key held by 1Password. The private key never leaves the vault: git delegates the signing operation to 1Password's own signer binary, which prompts you to approve it.
This is the alternative to the hardware-token flow in
yubikey.md — useYubiKey = true takes precedence for signing
new commits and tags. Signature verification trusts both sets of public keys.
Setup¶
The repository owner's public keys ship as the defaults for gitSigningKey, so
signing switches itself on as soon as a 1Password signer binary is present —
nothing to configure. Which default applies depends on the machine:
| Machine | Default key |
|---|---|
Entra ID tenant ending in Microsoft (isWork = true) |
work key |
| Everything else | personal key (published) |
isWork comes from dsregcmd /status on Windows and WSL; elsewhere it is
false, so the personal key applies. A gitSigningKey left over in your local
chezmoi config from an earlier chezmoi init is re-evaluated whenever it still
equals one of the shipped defaults, so a machine never gets pinned to the wrong
one — only a key of your own is treated as an override.
Using your own key instead:
- In the 1Password app, open the SSH key item.
- Choose ⋮ → Configure Commit Signing. On Windows, tick Configure for Windows Subsystem for Linux (WSL) if you want the WSL variant.
- Select Copy Snippet and take the public key from it.
- Put that key in your local chezmoi config, which overrides the default:
- Run
chezmoi apply.
That renders user.signingkey, points gpg.ssh.program at the right signer,
turns on commit.gpgsign / tag.gpgsign, and adds the key to
~/.config/git/allowed_signers so your own commits verify locally. A public
key is not a secret, so keeping it in the config is fine.
allowed_signers includes the configured gitSigningKey and all enrolled
YubiKey public keys regardless of useYubiKey, so switching signing backends
does not remove trust in previously signed commits. Keep the YubiKey .pub
files in ~/.ssh/ (id_ed25519_sk_*.pub, id_ecdsa_sk_*.pub, or the legacy
un-suffixed names); chezmoi reads them whenever it renders this file.
The YubiKeys do not need to be plugged in for verification.
Git needs a key:: prefix to read a literal public key rather than a file
path; the template adds it for you, so paste the key exactly as 1Password
gives it — with or without a trailing comment.
The agent has to offer the key¶
Holding the right key is not enough: the 1Password SSH agent only offers keys from the vaults listed in its config, so the signer can hold a perfectly good key and still fail with "No SSH private key found for the specified public key".
On Windows that config is managed by this repo at
%LOCALAPPDATA%\1Password\config\ssh\agent.toml, rendered from the
opSshVault chezmoi variable — Microsoft on work machines, Private
elsewhere. WSL benefits too, since it reaches the same Windows agent
(see wsl.md).
Watch out for a bare ssh-keys = [], which 1Password writes on a fresh
install. That is an explicit empty list, not "the default set", so the agent
offers nothing at all and ssh-add -l reports no identities. Adding at least
one [[ssh-keys]] entry is what fixes it.
Use a differently-named vault by setting it in your local chezmoi config:
The signer is platform-specific¶
1Password ships a different binary per platform, and the repo auto-detects the right one:
| Platform | Binary | Auto-detected from |
|---|---|---|
| WSL | op-ssh-sign-wsl.exe |
Current Windows user's %LOCALAPPDATA%\Microsoft\WindowsApps\, then the pre-8.11.18 …\1Password\app\8\ |
| Native Windows | op-ssh-sign.exe |
%LOCALAPPDATA%\Microsoft\WindowsApps\, then %LOCALAPPDATA%\1Password\app\8\ |
| macOS | op-ssh-sign |
/Applications/1Password.app/Contents/MacOS/ |
| Linux | — | no standard path; set it explicitly |
Paths are emitted with forward slashes, because git config treats a backslash as an escape character. That is also the form 1Password's own snippet uses.
Override auto-detection for a non-standard install:
If no signer is found¶
Signing is deliberately left off, and the rendered ~/.config/git/config
says why.
Enabling commit.gpgsign without a working gpg.ssh.program would make git
fall back to the local ssh-keygen, which cannot reach the key held by
1Password — so every git commit would fail. Leaving signing off keeps the
repo usable; install or update 1Password, or set opSshSignProgram, then
re-run chezmoi apply.
Verify¶
git config --get gpg.ssh.program
git config --get user.signingkey
git commit --allow-empty -m "signing test"
git log --show-signature -1
A good signature shows Good "git" signature. In WSL the approval prompt
appears on the Windows host — see wsl.md.
If signing fails with "No SSH private key found for the specified public key", check what the agent is actually offering:
No identities means the agent is not running, is locked, or its agent.toml
does not list the vault holding the key — see
the agent has to offer the key.