SSH Authentication with Ledger
Use your Ledger hardware wallet for secure SSH authentication.
Table of Contents
Section titled “Table of Contents”- Overview
- How It Works
- Prerequisites
- Setup
- Using SSH with Ledger
- GitHub/Server Configuration
- Troubleshooting
- Advanced Usage
- Security Considerations
- Related Documentation
Overview
Section titled “Overview”SSH authentication with Ledger provides hardware-backed security for SSH connections:
- Private key on device - Key never leaves Ledger
- Physical confirmation - Button press required for each auth
- Multiple agents - Two options: GPG agent or ledger-agent
- Platform support - Works with GitHub, GitLab, servers
How It Works
Section titled “How It Works”Architecture
Section titled “Architecture”┌─────────────────────────────────────────────────────────────┐│ SSH Authentication Flow │├─────────────────────────────────────────────────────────────┤│ ││ ssh github.com ││ │ ││ ▼ ││ SSH Client (looks for key) ││ │ ││ ▼ ││ SSH Agent (ledger-agent or gpg-agent) ││ │ ││ ▼ ││ Ledger Device ││ │ ││ ▼ ││ [User presses button to confirm] ││ │ ││ ▼ ││ Signature returned → SSH connection established ││ │└─────────────────────────────────────────────────────────────┘
Key Types
Section titled “Key Types”Ledger supports:
- ECDSA (NIST P-256) - Default, widely supported
- Ed25519 - Modern, faster (via ledger-agent)
- NIST P-256 with SSH - Via GPG agent
Prerequisites
Section titled “Prerequisites”- Ledger Nano S device
- SSH/GPG Agent app installed on Ledger
-
ledger-agent
package installed (included in hardware-security profile) - Device initialized and unlocked
See Ledger Setup Guide for initial setup.
Option 1: GPG Agent for SSH (Recommended)
Section titled “Option 1: GPG Agent for SSH (Recommended)”Your configuration uses GPG agent with SSH support enabled:
Already configured in nix/profiles/hardware-security.nix
:
services.gpg-agent = { enable = true; enableSshSupport = true; pinentry.package = pkgs.pinentry_mac;};
home.sessionVariables = { SSH_AUTH_SOCK = "$(gpgconf --list-dirs agent-ssh-socket)";};
Verify it’s working:
# Check SSH_AUTH_SOCK is setecho $SSH_AUTH_SOCK# List SSH keys from agentssh-add -L
Option 2: Standalone Ledger SSH Agent
Section titled “Option 2: Standalone Ledger SSH Agent”Alternative method using ledger-agent
directly:
Start the agent:
# Start in backgroundledger-agent -d ssh://ledger@localhost &
# Set SSH auth socketexport SSH_AUTH_SOCK="${HOME}/.ledger-agent/ssh-agent.sock"
Or use launchd service (already configured):
The hardware-security profile includes:
launchd.agents.ledger-ssh-agent = { enable = true; config = { ProgramArguments = [ "${pkgs.ledger-agent}/bin/ledger-agent" "-d" "ssh://ledger@localhost" ]; RunAtLoad = true; };};
Using SSH with Ledger
Section titled “Using SSH with Ledger”Get Your SSH Public Key
Section titled “Get Your SSH Public Key”# Using GPG agent (Option 1)ssh-add -L
# Using ledger-agent (Option 2)ledger-agent ssh://ledger@localhost &ssh-add -L
Output example:
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTY... ledger
Copy Public Key
Section titled “Copy Public Key”# Copy to clipboard (macOS)ssh-add -L | pbcopy
# Save to filessh-add -L > ~/.ssh/ledger_ssh.pub
Test SSH Authentication
Section titled “Test SSH Authentication”# Test GitHubssh -T git@github.com
# Ledger will display "SSH Auth" - press button to confirm
# Expected output:# Hi username! You've successfully authenticated...
SSH to Server
Section titled “SSH to Server”# Connect to serverssh user@server.com
# Ledger prompts for confirmation# Press button to authenticate
GitHub/Server Configuration
Section titled “GitHub/Server Configuration”Add to GitHub
Section titled “Add to GitHub”-
Copy your public key:
Terminal window ssh-add -L | pbcopy -
Add to GitHub:
- Go to Settings → SSH and GPG keys
- Click “New SSH key”
- Title:
Ledger SSH Key
- Key: Paste your public key
- Click “Add SSH key”
-
Verify:
Terminal window ssh -T git@github.com
Add to GitLab
Section titled “Add to GitLab”- Copy public key (same as above)
- Go to Preferences → SSH Keys
- Paste key and save
Add to Server
Section titled “Add to Server”# Copy public key to serverssh-copy-id -i <(ssh-add -L) user@server.com
# Or manually append to authorized_keysssh-add -L | ssh user@server.com 'cat >> ~/.ssh/authorized_keys'
Test Connection
Section titled “Test Connection”# SSH with verbose outputssh -v user@server.com
# Look for:# debug1: Offering public key: ecdsa-sha2-nistp256 ... ledger# debug1: Server accepts key: ...# [Ledger prompts for confirmation]
Troubleshooting
Section titled “Troubleshooting”SSH_AUTH_SOCK Not Set
Section titled “SSH_AUTH_SOCK Not Set”Problem: ssh-add -L
shows “Could not open a connection to your authentication agent”
Solution:
# For GPG agentexport SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket)
# For ledger-agentexport SSH_AUTH_SOCK="${HOME}/.ledger-agent/ssh-agent.sock"
# Add to ~/.zshrc to persistecho 'export SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket)' >> ~/.zshrc
No Keys Listed
Section titled “No Keys Listed”Problem: ssh-add -L
shows “The agent has no identities”
Solution:
# Ensure Ledger is:# 1. Connected via USB# 2. Unlocked (PIN entered)# 3. SSH/GPG Agent app is open# 4. Screen shows "ready"
# Restart agentkillall gpg-agent ledger-agentgpgconf --launch gpg-agent
# Or start ledger-agentledger-agent -d ssh://ledger@localhost &
# Check againssh-add -L
Ledger Not Responding
Section titled “Ledger Not Responding”Problem: SSH hangs waiting for Ledger
Checklist:
- Ledger connected and unlocked
- SSH/GPG Agent app is open on device
- Device screen shows “SSH/GPG Agent is ready”
- Agent process running:
pgrep -f ledger
Test:
# Check agent statuspgrep -f "ledger-agent\|gpg-agent"
# Check logstail -f ~/.local/share/ledger-ssh-agent.logtail -f ~/.local/share/gpg-agent.log
Permission Denied (publickey)
Section titled “Permission Denied (publickey)”Problem: Server rejects Ledger key
Solution:
-
Verify key is on server:
Terminal window ssh user@server.com 'cat ~/.ssh/authorized_keys' | grep "$(ssh-add -L | cut -d' ' -f2)" -
Check server logs:
Terminal window ssh user@server.com 'sudo tail /var/log/auth.log' -
Try with verbose output:
Terminal window ssh -vvv user@server.com
Agent Conflicts
Section titled “Agent Conflicts”Problem: Multiple SSH agents interfering
Solution:
# Kill all agentskillall ssh-agent gpg-agent ledger-agent
# Start only onegpgconf --launch gpg-agent
# Verifyecho $SSH_AUTH_SOCKssh-add -L
Advanced Usage
Section titled “Advanced Usage”Multiple Keys
Section titled “Multiple Keys”List all available SSH keys:
# From agentssh-add -L
# Specify key explicitlyssh -i <(ssh-add -L | head -1 | awk '{print $1" "$2}') user@server.com
SSH Config
Section titled “SSH Config”Configure per-host settings in ~/.ssh/config
:
# Use Ledger for GitHubHost github.com IdentityAgent /Users/you/.gnupg-ledger/S.gpg-agent.ssh IdentitiesOnly yes
# Use Ledger for work serversHost *.company.com IdentityAgent /Users/you/.gnupg-ledger/S.gpg-agent.ssh User your-username
Key Derivation Paths
Section titled “Key Derivation Paths”ledger-agent supports different derivation paths:
# Default pathledger-agent ssh://ledger@localhost
# Custom pathledger-agent ssh://ledger@localhost/0h/1h/2h
# Ed25519 (if supported)ledger-agent ssh://ledger@localhost --curve ed25519
Forwarding SSH Agent
Section titled “Forwarding SSH Agent”Forward Ledger agent to remote machine:
# Enable agent forwardingssh -A user@server.com
# On remote machine, SSH will use your Ledgerssh git@github.com
Security Note: Only forward to trusted machines.
Using with Git
Section titled “Using with Git”Configure Git to always use SSH:
# Set SSH for Git globallygit config --global url."ssh://git@github.com/".insteadOf "https://github.com/"
# Clone repos using SSHgit clone git@github.com:user/repo.git
Security Considerations
Section titled “Security Considerations”Threat Model
Section titled “Threat Model”What Ledger SSH protects against:
- ✅ Key theft from computer
- ✅ Malware extracting SSH keys
- ✅ Unauthorized SSH access
- ✅ Key exfiltration via network
What it doesn’t protect against:
- ❌ Malware intercepting SSH session after auth
- ❌ Compromised remote server
- ❌ Physical theft of Ledger (PIN protects)
- ❌ Social engineering attacks
Best Practices
Section titled “Best Practices”-
Physical Security
- Remove Ledger when not in use
- Lock screen when away
-
Key Management
- Use separate keys for different purposes
- Rotate keys periodically
- Remove old keys from servers
-
Agent Security
- Don’t forward agent to untrusted machines
- Use
IdentitiesOnly yes
in SSH config - Monitor agent logs for unusual activity
-
Backup
- Keep 24-word recovery phrase secure
- Test recovery process periodically
- Consider backup Ledger device
Recovery
Section titled “Recovery”If Ledger is lost or damaged:
-
Restore from seed:
Terminal window # On new Ledger with same seedledger-agent ssh://ledger@localhostssh-add -L # Same key will be generated -
Or use backup key:
- Keep traditional SSH key as backup
- Store securely (encrypted)
- Only use when Ledger unavailable
Related Documentation
Section titled “Related Documentation”- Ledger Setup Guide - Initial Ledger configuration
- Ledger Deep Dive - Comprehensive hardware security
- GPG Signing - Git commit signing with Ledger
- SOPS Guide - Secrets management
External References
Section titled “External References”- Ledger SSH/GPG Agent - Official app
- trezor-agent SSH - Agent docs
- SSH Public Key Auth - SSH documentation
- GitHub SSH Keys - GitHub docs
Quick Reference
Section titled “Quick Reference”Essential Commands
Section titled “Essential Commands”# Get SSH public keyssh-add -L
# Test GitHubssh -T git@github.com
# Test serverssh user@server.com
# Check agentecho $SSH_AUTH_SOCK
# Restart agent (GPG)killall gpg-agent && gpgconf --launch gpg-agent
# Start ledger-agentledger-agent -d ssh://ledger@localhost &
# View logstail -f ~/.local/share/ledger-ssh-agent.log
Environment Setup
Section titled “Environment Setup”# Add to ~/.zshrc
# For GPG agentexport SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket)
# For ledger-agentexport SSH_AUTH_SOCK="${HOME}/.ledger-agent/ssh-agent.sock"
Happy secure SSH! 🔐
See GPG Signing for commit signing with Ledger.