The ssh protocol uses two different keys to keep you secure:
The user ssh key is the one we normally think of. This
authenticates us to the remote host, proving that we are who we say we
are and allowing us to log in.
The ssh host key gets less attention, but is also important. This
authenticates the remote host to our local computer and proves that the ssh session is
encrypted so that nobody can be listening in.
Every time you see a prompt like the following, ssh is checking the
host key and asking you to make sure that your session is going to
be encrypted securely.
The authenticity of host 'ec2-...' can't be established.
ECDSA key fingerprint is ca:79:72:ea:23:94:5e:f5:f0:b8:c0:5a:17:8c:6f:a8.
Are you sure you want to continue connecting (yes/no)?
If you answer “yes” without verifying that the remote ssh host
key fingerprint is the same, then you are basically saying:
I don’t need this ssh session encrypted. It’s fine for any
man-in-the-middle to intercept the communication.
Ouch! (But a lot of people do this.)
Note: If you have a line like the following in your ssh config file,
then you are automatically answering “yes” to this prompt for every
# DON'T DO THIS!
Care about security
Since you do care about security and privacy, you want to verify
that you are talking to the right server using encryption and that no
man-in-the-middle can intercept your session.
There are a couple approaches you can take to check the fingerprint
for a new Amazon EC2 instance. The first is to wait for the console
output to be available from the instance, retrieve it, and verify that
the ssh host key fingerprint in the console output is the same as the
one which is being presented to you in the prompt.
Scott Moser has written a blog post describing how to verify ssh keys
on EC2 instances. It’s worth reading so that you understand
the principles and the official way to do this.
The rest of this article is going to present a different approach that
lets you in to your new instance quickly and securely.
Passing ssh host key to new EC2 instance
Instead of letting the new EC2 instance generate its own ssh host key
and waiting for it to communicate the fingerprint through the EC2
console output, we can generate the new ssh host key on our local
system and pass it to the new instance.
Using this approach, we already know the public side of the ssh key so
we don’t have to wait for it to become available through the console
(which can take minutes).
Generate a new ssh host key for the new EC2 instance.
tmpdir=$(mktemp -d /tmp/ssh-host-key.XXXXXX)
ssh-keygen -q -t ecdsa -N "" -C "" -f $keyfile
Create the user-data script that will set the ssh host key.
cat <<EOF >$userdatafile
cat <<EOKEY >/etc/ssh/ssh_host_ecdsa_key
cat <<EOKEY >/etc/ssh/ssh_host_ecdsa_key.pub
Run an EC2 instance, say Ubuntu 11.10 Oneiric, passing in the
user-data script. Make a note of the new instance id.
ec2-run-instances --key $USER --user-data-file $userdatafile ami-4dad7424
Wait for the instance to get a public DNS name and make a note of it.
Add new public ssh host key to our local ssh known_hosts after
removing any leftover key (e.g., from previous EC2 instance at same IP
ssh-keygen -R $host -f $knownhosts
ssh-keygen -R $(dig +short $host) -f $knownhosts
echo -n "$host "; cat $keyfile.pub
echo -n "$(dig +short $host) "; cat $keyfile.pub
) >> $knownhosts
When the instance starts running and the user-data script has
executed, you can ssh in to the server without being prompted to
verify the fingerprint
Don’t forget to clean up and to terminate your test instance.
rm -rf $tmpdir
There is one big drawback in the above sample implementation of this
approach. We have placed secret information (the private ssh host
key) into the EC2 user-data, which I generally recommend against.
Any user who can log in to the instance or who can cause the instance
to request a URL and get the output, can retrieve the user-data. You
might think this is unlikely to happen, but I’d rather avoid or
minimize unnecessary risk.
In a production implementation of this approach, I would take steps
like the following:
Upload the new ssh host key to S3 in a private object.
Generate an authenticated URL to the S3 object and have that URL
expire in, say, 10 minutes.
In the user-data script, download the ssh host key with the
authenticated, expiring S3 URL.
Now, there is a short window of exposure and you don’t have to worry
about protecting the user-data after the URL has expired.