Old ssh known_hosts entries

If you regularly rebuild Linux servers you will almost certainly come across a message that looks something like the following when you try to login via ssh:

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    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)!
It is also possible that a host key has just been changed.
The fingerprint for the ECDSA key sent by the remote host is
c0:87:77:8f:e8:5c:26:11:53:4d:7b:1b:7a:04:e9:06.
Please contact your system administrator.
Add correct host key in /home/example/.ssh/known_hosts to get rid of this message.
Offending ECDSA key in /home/example/.ssh/known_hosts:39
ECDSA host key for example has changed and you have requested strict checking.
Host key verification failed.

Quickly removing old entries

You can quickly remove old host entries using ssh-keygen:

ssh-keygen -R "example"

Alternatively I've had the following bash function in my .bashrc for a little while now:

ssh-del-knownhost() {
  last_cmd="$(history|grep '^ *[0-9]* *ssh '|sed 's/^ *[0-9]* *//'| tail -n 1)"
  if [ ! "$last_cmd" ]; then
    echo "Unable to find last ssh command!" 1>&2
    return 1
  fi
  if ! $last_cmd 2>&1 | grep -q 'WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!'; then
    echo "No conflicting know hosts entry found!" 1>&2
    return 2
  fi
  $last_cmd 2>&1 | \
    grep '^Offending .*key in '| \
    sed -r 's/^Offending .*key in ([^:]*):([0-9]*).*$/sed -i \2d \1/' | \
    bash -x
}

The above function essentially runs through the following steps:

  1. Check history for the last used ssh command.
  2. Run the command to make sure it displays a warning message.
  3. Extract the path to the known_hosts file and the line number of the offending entry.
  4. Use sed to remove the offending entry

Running the function looks something like this:

$ ssh-del-knownhost
+ sed -i 39d /home/example/.ssh/known_hosts

Checking new entries

Once you've removed any old entries you should get a message that looks something like this when you try to connect:

$ ssh example
The authenticity of host 'example (127.0.0.1)' can't be established.
ECDSA key fingerprint is c0:87:77:8f:e8:5c:26:11:53:4d:7b:1b:7a:04:e9:06.
Are you sure you want to continue connecting (yes/no)?

If you completely trust your network you can just type yes and carry on with what you were doing. If you want to be a little more paranoid you can run the following command directly on the server and compare the fingerprint before accepting it.

$ ssh-keygen -l -f /etc/ssh/ssh_host_ecdsa_key.pub
256 c0:87:77:8f:e8:5c:26:11:53:4d:7b:1b:7a:04:e9:06   (ECDSA)

Note: the file you need to check will depend on how OpenSSH has been configured on the server and which public key encryption algorithm you are using.