Skip to content

SSH-Agent and Host Verification

SSH Key Authentication mentioned that a passphrase-protected key asks for that passphrase on every use, and SSH Configuration mentioned in passing the host key prompt that appears on a first connection — both were left for later. This article covers those two mechanisms in depth: using ssh-agent to avoid retyping a passphrase, and host key verification to confirm the server you're connecting to is who it claims to be.

ssh-agent: Entering a Passphrase Once

If a private key is passphrase-protected, that passphrase is requested again on every ssh or scp call — inconvenient when connecting to several servers in a row, or in scripts. ssh-agent is a background process that decrypts a private key once, holds it in memory, and serves every SSH request for the rest of that session without asking for the passphrase again.

The important detail: the private key itself never leaves the agent, even when other programs use it — they only ask the agent to "sign this on my behalf," never obtaining the key itself.

Starting the Agent and Adding a Key

ssh-agent starts automatically in most modern desktop environments. On a server or a minimal environment, it may need to be started manually:

eval "$(ssh-agent -s)"
Agent pid 4821

Adding a key to the agent:

ssh-add ~/.ssh/id_ed25519
Enter passphrase for /home/alice/.ssh/id_ed25519:
Identity added: /home/alice/.ssh/id_ed25519 (alice@laptop)

The passphrase is requested once, right here. Every subsequent ssh alice@server call in this session won't ask for it again.

Listing and Removing Keys from the Agent

ssh-add -l
256 SHA256:k3f9Xq...Qz8 alice@laptop (ED25519)

Removing every key from the agent (for example, before handing a workstation over to someone else):

ssh-add -D

Note

ssh-agent is tied to a session. When a terminal window or graphical session closes, the agent usually stops with it, and the key has to be added again next time. This is deliberate from a security standpoint: an agent that runs forever in the background would extend the window during which the decrypted key is available in memory.

Host Key Verification: Confirming the Server's Identity

The prompt seen on a first connection in SSH Basics is actually only half of a two-way trust relationship — a passphrase and a private key prove your identity to the server, while a host key proves the server's identity to you.

Why This Matters: a Man-in-the-Middle Scenario

Imagine typing ssh [email protected], while someone on the network redirects the traffic at the DNS or ARP level and presents themselves as the real server — a man-in-the-middle attack. If the SSH client never verified the server's identity at all, you'd unknowingly send your login credentials, or at least an authentication attempt, straight to the impostor.

To prevent this, every SSH server has a permanent host key pair (usually stored in files like /etc/ssh/ssh_host_ed25519_key). On a first connection, the client shows the fingerprint of that key — a short, human-readable hash — and asks for confirmation:

The authenticity of host '10.20.0.15 (10.20.0.15)' can't be established.
ED25519 key fingerprint is SHA256:k3f9Xq7Lm...Qz8.
Are you sure you want to continue connecting (yes/no/[fingerprint])?

The correct security practice is to confirm this fingerprint through a separate channel from whoever administers the server — for example, an internal chat message, or running ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub on the server itself from another session. In practice, especially in an internal lab or on a freshly provisioned VM, yes is often accepted without that extra step — an acceptable level of risk only when you're confident you're genuinely connecting to a new server on a trusted, isolated network.

known_hosts: an Archive of Confirmed Keys

Once yes is confirmed, the fingerprint is stored in ~/.ssh/known_hosts:

cat ~/.ssh/known_hosts
10.20.0.15 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGx3k9F7Lp...

On every later connection, the client automatically compares the key received from the server against this entry. If they match, no prompt appears — the connection proceeds silently.

Note

On Debian/Ubuntu clients HashKnownHosts yes is the default, so a real entry usually looks like |1|abcd...=|efgh...= ssh-ed25519 AAAA... rather than the plaintext hostname shown above — the host field is hashed so that a stolen known_hosts file doesn't reveal every server you connect to. You can't grep it by name, but ssh-keygen -F 10.20.0.15 finds the matching (possibly hashed) entry, and ssh-keygen -R 10.20.0.15 removes it either way.

For unattended automation, answering yes by hand isn't possible, and disabling checking outright (StrictHostKeyChecking no) throws away MITM protection. The middle ground is:

ssh -o StrictHostKeyChecking=accept-new alice@new-server

accept-new trusts and records a host key the first time it's seen (so a freshly provisioned VM connects without a prompt) but still refuses to connect if a previously-recorded key later changes — preserving exactly the protection the changed-key warning below provides.

The Warning When a Host Key Has Changed

If a server has been reinstalled, its host keys have been rotated, or — the most serious case — an actual MITM attack is in progress, the following warning appears:

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
...
Offending ED25519 key in /home/alice/.ssh/known_hosts:12
  remove with:
  ssh-keygen -f "/home/alice/.ssh/known_hosts" -R "10.20.0.15"
Host key verification failed.

Danger

Never clear this warning by reflexively removing the old entry and reconnecting. Determine the cause first: if you recently reinstalled the server or deliberately rotated its host key, this is expected. Otherwise, it can be a genuine sign of an attack — do not proceed until you've confirmed the cause with your network or server administrator.

Once the cause is confirmed (for example, a deliberate server reinstall), removing the stale entry:

ssh-keygen -f ~/.ssh/known_hosts -R "10.20.0.15"

This is the same command the warning itself recommends — safer than editing the file by hand, since it removes only the matching entry in the correct format.

Agent Forwarding: Convenience and Its Risk

Sometimes you connect to an internal server through a bastion host, and from there need to perform another action — connecting to yet another server, or a Git repository — that itself requires a key. Agent forwarding (the -A flag) "forwards" your local agent to the remote server, without the private key itself ever being copied anywhere:

ssh -A alice@bastion-server

Warning

Agent forwarding is convenient, but it deserves caution: if root on bastion-server — or anyone who has compromised it — accesses the agent socket during that session, they can use your key, through your agent, to authenticate to other servers on your behalf, without your knowledge. The practical effect is close to having stolen the private key itself. Only use it on intermediate servers you fully trust and control; avoid -A on unfamiliar or multi-user servers. ProxyJump (covered in the previous article) often achieves the same goal without agent forwarding, more safely.

Practical Scenario: Using a Passphrase-Protected Key Conveniently in a Session

Problem: several servers need to be reached one after another during the day, but re-entering a passphrase every single time wastes time.

Step 1 — check the current state:

ssh-add -l
The agent has no identities.

Step 2 — add the key to the agent:

ssh-add ~/.ssh/id_ed25519

Step 3 — confirm the result:

ssh-add -l

Step 4 — connect to several servers in a row and confirm the passphrase is no longer requested:

ssh prod-web "uptime"
ssh staging-db "uptime"

Step 5 — clear the agent once the session is done (especially on a shared or temporary machine):

ssh-add -D

Step 6 — result: the passphrase was entered once during the day, every subsequent connection authenticated automatically, and the key was cleared from memory at the end of the session.

Common Mistakes

Confirming a Host Key Warning Without Knowing the Cause

This is one of the most serious security habits to avoid in SSH. When the warning appears, determine the cause first, then clear the known_hosts entry.

Forgetting to Restart ssh-agent in Every New Session

Opening a new terminal session sometimes starts a fresh, empty agent environment, and keys added earlier appear to have "disappeared." Always check what's currently loaded with ssh-add -l.

Enabling Agent Forwarding on an Untrusted Server

As explained above, this effectively hands another server the ability to "use" your private key without ever holding it. -A should only be used where trust is explicit and well understood.

Deleting the Entire known_hosts File

Deleting the whole file instead of fixing one bad entry forces re-verification for every previously trusted server — defeating the entire purpose of MITM protection. Only remove the specific problematic entry, with ssh-keygen -R.

Exercises

  1. Generate a passphrase-protected test key, add it to ssh-agent, and confirm it's listed with ssh-add -l.
  2. Take one entry from ~/.ssh/known_hosts and explain its three parts (host, key type, key value).
  3. Print your lab server's host key fingerprint directly on the server with ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub, and manually compare it against the fingerprint shown in the client's ssh -v output.
  4. For testing purposes, deliberately alter one character in a known_hosts entry, attempt to connect and observe the "REMOTE HOST IDENTIFICATION HAS CHANGED" warning, then fix it with ssh-keygen -R.

Verification criterion: for exercise 4, after running ssh-keygen -R, a normal connection to that host must succeed again and prompt for a fresh host key confirmation — if it fails or shows no prompt at all, the wrong entry was likely removed.

References