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.
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.
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 |
In /etc/ssh/ssh_config
or ~/.ssh/config
or with -o set the VerifyHostKeyDNS option to yes
::
VerifyHostKeyDNS yes |
Values are:
Depending on the value of StrictHostKeyChecking
untrusted keys are refused (yes), asked (ask), or accepted with a fat warning (no).
To retrieve SSHFP records "raw", dig it:
dig www.clazzes.org SSHFP |
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.
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.