SSH, Vagrant and Private Key -> Host mapping
I've been using a lot of different Linux systems (Linuxes?) lately so it's been a case of Vagrant to the rescue… however, there's a problem. Great as Vagrant is, and it is, the problem is that I'm working with multiple Vagrant instances that I need to
ssh into… directly (because Ansible) and this causes issues with
ssh and my
Why Ansible? Well to install and configure different Swift builds on different platforms
The biggest bug bears are different private keys for each Vagrant instance and multiple entires with different host fingerprints for the same
host with unique keys
The first problem is simple to fix, for each Vagrant instance we create a
Host entry in
~/.ssh/config. The config file saves you a lot of time and brain space by letting you setup a
Host definition that you can use anywhere
ssh is used (like
rsync or Ansible).
Back to our problem, for each Vagrant instance we can define a seperate
Host entry that includes a useful alias, the username to log in with, the port to ssh to and the location of the private key to use, something like this:
#Development IdentitiesOnly=yes #Vagrant instance in Development/Websites Host localweb HostName localhost Port 2222 User vagrant IdentityFile ~/Development/Websites/.vagrant/machines/default/virtualbox/private_key #Vagrant instance in Development/Ansible Host localansible HostName localhost Port 2223 User vagrant IdentityFile ~/Development/Ansible/.vagrant/machines/default/virtualbox/private_key #Vagrant instance in Development/SwiftServer Host localswift HostName localhost Port 9001 User vagrant IdentityFile ~/Development/SwiftServer/.vagrant/machines/default/virtualbox/private_key
N.B. Different ports are only needed for each instance if you intend on having more than one running at the same time.
Now that the first issue is resolved, it's clear I've not explained the second problem very well… maybe an example will help. In the following snippet I'm
ssh'ing into a CentOS Vagrant instance… using specific port and identity parameters.
me:CentOS7: ssh firstname.lastname@example.org -p 2222 -i .vagrant/machines/default/virtualbox/private_key @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @ 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 RSA key sent by the remote host is SHA256:EDR3Dex/fIdTsB4Siewx+wiXVho+fxAFl/18yLE89ss. Please contact your system administrator. Add correct host key in /Users/me/.ssh/known_hosts to get rid of this message. Offending RSA key in /Users/me/.ssh/known_hosts:114 RSA host key for [127.0.0.1]:2222 has changed and you have requested strict checking. Host key verification failed. me:CentOS7:
The reason this error is being thrown is because I have previously used almost the identical settings to
ssh into a Ubuntu instance, which of course has a different key associated with it.
So the problem is that a line in the
~/.ssh/known_hosts matches the current request (erroneously but anyway) based on the host identity. If you
know_hosts file you'll see that each line starts with a host identity, a space and then the host key signature… similar to these:
[127.0.0.1]:2222 randomletters+thatarethekeyfingerprintiidentifyingthehost [127.0.0.1]:8080 randomlettersthat+arethekeyfingerprintiidentifyingthehost [::1]:8080 randomlettersthat+arethekeyfingerprintiidentifyingthehost localhost:2222 randomlettersthatare+thekeyfingerprintiidentifyingthehost
As you can see these are all references to the
loopback interface (i.e. the local computer), this is a problem because the entries are added sequentially and the lookup isn't that smart for resolving if the host you're connecting to is actually known… As far as I can tell it stops on the first match so when you're running multiple virtual machines with similar configurations on your local computer, you will eventually hit this problem.
In the error above, on line 114, it finds a match for a host at
127.0.0.1 it's just not the right match for that host.
Before you read any further — remember this solution is only for your local development machine and these configuration changes should not be used on anything else, definitely not on a production, staging or QA system.
My first thought was to find a way to set things up so the correct match was made (in this case on line 116) — but that's not possible.
It turns out the solution for this type of development issue is pretty straight forward, it's just that a little reverse thinking is required, which is why the solution isn't obvious.
Since we can't make it find the right entry in
known_hosts the trick is to make sure there isn't a match in the first place in a way that doesn't stop Ansible or whatever other tool we're using from working.
To this, we go back to that friend of SSH users everywhere, the config file. So, as you should know the
config file lets you setup hosts with all their unique attributes including user, port, identity file, hostname and a host alias (amongst many other things) Here's part of my
config, as an example:
#Development IdentitiesOnly=yes #Vagrant instance in Development/Websites Host localweb HostName localhost Port 2222 User vagrant IdentityFile ~/Development/Websites/.vagrant/machines/default/virtualbox/private_key UserKnownHostsFile /dev/null #Vagrant instance in Development/Ansible Host localansible HostName localhost Port 2223 User vagrant IdentityFile ~/Development/Ansible/.vagrant/machines/default/virtualbox/private_key UserKnownHostsFile /dev/null #Vagrant instance in Development/SwiftServer Host localswift HostName localhost Port 9001 User vagrant IdentityFile ~/Development/SwiftServer/.vagrant/machines/default/virtualbox/private_key UserKnownHostsFile /dev/null
As you can see I've defined three Vagrant instances that all point to my local machine (i.e.
HostName localhost) but I've given each a different alias (e.g.
Host localswift) and notably, different ports and the
IdentityFile is the one in each of the instances
.vagrant directory. So far all pretty basic stuff - so how do these configurations fix my problem?
Have a look at that last line for each
Host, this option is defined as follows:
Specifies a file to use for the user host key database instead of ~/.ssh/known_hosts.
The trick is to specify
/dev/null as the file to use — this works because the null device is a valid file descriptor or in Wikipedia's words "null device is device file"
So now the entries for the
::1 won't be added anywhere that can be checked and thus solving our original issue — but now we have another problem.
As a result of the
UserKnownHostsFile change, the ssh agent, rightly, stops everything and asks if it's OK to use this "new" host as because, hey, I don't have this fingerprint on file anywhere. So, when I
ssh localweb I (or Ansible or some other tool) has to interact with the ssh agent:
ssh localweb The authenticity of host '[localhost]:2222 ([127.0.0.1]:2222)' can't be established. ECDSA key fingerprint is SHA256:eUgqRdjBZBO61tKa3fLJwCAu5E2lOZEy+c1Xer/DOY8. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added '[localhost]:2222' (ECDSA) to the list of known hosts.
Ok, the solution is to actually tell ssh to not be so strict about hostkey fingerprints for this particular host. That's where the
StrictHostKeyChecking no option comes in. With that option added, you still get a warning but that's just sent to
stdout and it's easily ignored by you and tools like Ansible.
With this final option added our
Host configurations now look like this:
#Vagrant instance in Development/Websites Host localweb HostName localhost Port 2222 User vagrant IdentityFile ~/Development/Websites/.vagrant/machines/default/virtualbox/private_key StrictHostKeyChecking no UserKnownHostsFile /dev/null
and ssh only outputs a warning about the key being added to the list of
known_hosts, which is actually
$ ssh localweb Warning: Permanently added '[localhost]:2222' (ECDSA) to the list of known hosts. Welcome to Ubuntu 14.04.5 LTS (GNU/Linux 3.13.0-96-generic x86_64)
~/.ssh/configto define each of your virtual hosts
- In your
- Turn off strict host key checking for your newly defined
- SSH to the host alias defined in your