SSHFP Records on Windows Server

SSHFP records are a vital part of securing SSH. However, Microsoft's DNS Server doesn't give us an easy way to add them. Here's how.

Written .

A Review of SSH Fingerprints

SSH servers all have fingerprints to identify themselves. These little hashes of the host's public key are exchanged with clients, and remembered in a Trust On First Use (TOFU) model.

The authenticity of host ' (2001:db8::49)' can't be established.
ED25519 key fingerprint is SHA256:1z0nm0KwN5cnOSA9HQ0VzjUR9VaPUd+/tB5FtTB1NdQ=.
No matching host key fingerprint found in DNS.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])?
The default OpenSSH warning when connecting to an unknown server.

Now, let's be honest. SSH is an incredibly high-value target, but how many of us have actually taken the time to manually verify an SSH key? Raise your hands. Yeah, I'm not raising mine, either.

TOFU is a decent security model, because it protects all connections to the server — except for the very first one.

You might have noticed that there is a line up there that reads, No matching host key fingerprint found in DNS. Longtime Linux might know about the SSHFP DNS record, defined way back in RFC 4255. Adding one to a standard DNS server such as BIND9 is as simple as making the records and copying them into your zone file.

# ssh-keygen -r myservername | tee ssh-keys.txt
myservername IN SSHFP 1 2 d73d279b42b037972739203d1d0d15ce3511f5568f51dfbfb41e45b5307535d4
myservername IN SSHFP 3 2 95941914e0c29ca8a104bf4b6c8890c7c172f7ce610bc331ea6aab1537852ead
myservername IN SSHFP 4 2 6c0461c9809836eb61b0e3a07b31a99522452a7e28499a39aa8423a17b8e2f2a
# ssh-keys.txt >> /etc/bind9/myzonefile.dns
SSHFP records can be generated with the ssh-keygen command, and appended to your zone file. None of this is new. (I'm using tee so we have something to look at.)

If you're lucky enough to be using the BIND DNS server, congratulations! Your work is done. However, if this was all I was writing about, it wouldn't make for a useful article.

Microsoft in the Mix

However, some of us administer networks, which sometimes means that Active Directory Domain Services (AD DS) is in the mix; and, if that be true, then one would be foolish not to use the Microsoft DNS Server alongside that. Though it lags far behind BIND in terms of feature and resource record support, it does provide a GUI (albeit dated) and a robust module.

While it does not support SSHFP records natively, the DNS Server included with all versions of Windows Server will at least accept, store, and serve SSHFP records. The problem, though, is how to get them saved, as neither the GUI nor the PowerShell cmdlets will let you input one. (Neither will dnscmd, but that thing is deprecated, anyway.)

You might be wondering, though. What is the point of storing SSHFP records when you have a Windows-centric network? Simple: you gain the same benefits.

  • If you have or machines on your network, they likely have SSH servers running.
  • Your firewall, switches, and VMware hosts might have SSH daemons running, too. Even if they only run some of the time, you can still have DNS-level protection.
  • Notably, the OpenSSH Server is an installable feature in Windows 10, Windows 11, Windows Server 2019, and Windows Server 2022; with backports available for downlevel versions. (This may also be the replacement for PowerShell Remoting if WinRM ever becomes deprecated.)

Here's How

Check Your DNS Server

You will need to be running Windows Server 2012 or later. While this should work with any version of the Microsoft DNS Server, both the RFC — and common sense — strongly recommend you use DNSSEC to secure these records.

If you are running Windows Server 2008 R2 or older, stop right here and evaluate your personal and professional life decisions. Not only has been out of extended support for , but its DNSSEC implementation is rudimentary at best.

Gather Your Fingerprints

You will need to gather the SSH fingerprints for all of your hosts. You can log on and run ssh-keygen -r to generate them interactively, or for things like printers and other network devices, a tool like ssh-keyscan can read them remotely.

Download the BIND9 Tools

If you have a macOS or Linux machine with the nsupdate tool on there, you can skip this section. Otherwise, download the BIND9 Tools for Windows to obtain a copy of nsupdate.exe, which will allow us to spit arbitrary DNS records into our zone.

You can also use PowerShell to download and install the BIND9 Tools. This is useful if you want to script this, or if you're lucky enough to be running a headless version of Windows Server.
Set-Location $env:Temp
Invoke-WebRequest -OutFile '' -Uri ''
Expand-Archive -Path ''

Create the NSUpdate Command

The nsupdate tool has its own syntax. You can copy and paste all of the hostnames and fingerprints that you've gathered from across your network, and combine them into one big Notepad document.

You can also use this PowerShell to turn your ssh-keygen -r output into a file that can be used by nsupdate (here is a barebones example):

# Edit this next line with the name of your DNS zone!
$MyDomainName = ''

$sshfp = ''
Get-Content 'Output of ssh-keygen -r.txt' | ForEach-Object -ScriptBlock {
     # Each line of the input file will need to be modified to add some more items. It must be prefixed with "update add" and have a TTL inserted after the hostname (even though the DNS zone will likely override it).
     $x = $_ -Split "[\t\s]"
     $sshfp += "update add $($x[0]).$MyDomainName 3600 $($x[1..5]).`r`n"

# Prepare the NSUpdate command.
$NSUpdateCommand = "server $DNSServer
zone $MyDomainName
This PowerShell code can be used to convert ssh-keygen -r output into something nsupdate can understand.

Relaxing Zone Security (For a Few Seconds)

Security-conscious people might be thinking that using freeware to inject random DNS records is a very bad thing, and they are correct. Fortunately, by default, Windows-hosted zones default to only allowing secure dynamic updates (authenticated by Kerberos). To accomplish our goal, we will need to temporarily relax security rules.

  1. In the DNS snap-in, right-click your zone and choose Properties.
  2. Under Dynamic Updates, choose Secure and Nonsecure.
  3. Click OK.
Microsoft DNS Server's zone properties, showing the selections for the security drop-down:  Secure, Secure and Nonsecure, Disabled. Set-DnsServerPrimaryZone -Name $MyDomainName -DynamicUpdate 'NonsecureAndSecure'
Temporarily set your zone update settings to allow secure and non-secure updates, but don't forget to change it back later. You can point and click, or use PowerShell.

Now, don't linger, since we've left our zone open to exploit.


Now for the coup de grâce. You can copy and paste your file directly into nsupdate.exe. Alternatively, if you've been following along with my PowerShell commands, you can simply do this:

$NSUpdateCommand | .\nsupdate.exe
Send the last code block's work into nsupdate.exe.

Before you celebrate, we need to restore safety and sanity; either skip back a section and undo your changes, or run this PowerShell command:

Set-DnsServerPrimaryZone -Name $MyDomainName -DynamicUpdate 'Secure'
Please do not leave gaping security holes in your infrastructure.

Verifying Your Work

Once this is done, you will see some unknown records listed in your list of DNS entries:

Microsoft DNS Server's zone entries, showing the SSHFP
									records.  They show up as an unknown type because the DNS Server service is an
									afterthought to Microsoft.  Don't even get me started on TLSA.
This is what you'll see in your DNS zone. For this example, I had created a fictional DC, and these are the SSHFP records that I just assigned in the previous section.

Unfortunately, because Microsoft's DNS Server service lags so far behind the curve, you will not be able to edit or properly view the record. Just be happy we got this far. You can, though, double-click on it and view the raw binary data, for what that's worth:

Microsoft DNS Server showing an "unknown"
									(SSHFP) record.  They show up uneditable because the DNS Server service is an afterthought
									to Microsoft.  Don't even get me started on TLSA.
This is what you'll see if you view the record properties (only available on Windows Server 2016 and newer). There is nothing useful to see here, but it's better than the literal nothing you'd see in Server 2012 and older.

Let's Try It

Now that your SSHFP DNS records are live (and hopefully secured), let's try connecting again. If your records are present and correct, you will see output like this.

The authenticity of host ' (2001:db8::49)' can't be established.
ED25519 key fingerprint is SHA256:1z0nm0KwN5cnOSA9HQ0VzjUR9VaPUd+/tB5FtTB1NdQ=.
Matching host key fingerprint found in DNS.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])?
There we go! Now the host key is verified.

It's a bit of a roundabout method, unfortunately. It would be great if Microsoft's DNS Server gave us an easier way to add and modify SSHFP records (and DANE/TLSA records, for that matter). However, this will work, and this will help you secure your internal environment.

Finally, bookmark this page. This isn't a shameless plug, but a warning that, as you replace devices or regenerate SSH host keys, you will need to regenerate your SSHFP records.


RFC 4255: Using DNS to Securely Publish Secure Shell (SSH) Key Fingerprints
BIND9 Tools for Windows