GPG Signing¶
Configure GPG commit and tag signing per identity.
Overview¶
GPG signing provides cryptographic verification of commits and tags. RemoteJuggler manages per-identity GPG keys.
Key Generation¶
Create GPG Key¶
Choose: - Key type: RSA and RSA (default) - Key size: 4096 - Expiration: 1 year recommended - Real name: Your name for this identity - Email: Must match identity email
Example for Work Identity¶
gpg --full-generate-key
# Select RSA and RSA
# 4096 bits
# 1y expiration
# Real name: Work User
# Email: work@company.com
Listing Keys¶
All Secret Keys¶
Output:
/Users/user/.gnupg/pubring.kbx
------------------------------
sec rsa4096/ABC123DEF456 2024-01-15 [SC] [expires: 2025-01-15]
ABCDEF1234567890ABCDEF1234567890ABC123DE
uid [ultimate] Work User <work@company.com>
ssb rsa4096/GHI789JKL012 2024-01-15 [E] [expires: 2025-01-15]
RemoteJuggler Key List¶
Shows: - Available GPG keys - Per-identity GPG configuration - Signing preferences
Configuration¶
Configure Identity GPG¶
Add to identity configuration:
{
"identities": {
"work": {
"gpg": {
"keyId": "ABC123DEF456",
"signCommits": true,
"signTags": true,
"autoSignoff": false
}
}
}
}
Auto-Detect Key by Email¶
Searches for GPG key matching the identity's email address.
Provider Registration¶
GPG keys must be registered with the provider for verification.
GitLab¶
-
Export public key:
-
Go to GitLab > Settings > GPG Keys
-
Paste the public key
GitHub¶
-
Export public key:
-
Go to GitHub > Settings > SSH and GPG keys
-
Click "New GPG key" and paste
Verification URL¶
Shows registration status and direct links to settings pages.
Git Configuration¶
Manual Setup¶
# Set signing key
git config --global user.signingkey ABC123DEF456
# Enable commit signing
git config --global commit.gpgsign true
# Enable tag signing
git config --global tag.gpgsign true
RemoteJuggler Automatic Setup¶
When switching identities with GPG configured:
Automatically sets:
- user.signingkey
- commit.gpgsign
- tag.gpgsign (if configured)
Signing Operations¶
Sign Commits¶
With commit.gpgsign = true:
Manual signing:
Sign Tags¶
With tag.gpgsign = true:
Manual signing:
Verify Signatures¶
GPG Agent¶
Configure Agent¶
~/.gnupg/gpg-agent.conf:
Restart Agent¶
Troubleshooting¶
"secret key not available"¶
Key not found in GPG keyring:
"failed to sign the data"¶
GPG agent issue:
Pinentry Issues (macOS)¶
Install pinentry-mac:
brew install pinentry-mac
echo "pinentry-program $(which pinentry-mac)" >> ~/.gnupg/gpg-agent.conf
gpgconf --kill gpg-agent
TTY Issues¶
Set GPG TTY:
Git Commit Hangs¶
GPG waiting for passphrase input:
# Use GUI pinentry
echo "pinentry-program /usr/local/bin/pinentry-mac" >> ~/.gnupg/gpg-agent.conf
gpgconf --kill gpg-agent
Key Management¶
Export Public Key¶
Export Private Key (Backup)¶
Store securely (encrypted backup).
Key Expiration¶
Extend key expiration:
Re-upload public key to providers after extension.
Revoke Key¶
If key is compromised:
Remove from provider settings.
Multiple Keys Per Identity¶
Some setups require different keys for commits vs tags:
{
"gpg": {
"keyId": "ABC123DEF456",
"signCommits": true,
"signTags": true,
"tagKeyId": "XYZ789ABC123"
}
}
Note: This requires custom git configuration beyond RemoteJuggler's standard setup.
Hardware Token (YubiKey) Support¶
RemoteJuggler supports GPG signing with hardware tokens like YubiKey. This section covers setup, touch policies, and agent limitations.
Overview¶
Hardware tokens provide enhanced security by storing private keys on tamper-resistant hardware. However, they have specific requirements for signing operations:
- Physical touch: YubiKey can require physical touch for each signature
- Card presence: The token must be connected when signing
- Agent limitations: MCP agents cannot trigger physical touch
YubiKey Configuration¶
Check YubiKey Status¶
Touch Policy¶
YubiKey touch policies control when physical touch is required:
| Policy | Behavior | Agent Compatible |
|---|---|---|
off |
Never require touch | Yes |
on |
Always require touch | No - cannot automate |
cached |
Touch once, cached 15s | Partially - user must initiate |
Check current touch policies:
Set touch policy (requires PIN):
# Set signing to "cached" for better agent compatibility
ykman openpgp keys set-touch sig cached
# Options: off, on, cached, fixed (permanent)
Identity Configuration for Hardware Keys¶
Configure an identity to use a hardware-backed GPG key:
{
"identities": {
"gitlab-personal": {
"gpg": {
"keyId": "8547785CA25F0AA8",
"format": "gpg",
"signCommits": true,
"signTags": true,
"hardwareKey": true,
"touchPolicy": "on"
}
}
}
}
The hardwareKey and touchPolicy fields enable RemoteJuggler to warn agents about touch requirements.
SSH Signing Alternative¶
Git 2.34+ supports SSH key signing, which can use FIDO2 keys on YubiKey:
{
"identities": {
"gitlab-work": {
"gpg": {
"format": "ssh",
"sshKeyPath": "~/.ssh/gitlab-work-sk.pub",
"signCommits": true,
"hardwareKey": true,
"touchPolicy": "cached"
}
}
}
}
Advantages of SSH signing:
- FIDO2 keys can use
aut=cachedtouch policy - SSH agent handles authentication caching
- Simpler toolchain than GPG
Setup SSH signing:
# Configure git for SSH signing
git config --global gpg.format ssh
git config --global user.signingkey ~/.ssh/gitlab-work-sk.pub
git config --global commit.gpgsign true
# Create allowed signers file for verification
echo "your@email.com $(cat ~/.ssh/gitlab-work-sk.pub)" >> ~/.ssh/allowed_signers
git config --global gpg.ssh.allowedSignersFile ~/.ssh/allowed_signers
MCP Tool: juggler_gpg_status¶
The juggler_gpg_status MCP tool checks signing readiness including hardware token status:
Response includes:
{
"identity": "gitlab-personal",
"signingFormat": "gpg",
"keyId": "8547785CA25F0AA8",
"hardwareKey": true,
"cardPresent": true,
"cardSerial": "26503492",
"touchPolicy": {
"signing": "on",
"authentication": "cached"
},
"canSign": false,
"reason": "Physical YubiKey touch required for each commit",
"recommendation": "Ensure YubiKey is connected. Agent will configure identity; user must touch YubiKey when committing."
}
Agent Workflow with Hardware Keys¶
When agents use juggler_switch with a hardware-key identity:
- Agent switches identity - configures git user and signing key
- Agent receives warning - told that touch is required
- Agent cannot sign - must inform user
- User commits - physically touches YubiKey
- Commit succeeds - signature created
Example switch response:
Switching to identity: gitlab-personal
================================
[OK] Set user.name = Jesssullivan
[OK] Set user.email = jess@sulliwood.org
[OK] Set signing format: gpg
[OK] Set GPG signing key: 8547785CA25F0AA8
[OK] Enabled GPG commit signing
[HARDWARE KEY WARNING]
GPG signing key 8547785CA25F0AA8 is on a hardware token (YubiKey)
Touch policy: on - Physical touch required for EACH signature
Agent CANNOT automate signing - user must touch YubiKey when committing
Use 'juggler_gpg_status' to check YubiKey presence before committing
Troubleshooting Hardware Keys¶
"No secret key" Error¶
Causes:
- YubiKey not connected
- Wrong signing key configured (placeholder vs real key)
- GPG agent doesn't see the card
Fix:
# Check card is visible
gpg --card-status
# If not, restart gpg-agent
gpgconf --kill gpg-agent
# Verify correct key ID
gpg --list-secret-keys --keyid-format=long
git config --global user.signingkey # Should match
Signing Timeout¶
GPG waiting for touch that never happens (batch mode):
# Test signing interactively
echo "test" | gpg -u 8547785CA25F0AA8 --clearsign
# If this works with touch, hardware is fine
# If this hangs, touch policy may be "on" without user awareness
YubiKey Not Detected¶
# Check USB connection
ykman list
# Check GPG sees the card
gpg --card-status
# If "No card" error, try:
# 1. Unplug and replug YubiKey
# 2. Kill and restart gpg-agent
gpgconf --kill gpg-agent
# 3. Check for pcscd conflicts
Best Practices¶
- Use
cachedtouch for CI-adjacent workflows - allows brief automated operation after user touch - Use
ontouch for maximum security - every signature requires presence proof - Prefer SSH signing for work accounts - simpler setup, better agent compatibility
- Keep GPG signing for personal accounts - established trust, keyserver publishing
- Always set
hardwareKey: truein config - enables proper agent warnings - Run
juggler_gpg_statusbefore signing - agents should check readiness
Reference: Touch Policy Comparison¶
| Scenario | GPG (touch=on) | GPG (touch=cached) | SSH (aut=cached) |
|---|---|---|---|
| Single commit | Touch required | Touch required | Touch required |
| Multiple commits (rapid) | Touch each | Touch once | Touch once |
| Agent automation | Not possible | Limited window | Limited window |
| CI/CD signing | Not supported | Not supported | Not supported |
| Maximum security | Best | Good | Good |
| User friction | High | Medium | Medium |