How to Configure a Let's Encrypt TLS Certificate for Windows Remote Desktop
Introduction
Windows Remote Desktop Protocol supports TLS security, which is one defensive layer to consider when hardening your Windows Server. This guide explains how to install a free Let's Encrypt TLS certificate, and configure it for Windows Remote Desktop. This guide assumes you do not have a web server running on port 80.
1. Configure DNS
Add a DNS A record for your Windows Server instance. This tutorial uses myserver.example.com.
2. Install Required Software
To manage the TLS certificates, you'll need to install several software packages. Several of these installation steps modify your path and environment variables, and you'll need to log out and back in to the server a few times during this process.
Open an administrative PowerShell.
Click Start, type PowerShell, right-click Windows PowerShell, and then click Run as administrator.
Install the Chocolatey Package Manager, which automates many of the following installation steps.
> Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))
Log out, and log back in to the server to set the new environment.
Install OpenSSL and Python3 with Chocolatey
> choco install openssl python3 -y
Log out, and log back in to the server to set the new environment.
Install Certbot with pip:
> pip install certbot
Log out, and log back in to the server to set the new environment.
3. Open Firewall Port 80
Let's Encrypt needs to perform a handshake on port 80 to verify your domain name. With PowerShell, create a rule to allow inbound traffic on port 80.
> New-NetFirewallRule -DisplayName "Let's Encrypt (HTTP-In)" -Direction inbound -LocalPort 80 -Protocol TCP -Action Allow
If you use the Vultr Firewall, verify port 80 is open there as well.
4. Get a Let's Encrypt Certificate
Request a certificate with Certbot. Replace
myserver.example.com
with your domain name.> certbot certonly -d myserver.example.com
You'll be prompted to either spin up a temporary webserver or place files in the webroot. Enter option 1 to use a temporary webserver.
When prompted, enter your email address.
Agree to the terms of service.
When finished, your Let's Encrypt keys are stored in C:\Certbot\live\myserver.example.com
5. Convert and Import Certificate
You have created a .pem format certificate, but Windows requires .pfx format.
Convert the certificate with OpenSSL.
Choose a strong password to replace
YOUR_PASSWORD
Replace
myserver.example.com
with your domain name> openssl pkcs12 -export -out C:\Certbot\keys\winrdp.pfx -inkey C:\Certbot\live\myserver.example.com\privkey.pem -in C:\Certbot\live\myserver.example.com\cert.pem -certfile C:\Certbot\live\myserver.example.com\chain.pem -password pass:YOUR_PASSWORD
Import your certificate. Replace YOUR_PASSWORD
with the strong password you chose earlier.
> certutil -p YOUR_PASSWORD -importPFX C:\Certbot\keys\winrdp.pfx noExport
6. Apply the Certificate
Run these commands to make Remote Desktop use the certificate.
Retreive the certificate thumbprint and set it to the variable $thumbprint
.
> $thumbprint = (Get-ChildItem -Path Cert:\LocalMachine\my | WHERE {$_.Subject -match "myserver.example.com" } | Sort-Object -Descending NotBefore | Select -First 1).Thumbprint
Apply the certificate thumbprint to RDP.
> wmic /namespace:\\root\CIMV2\TerminalServices PATH Win32_TSGeneralSetting Set SSLCertificateSHA1Hash="$thumbprint"
7. Test the Certificate
Connect to your instance with RDP using the instance IP address. You should receive a certificate validation warning.
Next, connect to the instance using the domain name instead of the IP address. You should connect without certificate security warnings.
This demonstrates your certificate is working properly.
8. Create a Task Schedule to Renew the Certificate Automatically
Let's Encrypt certificates expires after three months. To keep your certificates valid, create a scheduled task to renew them automatically.
Create a new PowerShell script named
C:\Certbot\renew-certificates.ps1
.> notepad C:\Certbot\renew-certificates.ps1
Paste the following into the PowerShell script.
Make sure to change
myserver.example.com
to your domain name, and use the strong password you chose earlier.certbot renew openssl pkcs12 -export -out C:\Certbot\keys\winrdp.pfx -inkey C:\Certbot\live\myserver.example.com\privkey.pem -in C:\Certbot\live\myserver.example.com\cert.pem -certfile C:\Certbot\live\myserver.example.com\chain.pem -password pass:YOUR_PASSWORD certutil -p YOUR_PASSWORD -importPFX C:\Certbot\keys\winrdp.pfx noExport $thumbprint = (Get-ChildItem -Path Cert:\LocalMachine\my | WHERE {$_.Subject -match "myserver.example.com" } | Sort-Object -Descending NotBefore | Select -First 1).Thumbprint wmic /namespace:\\root\CIMV2\TerminalServices PATH Win32_TSGeneralSetting Set SSLCertificateSHA1Hash="$thumbprint"
Create the scheduled task to check and renew certificates every Sunday at 1 a.m. every four weeks.
> $action = New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-ExecutionPolicy Bypass -WindowStyle Hidden C:\Certbot\renew-certificates.ps1" > $trigger = New-ScheduledTaskTrigger -Weekly -DaysOfWeek Sunday -WeeksInterval 4 -At 1am > Register-ScheduledTask "Renew Certificates" -Action $action -Trigger $trigger -User "System"