DNS-based SSH host key verification

Thu, 2017-12-14 16:06

SSH is a pretty clever connection mechanism that enables clients and server to verify each other. For the most part, the client (users) are verified properly, but there is very little effort from the client to verify the server. By default, SSH clients connect to the server, and record the server's public key fingerprint. If the fingerprint has changed later, client will bail out with a big scary warnings with ALL CAPS and exclamation marks!!! This guarantees that the server you are about to connect to is the same one that you have first connected with.

What about the first connection, though? When you first connect to the server, your SSH client has no information about the server, so it asks you if the fingerprint is correct. There is a way to hint your SSH client about the server key: DNS. Certificate Authority Authorization (CAA) relies on DNS to publish a list of Certificate Authorities that are authorized to issue TLS certificates. TLSA can publish information about certain PKI key information. There is also a record type, Secure SHell Finger Print, or SSHFP, that can publish the server's SSH key fingerprint so the client can verify the server key's authenticity.

DNSEC

By default, DNS queries are sent and received without encryption or authentication. While we don't have encryption widely available yet, we can authenticate DNS queries. I'm not going to cover DNSSEC in this post, but do note that you should enable DNSSEC first. DNSSEC is supported in many DNS servers nowadays, and many recursive DNS servers can properly validate them.

Without DNSSEC enabled, your SSH client will keep asking if you trust the provided server key.

Key types (optional)

As of today, OpenSSH, the most popular SSH server, supports RSA, DSA, ECDSA and Ed25519 keys. I ruled out RSA and DSA because the key sizes are small and they are old mechanisms. The cryptography community has some doubts about the ECDSA, so I ruled that out too. Ed25519 is the newer protocol, and because my current keys are Ed25519 anyway, so I thought to restrict the SSHFP records to just Ed25519 key.

You can generate the SSHFP records just for the Ed25519 key, or better yet disable RSA, DSA, and ECDSA altogether. Edit your /etc/ssh/sshd_config file and remove the lines starting with HostKey directive referring to non-Ed25519 keys. Move the public and private keys to somewhere else so there is only one Ed25519 key pair and no other types in /etc/ssh directory.

You have to keep the key types that you and everyone else use to log into the server (including rsync, git, etc). If you are not sure, it's better you skip this part.

Generate SSHFP records

There is a handy command to generate the SSHFP records. Type in ssh-keygen -r <your-domain-name> and the magic of ssh-keygen command will print the necessary DNS records that you have to put into your DNS server.
If you have multiple key types, and want to limit SSHFP records to a certain set of keys, you can do so with the -f option. For example, ssh-keygen -r <your-domain-name> -f /etc/ssh/ssh_host_ecdsa_key.pub will print the SSHFP records for the public key /etc/ssh/ssh_host_ecdsa_key.pub.

The output would look like this:

example.com IN SSHFP 4 1 1b69784a17572ee7e850107f6b3052699a953ad3
example.com IN SSHFP 4 2 b11000d176792edf9c7645aebb2ccdd4a6eb0cf856cadcb6b82ee18e333bef13

example.com IN is part of the BIND and BIND-like DNS record syntax. If you are using any other DNS provider, the part after SSHFP is what you should copy-pasta.

The record type is pretty basic. It's [Algorithm] [Fingerprint type] [Hex fingerprint].

Algorithm
1.RSA
2.DSA
3. ECDSA
4. Ed25519
In out case, key is Ed25519 so the value is 4.

Fingerprint type
1 - SHA-1
2 - SHA-256
Almost every client will look up the SHA-256, but it's good to have the SHA-1 finger print as well, god forbid anyone still uses SHA1 for this. For the example above, we have 1 and 2 both.

Fingerprint in Hex
This is the actual fingerprint, hex-encoded.

Once you have the DNS records, add them in your DNS server. Not all DNS servers support SSHFP servers. Most notably, AWS Route53 does not. If your DNS provider does not support SSHFP records, it's tough luck for you.

Client configuration

Your SSH client must support SSHFP record lookup. OpenSSH client does, and it needs the configuration VerifyHostKeyDNS yes under your connection particulars or global configuration. Ideally, this can go to your ~/.ssh/config file, right under the Host *.

Host *
  User root
  VerifyHostKeyDNS ask

See if it's working

Without DNS authentication
When you do not have SSHFP setup, or the client not looking them up, you will see an output like the following. This is how it always will be unless you have SSHFP DNS-based authentication.

The authenticity of host '[example.com]:22 ([111.222.111.222]:22)' can't be established.
ED25519 key fingerprint is SHA256:sRAA0XZ5Lt+cdkWuuyzN1KbrDPhWyty2uC7hjjM77xM.
Are you sure you want to continue connecting (yes/no)?

With SSHFP added, but no DNSSEC
When you have SSHFP records, and client lookup enabled, client will still show the "authenticity can't be established" message if the DNS query was not DNSSEC-signed. This is also the case for Windows because it current OpenSSH implementations for Windows do not support DNSSEC checks yet.

You can also set your your ~/.ssh/config file setting VerifyHostKeyDNS ask to force trigger this question even if DNSSEC is used.

The authenticity of host '[example.com]:22 ([111.222.111.222]:22)' can't be established.
ED25519 key fingerprint is SHA256:sRAA0XZ5Lt+cdkWuuyzN1KbrDPhWyty2uC7hjjM77xM.
Matching host key fingerprint found in DNS.
Are you sure you want to continue connecting (yes/no)?

With SSHFP added, and DNSSEC enabled
When you have SSHFP records added, and DNSSEC enabled, your client will proceed without any prompts or warnings 😍.

With DNS authentication, possible MitM attack 😨
When you have an SSHFP record setup, and when something shady is going on (someone else is pretending be your server, or perhaps a misconfiguration :( ), SSH client will show its classic big scary warning:

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    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 ED25519 key sent by the remote host is
SHA256:sRAA0XZ5Lt+cdkWuuyzN1KbrDPhWyty2uC7hjjM77xM.
Please contact your system administrator.
Update the SSHFP RR in DNS with the new host key to get rid of this message.
The authenticity of host '[example.com]:22 ([111.222.111.222]:22)' can't be established.
ED25519 key fingerprint is SHA256:sRAA0XZ5Lt+cdkWuuyzN1KbrDPhWyty2uC7hjjM77xM.
No matching host key fingerprint found in DNS.
Are you sure you want to continue connecting (yes/no)?

kthxbye