292

I built several virtual machines during the last few weeks. The problem is, the .ssh/known_hosts gives me the Man in the middle warning. This happens because another fingerprint is associated with the virtual machine IP.

In the .ssh/known_hosts file, however, I don't find the record related to the IP, only two bizarre, key-like strings and "ssh-rsa".

Does anyone have any ideas about how to remove the old key from known_hosts?

2
  • 10
    The "bizarre, key-like strings" you refer to are the hashed hosts/ip addresses. This a security feature which helps stops an intruder from knowing which systems you have access to. If you see this then your ssh_config has HashKnownHosts yes set.
    – Deebster
    Jul 12, 2014 at 15:03
  • 1
    If you feel the file contents are too confusing, you probably have line-wrapping activated. Deactivate it. All lines start with a host name or an IP address.
    – Daniel B
    Jun 28, 2018 at 8:01

11 Answers 11

145
sed -i '6d' ~/.ssh/known_hosts

Will modify the file ~/.ssh/known_hosts:6 , removing the 6th line.

In my opinion, using ssh-keygen -R is a better solution for an openssh power user, while your regular Linux admin would do better to keep his/her sed skills fresh by using the above method.

5
  • 49
    I don't think it's a good advice to edit a configuration file manually if you have an official application for that. Taking risks doesn't make you a pro, finding the quickest and safest option does. It's like telling people to go ahead and edit /etc/sudoers without visudo. If you want to sharpen your sed skills, go ahead and do that without messing up your system.
    – kraxor
    Jun 27, 2014 at 11:56
  • 4
    "if you have an official application for that" => both ssh-keygen -R and sed -i {line}d are pretty "official", and both will work for the foreseeable future. Util ssh-keygen allows removal by line number, both are perfectly acceptable (because, line numbers are often easier to deal with, and less error prone, than dealing with modern data center host-names).
    – michael
    Sep 20, 2016 at 9:26
  • 9
    A)The deletion of specifically the 6th line, is all very "look no hands". No explanation at all as to what is significant about the 6th line of the file?! B)Also man ssh-keygen mentions ssh-keygen -R hostname you've just said ssh-keygen -R with no hostname specified, and you haven't explained what you mean by that.
    – barlop
    Mar 16, 2018 at 5:33
  • 1
    When we aren't using default SSH port, then the hostname for -R should be provided with the following format '[<host-name OR IP>]:<SSH Port>'. For example: ssh-keygen -f ~/.ssh/known_hosts -R '[192.168.23.2]:1234'
    – Junaid
    Jun 13, 2022 at 21:50
  • As a rule I agree with other comments that ssh-keygen -R should be used whenever possible. I had issues with that as using the hotsname would delete the new key instead of the old now-offending one... eventually I figured out that I could provide the IP address IP address printed in the ssh error message instead of the hostname, but the sed was next as nothing else was working. Last resort!
    – Oliver
    Mar 27, 2023 at 20:40
277

There is an ssh-keygen switch (-R) for this.

man ssh-keygen reads:

-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).

7
  • 39
    This is the easiest and safest method.
    – chicken
    Apr 15, 2014 at 14:13
  • 1
    Note: This will change the permissions of the known_hosts file to 0600. If you have a shared known_hosts file for any reason, this could disable the sharing of it. Sep 11, 2017 at 18:04
  • 1
    and the correct one. Also, I had to do [localhost]:port, using the brackets because I used a custom port I guess =/. Like others have said, I would also use the no SSH key-checking approach for my transient/test system development.
    – Pysis
    Oct 26, 2018 at 12:58
  • This removes all ocurences so the best way. You can add new key with: ssh-keyscan -H my.ssh.server.example.com >> ~/.ssh/known_hosts;
    – Nux
    Oct 16, 2019 at 11:08
  • 1
    @Pysis Thanks! your suggestion worked for me!
    – kyrlon
    Jan 15 at 4:36
228

The simplest solution is:

rm -f .ssh/known_hosts

ssh will recreate the file again, but you lose key checking for other hosts!

Or, you can use:

ssh-keygen -R "hostname"

Or the ssh "man-in-the-middle" message should indicate which line of the known_hosts file has the offending fingerprint. Edit the file, jump to that line and delete it.

9
  • 109
    ssh-keygen -R hostname will work too. Aug 26, 2009 at 17:14
  • 24
    If we remove that file, other keys will remove too.
    – shgnInc
    May 4, 2014 at 9:13
  • 61
    Removing the file is a bad advice, it's like telling someone to buy a new PC because the old one has a broken mouse. Manually editing a file that can be edited by an official application is also a bad idea. The ssh-keygen option was added because of a comment, but with no explanation. I don't think this answer deserves so many upvotes.
    – kraxor
    Jun 27, 2014 at 11:52
  • 32
    -1 because of the whole "delete the whole known_hosts file" first lines. This is a terrible, terrible, terrible thing to propose, and should be edited out. Mar 9, 2015 at 10:35
  • 15
    This solution is overkill. Just remove the offending line. That's it. May 11, 2016 at 18:31
48

You need to run the following command to get rid of this problem. Open the terminal and type the following command:

For all examples below just replace the value after -R:

ssh-keygen -R server-name
ssh-keygen -R server.ip.addre.ss
ssh-keygen -R 202.54.1.5
ssh-keygen -R server1.example.com
4
  • 1
    This method has already been suggested in the previous answers. Could you expanded upon what is different in your answer?
    – Burgi
    May 31, 2016 at 8:02
  • 5
    @Burgi - this answer gives more detail about the syntax of ssh-keygen -R than any of the other answers so far. It show by example exactly what you can write after -R. So this answer is worthwhile, even though it is not a totally new answer.
    – Yitz
    Dec 25, 2017 at 9:03
  • @Yitz My comment was made as part of review. At the time (18 months ago) I thought the question needed a little help to make it even better.
    – Burgi
    Dec 25, 2017 at 23:01
  • Seems it doesn't work if some of the hosts are on the different port than 22.
    – PocketSam
    Dec 1, 2022 at 12:02
31

All answers are good, but for real SSH pro we have missing information how to remove ssh signature with (non-standard) port number.

  • Simple SSH host signature remove command:

      ssh-keygen -R example.com
    
  • Complex ssh key remove, e.g. you connect to ssh on non standard port 222:

      ssh example.com -p 222
    

and you get warning, and to remove this, you need to use square brackets colon port number:

    ssh-keygen -R [example.com]:222

Note, that probably there will be IP record for the same host, so you will need to remove that one also.

Hope this helps for non-standard configuration users.

0
20

The warning will tell you the exact line in the known hosts file.

Here's an example:

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@       WARNING: POSSIBLE DNS SPOOFING DETECTED!          @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
The RSA host key for foo-bar.net has changed,
and the key for the corresponding IP address 127.0.0.1
is unchanged. This could either mean that
DNS SPOOFING is happening or the IP address for the host
and its host key have changed at the same time.
Offending key for IP in /home/user/.ssh/known_hosts:6
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!

See the /home/user/.ssh/known_hosts:6 part? It specifies the file and line number.

0
10

You can also instruct ssh to not check the known_hosts file using the UserKnownHostsFile and StrictHostKeyChecking flags.

For instance:

ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no [email protected]

For ease of use you can alias this:

alias boldssh='ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no'

Now you can just boldssh whenever you are sure you trust the server's certificate.

3
  • 11
    What a horrible idea. Permanently disable a layer of security just because you're too lazy keeping your ~/.ssh/known_hosts up-to-date? Why not just go ahead and use telnet? "whenever you are sure" - if you are ever sure, then you have no idea what a MITM attack is and you should probably spend some time reading some good literature.
    – kraxor
    Jun 27, 2014 at 12:02
  • 3
    Based on the OP's question I think this is a valid answer. Sometimes you have a test system that you're creating/destroying a lot of VMs on. (I'm doing this right now as I prep for the RHCE exam.) There might not be any security implications. While noting the security implications is great, I don't think this has to be labeled a "horrible idea". Oct 1, 2015 at 19:54
  • related: superuser.com/a/1126243/73961
    – michael
    Sep 20, 2016 at 9:31
2

Here is a method using Ex editor:

ex +6d -scwq ~/.ssh/known_hosts

where 6th is your line number mentioned in the warning message. Such as this one:

Offending key for IP in /home/user/.ssh/known_hosts:6 <== LINE NUMBER


In general, it's advised to use ex to edit the files non-interactively, instead of sed, which is more a Stream EDitor and its -i parameter which is a non-standard FreeBSD extension.

1
  • This might be the breakthrough I need to use vim as a true Unix filter, I've been tearing my hair out trying to get it working. Note to self:vim -e = ex Aug 10, 2022 at 21:57
0

The entry for the host name or ip should be in the first column. The warning should also list a line number where the offending key lies.

0

You can also remove a single line from known hosts with e.g. rmknownhost 111 (111 is the line to remove):

#! /usr/bin/env ruby
line = ARGV[0] || raise("gimme line to remove")
hosts = File.expand_path("~/.ssh/known_hosts")
content = File.readlines(hosts)
removed = content.delete_at line.to_i - 1
puts "Removed:\n#{removed}"
File.open(hosts, 'w'){|f| f.write content * ""}

Save this as rmknownhost in a folder from your PATH.

5
  • 1
    What's the benefit of this over doing it in any given text editor? Is there some reason not to do it that way, like how sudoers has to be edited with visudo? Jun 22, 2010 at 16:37
  • What distros come with this? Ubuntu doesn't seem to have it.
    – flickerfly
    Jul 19, 2013 at 13:54
  • The benefit is that it's automated and quick / it's a separate binary you add yourself
    – grosser
    Jul 20, 2013 at 15:17
  • 2
    You could have just posted your script here instead of linking your own blog entry that you created on the day you posted this answer. This qualifies as spam IMHO. Not to mention that you could create a simple alias to achieve the same result, no need for a 7 lines long ruby script.
    – kraxor
    Jun 27, 2014 at 12:08
  • 1
    or just add this to your ~/.bashrc: sshdel() { sed -i "${@}d" ~/.ssh/known_hosts; } and call it with sshdel [line number]. no ruby, no binary, no worries. Sep 24, 2019 at 17:19
0

It is a text file. You can easily edit with vi(m) and simply delete the line in question (dd), and save the file (wq). But if there is a specific command to remove a host, that's probably the safest method.

2
  • I don't see how editing the file directly in VIM is "unsafe". It's based on your comfort level with VIM. Especially with this file, the biggest risk you have is deleting too many keys, in which case you'll just get prompted again. Oct 1, 2015 at 19:56
  • The "safety" I was referring to involves 1) forgetting/not knowing to remove dependent info in other files (if any) and 2) Accidentally deleting more or less than needs to be, thus breaking the file. Oct 2, 2015 at 18:41

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .