I need to setup SSHFP records in the DNS for my host. I have done some searching but I haven't found any good example.
- What are SSHFP records?
- What does SSHFP records look like?
- How do I create SSHFP records?
SSHFP records are DNS records that contain fingerprints for public keys used for SSH. They're mostly used with DNSSEC enabled domains. When an SSH client connects to a server it checks the corresponding SSHFP record. If the records fingerprint matches the servers, the server is legit and it's safe to connect.
SSHFP records consist of three things:
There are five different algorithms defined in SSHFP as of 2021. Each algorithm is represented by an integer. The algorithms are:
Two fingerprint types are defined in SSHFP as of 2012. Each fingerprint type is represented by an integer. These are:
You can use ssh-keygen locally to generate the records using the -r
parameter, followed by the hostname (which does not affect the fingerprints so you can specify whatever you like instead).
You can use ssh-keyscan to generate records for a remote server using the -D
parameter, followed by the hostname.
Using ssh-keygen
and CentOS:
[root@localhost ~]# ssh-keygen -r my.domain.com
my.domain.com IN SSHFP 1 1 450c7d19d5da9a3a5b7c19992d1fbde15d8dad34
my.domain.com IN SSHFP 2 1 72d30d211ce8c464de2811e534de23b9be9b4dc4
Sometimes ssh-keygen
will ask for the location of the public certificate. If it asks, you will have to run ssh-keygen
multiple times and every time specify a different certificate to make sure that you generate all necessary SSHFP records. Your public keys are usually located in /etc/ssh
.
ssh-keygen -r
also handles ed25519 type records (using the experimental number 4 from iana iana.org/assignments/dns-sshfp-rr-parameters/… )
Commented
Jan 28, 2015 at 16:11
I'm not sure if ssh-keygen
works with existing keys. If not you still can easily assemble them in your shell (which I prefer), and without fancy software or remote interfaces.
A records such as mentioned...
my.domain.com IN SSHFP 2 1 72d30d211ce8c464de2811e534de23b9be9b4dc4
...exist of 6 parts:
part 1: hostname
part 2: Usually "IN" for internet
part 3: "SSHFP", the RR name for type 44
part 4: RSA keys = "1"
DSA keys = "2"
ECDSA keys = "3"
Ed25519 keys = "4"
Ed448 keys = "6"
part 5: The algorithm type:
SHA-1 = "1"
SHA-256 = "2"
part 6: You can generate, for example:
$ awk '{print $2}' /etc/ssh/ssh_host_dsa_key.pub | \
openssl base64 -d -A | openssl sha1
To make use of it, put VerifyHostKeyDNS ask
in your SSH client's config, usually ~/.ssh/config
.
ssh-keygen -r
does generate SSHFP records for existing keys despite the fact that the name of the command suggests it's only for GENerating.
Older versions of ssh-keygen don't generate all the available keys (eg. no support for ecdsa and sha256). This script does creates all the records for all available keys in /etc/ssh/
:
#!/bin/bash
#
# Creates SSHFP Records for all available keys
#
HOST="${1-$(hostname -f)}"
if [[ "$1" == "-h" || "$1" == "--help" ]]
then
echo "Usage: sshfpgen <hostname>"
fi
if which openssl >/dev/null 2>&1
then
if ! which sha1sum >/dev/null 2>&1
then
sha1sum() {
openssl dgst -sha1 | grep -E -o "[0-9a-f]{40}"
}
fi
if ! which sha256sum >/dev/null 2>&1
then
sha256sum() {
openssl dgst -sha256 | grep -E -o "[0-9a-f]{64}"
}
fi
fi
for pubkey in /etc/ssh/ssh_host_*_key.pub /etc/ssh_host_*_key.pub
do
case "$(cut -d _ -f3 <<< "$pubkey")"
in
rsa)
echo "$HOST IN SSHFP 1 1 $(cut -f2 -d ' ' "$pubkey" | base64 --decode | sha1sum | cut -f 1 -d ' ')"
echo "$HOST IN SSHFP 1 2 $(cut -f2 -d ' ' "$pubkey" | base64 --decode | sha256sum | cut -f 1 -d ' ')"
;;
dsa)
echo "$HOST IN SSHFP 2 1 $(cut -f2 -d ' ' "$pubkey" | base64 --decode | sha1sum | cut -f 1 -d ' ')"
echo "$HOST IN SSHFP 2 2 $(cut -f2 -d ' ' "$pubkey" | base64 --decode | sha256sum | cut -f 1 -d ' ')"
;;
ecdsa)
echo "$HOST IN SSHFP 3 1 $(cut -f2 -d ' ' "$pubkey" | base64 --decode | sha1sum | cut -f 1 -d ' ')"
echo "$HOST IN SSHFP 3 2 $(cut -f2 -d ' ' "$pubkey" | base64 --decode | sha256sum | cut -f 1 -d ' ')"
;;
ed25519)
echo "$HOST IN SSHFP 4 1 $(cut -f2 -d ' ' "$pubkey" | base64 --decode | sha1sum | cut -f 1 -d ' ')"
echo "$HOST IN SSHFP 4 2 $(cut -f2 -d ' ' "$pubkey" | base64 --decode | sha256sum | cut -f 1 -d ' ')"
;;
ed448)
echo "$HOST IN SSHFP 6 1 $(cut -f2 -d ' ' "$pubkey" | base64 --decode | sha1sum | cut -f 1 -d ' ')"
echo "$HOST IN SSHFP 6 2 $(cut -f2 -d ' ' "$pubkey" | base64 --decode | sha256sum | cut -f 1 -d ' ')"
;;
esac
done
Edit: New Version with PR from alex-dupuy with *BSD support.
This is how I'm getting my SSHFP records through Ansible:
- name: Capture the SSHFP entries
shell: "ssh-keygen -r {{ ansible_nodename }}|awk '{print $4, $5, $6}'"
register: sshfp_entries
If you use Puppet, facter
has built in support for sshfp
. Plus if you are using PuppetDB you can easily extract this info for all your hosts.
facter | grep -i sshfp
sshfp_dsa => SSHFP 2 1 e1a3e639d6dbd48d3964ebfb772d2d11f1065682
SSHFP 2 2 4f620ce2bc97d91ae5eff42fba621d65b677ab725f275f56b2abd1303c142b73
sshfp_rsa => SSHFP 1 1 a78351af371faf3f19533c3a4a9e967543d7d2f5
SSHFP 1 2 795943a6ee8b53c818cfef5781209e25a6eb4bc386813db60d3ff2c1569692fc
This one works even better:
Source: https://weberblog.net/generating-sshfp-records-remotely/
# Source: https://gist.github.com/webernetz/2ca7325555ce7f28f26daf5728386d82
wget https://gist.githubusercontent.com/webernetz/2ca7325555ce7f28f26daf5728386d82/raw/1c18dc43a05478771ac4693401a3c78205a4e710/grabsshfp.sh
chmod u+x grabsshfp.sh
# Run it (will check: rsa dsa ecdsa ed25519)
weberjoh@nb15-lx:~$ ./grabsshfp.sh pa-mgmt
pa-mgmt IN SSHFP 1 1 4addde64e14a19e6a2286ca422ca0b9bd322c31d
pa-mgmt IN SSHFP 1 2 ca0acaa29d0cb233b2a715be3217a91002efe87d7e28bd51314b1feef203c5a7