If your SSH key has a passphrase (it should), typing it for every connection gets old fast. ssh-agent keeps your unlocked keys in memory, so you enter the passphrase once per session. Agent forwarding lets a server you’re logged into use your local keys, for example to git pull from a private repository, without copying your private key to the server.

ssh-agent basics

Most desktop environments and macOS start an agent automatically. Check:

echo "$SSH_AUTH_SOCK"
ssh-add -l               # list loaded keys ("The agent has no identities" = empty)

Start one manually if needed (in a plain shell or on a server):

eval "$(ssh-agent -s)"

Add your key:

ssh-add ~/.ssh/id_ed25519          # asks for the passphrase once
ssh-add -t 4h ~/.ssh/id_ed25519    # forget it after 4 hours
ssh-add -l                         # verify
ssh-add -D                         # remove all keys from the agent

Automatic loading

In ~/.ssh/config on your computer:

Host *
    AddKeysToAgent yes
    IdentityFile ~/.ssh/id_ed25519

The first connection asks for the passphrase and adds the key to the agent. Later connections don’t ask. On macOS, add UseKeychain yes to store the passphrase in the Keychain.

Windows: enable the “OpenSSH Authentication Agent” service, then use ssh-add in PowerShell.

See SSH keys with ssh-keygen and SSH config file.

Agent forwarding

Scenario: you SSH into your web server and need to git pull from a private GitHub repository. The deploy key isn’t on the server, it’s on your laptop. With forwarding:

ssh -A deploy@web1
# on web1:
ssh-add -l                       # shows YOUR laptop's keys
git pull                         # authenticates to GitHub with your laptop key

Or per host in ~/.ssh/config:

Host web1
    HostName 203.0.113.10
    User deploy
    ForwardAgent yes

The private key never leaves your computer. The server just asks your agent to sign authentication requests through the SSH connection.

The server’s sshd_config must allow it with AllowAgentForwarding yes, which is the default.

The risk: root on the server can use your agent

While you’re connected with forwarding, anyone with root on that server, or access to your user there, can use your agent socket to authenticate as you to any other server or service your keys open. They can’t copy the key, but they can use it while you’re connected.

Guidelines:

  • Never enable ForwardAgent yes for Host *. Enable it only for specific, trusted servers.
  • Don’t forward to shared or untrusted machines.
  • Use ssh-add -c (confirm). The agent asks for confirmation on your desktop for each use (needs ssh-askpass).
  • Prefer the alternatives below when they fit.

Safer alternatives

Jumping through a bastion host? Use ProxyJump instead of forwarding:

ssh -J bastion.example.com app-server

The connection to app-server is tunnelled through the bastion, but authentication happens from your laptop. The bastion never gets access to your agent. See SSH jump host with ProxyJump.

Deploying from a server? Use a deploy key on the server. Create a dedicated key on the server and add it as a read-only deploy key to that one repository:

ssh-keygen -t ed25519 -f ~/.ssh/deploy_myrepo -N ""

Add the public key in the repository’s settings under Deploy keys, and map it in ~/.ssh/config:

Host github-myrepo
    HostName github.com
    User git
    IdentityFile ~/.ssh/deploy_myrepo

Then clone with git clone git@github-myrepo:org/myrepo.git. If the server is compromised, only read access to one repository is exposed. See Git SSH keys.

CI/CD pipelines should use their own secrets and deploy keys, not a human’s forwarded agent. See GitHub Actions deploy.

Troubleshooting

Could not open a connection to your authentication agent — no agent is running in this shell. Run eval "$(ssh-agent -s)".

Forwarding doesn’t work (ssh-add -l on the server says no agent) — check ForwardAgent yes or -A, that the server allows AllowAgentForwarding, and that sudo isn’t dropping SSH_AUTH_SOCK. With sudo -E, or an env_keep += "SSH_AUTH_SOCK" sudoers rule, the variable is kept, but root also needs permission on the socket. That’s another reason to prefer deploy keys.

Inside tmux or screen, the agent stops working after reconnecting — the socket path changed. Use a stable symlink (~/.ssh/ssh_auth_sock) updated in ~/.ssh/rc.

Quick reference

Task Command
Start agent eval "$(ssh-agent -s)"
Add key ssh-add ~/.ssh/id_ed25519
Add with timeout ssh-add -t 4h key
List / remove keys ssh-add -l / ssh-add -D
Forward once ssh -A host
Forward per host ForwardAgent yes in ~/.ssh/config
Safer hop ssh -J bastion target

Related: SSH hardening and SSH tunnels.

  • SSH
  • Security
  • Linux