SSHFP records: DNS providing public ssh host keys

Introduction

I recently learnt (Thanks Jacomo!) that public parts of ssh host keys can be put in the DNS system, using SSHFP record.

Here are a few notes on this topic.

Having ssh-keygen propose SSHFP record content

ssh-keygen -r hostname [-f public-key-file]  proposes a complete zone file line for hostname:

test -f /etc/ssh/ssh_host_rsa_key.pub && ssh-keygen -r www -f /etc/ssh/ssh_host_rsa_key.pub
test -f /etc/ssh/ssh_host_dsa_key.pub && ssh-keygen -r www -f /etc/ssh/ssh_host_dsa_key.pub
test -f /etc/ssh/ssh_host_ecdsa_key.pub && ssh-keygen -r www -f /etc/ssh/ssh_host_ecdsa_key.pub

Unfortunately, ssh-keygen -r is usually one algorithm behind ssh-keygen, therefore we usually use the openssl method shown in the next paragraph.

Manual extraction of SSHFP records contents from /etc/ssh/ssh_host_*_key.pub

To generate the values for the SSHFP records of a host, use these commands:

HN=$(hostname -s)
I="1"
for ALGO in rsa dsa ecdsa ; do
  if [ -f /etc/ssh/ssh_host_${ALGO}_key ] ; then
    echo -n "$HN SSHFP $I 1 " ; awk '{print $2}' /etc/ssh/ssh_host_${ALGO}_key.pub | openssl base64 -d -A | openssl sha1   |cut -f2 -d' '
    echo -n "$HN SSHFP $I 2 " ; awk '{print $2}' /etc/ssh/ssh_host_${ALGO}_key.pub | openssl base64 -d -A | openssl sha256 |cut -f2 -d' '
  fi
  I=$(($I+1))
done

Telling ssh to respect SSHFP records

In /etc/ssh/ssh_config or ~/.ssh/config or with -o set the VerifyHostKeyDNS option to yes::

VerifyHostKeyDNS yes

Values are:

  • yes: trust keys that match the SSHDS record
  • ask: check the SSHDS record and display the result, but still ask whether the key is to be trusted
  • no (default): do not check SSHDS records at all

Depending on the value of StrictHostKeyChecking untrusted keys are refused (yes), asked (ask), or accepted with a fat warning (no).

Retrieving records

To retrieve SSHFP records "raw", dig it:

dig www.clazzes.org SSHFP

OpenSSH Options to use SSHFP records

To turn on SSHFP activities, VerifyHostKeyDNS must be set to ask or yes.

Consider setting StrictHostKeyChecking to ask or yes, too.

Due to a lack of trust into the DNS system, and propably to avoid parsing OS-specifics like resolv.conf, up until recently one had to use full canonical hostname for the SSHFP check to match. The following paragraph describes the solution introduced with OpenSSH 6.5.

OpenSSH 6.5 to allow using non-canonical hostnames

From OpenSSH 6.5 on (Debian: wheezy-backports) it's possible to enable canonicalization by the ssh client.

Here is a list of the Canonical* options of OpenSSH 6.5, with default values leading the paragraphs and my example values afterwords:

#CanonicalDomains
CanonicalDomains internal.site.mydomain.foo mydomain.foo partners.mydomain.foo 
# should comply with search list in /etc/resolv.conf, otherwise confusion might arise

#CanonicalizeFallbackLocal no
CanonicalizeFallbackLocal yes

#CanonicalizeHostname no
CanonicalizeHostname yes
# do not use 'always' when using a IPv4 DNAT firewall to reach multiple hosts behind it, separated by port
#CanonicalizeHostname always

CanonicalizeMaxDots 1

CanonicalizePermittedCNAMEs *.mydomain.foo:*

This approach should only be used if the nameservers can be trusted, i.e. you only use your own well-managed DNSes or the domains are protected by DNSSEC.

Further reading