How to Configure a Let's Encrypt TLS Certificate for Windows Remote Desktop

Updated on April 13, 2021
How to Configure a Let's Encrypt TLS Certificate for Windows Remote Desktop header image

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.

  1. Open an administrative PowerShell.

    Click Start, type PowerShell, right-click Windows PowerShell, and then click Run as administrator.

  2. 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'))
  3. Log out, and log back in to the server to set the new environment.

  4. Install OpenSSL and Python3 with Chocolatey

     > choco install openssl python3 -y
  5. Log out, and log back in to the server to set the new environment.

  6. Install Certbot with pip:

     > pip install certbot
  7. 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

  1. Request a certificate with Certbot. Replace myserver.example.com with your domain name.

     > certbot certonly -d myserver.example.com
  2. 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.

  3. When prompted, enter your email address.

  4. 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.

  1. Create a new PowerShell script named C:\Certbot\renew-certificates.ps1.

     > notepad C:\Certbot\renew-certificates.ps1
  2. 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"
  3. 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"

More Resources