Score:0

How to remove all lines with the same public key from known_hosts?

in flag

Let's imagine the following scenario.

I have an host key ABCDEF1234 for a given hostname, so my known_hosts file looks like this (unhashed version):

example.com ssh-rsa ABCDEF1234

Now I connect to it, and hostnames resolve to 10.11.12.13 I have a message like this

Warning: Permanently added the ECDSA host key for IP address '10.11.12.13' to the list of known hosts.

And my known_hosts looks like this

example.com ssh-rsa ABCDEF1234
192.0.2.1 ssh-rsa ABCDEF1234 

Now a few month later, example.com admin tells me the RSA key is removed and changed in favour of 1234ABCDEF key. So I remove the offending key using ssh-keygen -R example.com, then I connect for the first time, accepts the key, and know my known_host looks like this:

192.0.2.1 ssh-rsa ABCDEF1234 
example.com  ssh-rsa 1234ABCDEF

And every time I connect I have this nice warning message:

Warning: the ECDSA host key for 'example.com' differs from the key for the IP address '192.0.2.1'
Offending key for IP in /home/jenkins/.ssh/known_hosts:162
Matching host key in /home/jenkins/.ssh/known_hosts:182

Now imagine there are tens or hundreds of IP for that particular hostname, that is quite a lot of lines to clean. One solution is to use sed to remove matching lines, but isn't the goal of ssh-keygen -R to avoid messing with sed?

sed -i '/ABCDEF1234/d' known_hosts

Is there another solution, that would remove all entries from a known_host file that are associated with a given key, instead of an hostname or IP address ?

asktyagi avatar
in flag
I think this post has your answer https://askubuntu.com/questions/123072/ssh-automatically-accept-keys
uz flag
Why do you use: `ssh-keygen -R myhost.com` to remove the entry for myhost.com,, and do you not use: `ssh-keygen -R 10.11.12.13` to remove the entry for 10.11.12.13 ?
shodanex avatar
in flag
@Luuk Let's say github.com changes its rsa key, do you know all IP of github.com ? Of course if I have single ip, I can do waht you suggest.
uz flag
That's why, when you connect to github.com, you will not use an ip-address, but use a hostname.
shodanex avatar
in flag
@Luuk Well on my ubuntu machine, if I connect by hostname, an entry is also added for the IP that hostname was resolved to. And the issue happen when there is a mismatch. But everything is already written above in the ticket, which deserves being read in full :)
dave_thompson_085 avatar
jp flag
shodanex: which Ubuntu? Adding both hostname and IP to `known_hosts` was long the default behavior in OpenSSH, but you could disable it by setting option `CheckHostIP = no` on the commandline with `-o` or in your config file(s). [OpenSSH 8.5 changed the default to no](http://www.openssh.com/txt/release-8.5), and Ubuntu 22.04 up should have OpenSSH 8.9 up.
Score:3
jp flag

The purpose of ssh-keygen -R is not to avoid using sed, but to remove hashed hosts that, e.g., sed could not find. From ssh-keygen(1):

-R hostname

Removes all keys belonging to hostname from a known_hosts file. This option is useful to delete hashed hosts (see the -H option above).

-H

Hash a known_hosts file. This replaces all hostnames and addresses with hashed representations within the specified file; the original content is moved to a file with a .old suffix. These hashes may be used normally by ssh and sshd, but they do not reveal identifying information should the file's contents be disclosed. This option will not modify existing hashed hostnames and is therefore safe to use on files that mix hashed and non-hashed names.

Considerations

Avoid collisions

Notice that it is best to use the full public key encoded in Base64 to avoid removing other keys. E.g., if you use just parts of the header your would end up removing all the keys of the same type:

 Base64 ASCII Ref.
AAAAE2VjZHNhLXNoYTItbmlzdHAyNTY
AAAAIbmlzdHAyNTYAAABBB
....ecdsa-sha2-nistp256
....nistp256...A
RFC 5656, 3.1
AAAAC3NzaC1lZDI1NTE5AAAAIFKy ....ssh-ed25519... R² RFC 8709, 4
AAAAB3NzaC1yc2EAAAADAQABAAABAQ ...ssh-rsa........... RFC 4253, 6.6

Adjust your sed for Base64

The Base64 encoded public key contains characters A-Za-z0-9+/=. As it can contain the / used in your sed example, you would like to use another character like :.

Working examples

In the examples:

  • The AAAA+OLD/KEY= is a placeholder for the full old public key.
  • The AAAA+NEW/KEY= is a placeholder for the full new public key.

Remove all hosts having the same key

Use the full old key to remove all lines containing it:

sed -i ':AAAA+OLD/KEY=:d' ~/.ssh/known_hosts

Replace the old key with a new one

Use the full keys (old & new) to replace it on all lines containing the old key:

sed -i 's:AAAA+OLD/KEY=:AAAA+NEW/KEY=:g' ~/.ssh/known_hosts

If the key type also changes, you would have to include it, e.g.,

sed -i 's:ssh-rsa AAAA+OLD/KEY=:ecdsa-sha2-nistp256 AAAA+NEW/KEY=:g' ~/.ssh/known_hosts

Remove keys for the hostname or IP

This is the only use case where you would use ssh-keygen.

ssh-keygen -R example.com

ssh-keygen -R 192.0.2.1

Score:0
in flag

Avoiding the issue in the first place is a good solution. If known_hosts wasn't filled with entry for each and every IP for a given hostname, there would be no need to mess with sed. ssh_keygen -R hostname would be sufficient to perform key rotation.

So my solution to this is to set CheckHostIP to no in the ssh config.

How does the SSH option CheckHostIP=yes really help me?

I sit in a Tesla and translated this thread with Ai:

mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.