I just did some let's encrypt magic so that both of the Windows Machines on my LAN that I RDP into have real, legitimate, let's encrypt certs for their respective FQDNs. I need to provide a little bit of background on how I manage certificates first.

I use Let's Encrypt. It's awesome. I haven't had to manually renew a cert in years, occasionally I've gone long enough between nginx reloads that the old cert that Nginx is holding on to will expire... But otherwise, I haven't manually done anything for Cert Upgrades in a while.

I use DNS validation, and cloudflare for all my DNS. I use Dehydrated as a Let's Encrypt client, but I've made a small change to the Cloudflare Hook, which you can see here - I have a directory for installation hooks, and if there's an executable file in that directory with the name of the cert that was just generated, it will run that script. See the hooks I have here.

Alright, the next step is to install OpenSSH server on windows.

Yes. you read that right.

Open SSH Server. On Windows.

Here's the official docs, but also here's the tl;dr:

# install openssh server.
Get-WindowsCapability -Online | ? Name -like 'OpenSSH*'
Add-WindowsCapability -Online -Name OpenSSH.Server~~~~

# Start and enable the service
Start-Service sshd
Set-Service -Name sshd -StartupType 'Automatic'

# Set the default shell to powershell
New-ItemProperty -Path "HKLM:\SOFTWARE\OpenSSH" -Name DefaultShell -Value "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -PropertyType String -Force

Next, to get ssh certs to work right, you have to edit the sshd_config at C:\ProgramData\ssh\sshd_config - take out the lines at the end about "admin authorized_keys" - it's the last 3-ish lines of the file. (Sorry, I don't have the original config in front of me)

Do a Restart-Service sshd and you should be able to ssh into your windows machine with a key. (Public Keys go in C:\Users\{USERNAME}\.ssh\authorized_keys, exactly as you'd expect)

Actually installing certs for RDP

First off, here's my cloudflare hook for installing certs for RDP. I'll explain a bit more about how it works below:

The first thing to do is to generate a p12:

p12_path=/path/to/your/p12_output/fileopenssl pkcs12 -in fullchain.pem -inkey privkey.pem -export -password pass:verysecret -out $p12_path

After this, you'll need to SCP it over to windows. After it's on windows, you'll need to load it into the windows LocalMachine certificate store, and tell RDP to use it.

# load the cert 
$pass = ConvertTo-SecureString -string 'verysecret' -AsPlainText -Force
$thumb = (Import-PfxCertificate -Password $pass -filepath C:/ProgramData/Certs/$p12_filename -CertStoreLocation Cert:\LocalMachine\My).Thumbprint

# use WMI to tell the RDP service to use the new certificate
$tsgs = gwmi -class "Win32_TSGeneralSetting" -Namespace root\cimv2\terminalservices -Filter "TerminalName='RDP-tcp'"
swmi -path $tsgs.__path -argument @{SSLCertificateSHA1Hash="$thumb"}

All of this is done by scping over a powershell file and executing it on the remote windows box, from within a hook that gets executed every time LE issues a new cert.

It's magic. Never going back to "oh crap my certs are expired, gotta get new ones" as long as I can help it.