2017-11-03

Let's encrypt on Windows server + auto certificate bindings renewal

I am runnging a simple WCF Web HTTP service on a Windows 2008 box. There is a requirement to expose service's endpoints securely using HTTPS protocol. To do this I had to obtain a certificate from a certification authority. Recently, the Internet Security Research Group created free of charge authority, called Let's Encrypt. The authority allows you to create a certificate with validity that lasts few months and to renew generated certificates programatically. I decided to use Let's Encrypt certificates for my task.

Installation and set-up of Let's Encrypt client

  1. Install nginx and configure it as Windows service by using NSSM.

    To verify ownership of a domain, Let's Encrypt client has to expose a generated file on a certain unsecured (HTTP) URL of the server. Then the Let's Encrypt's server opens the URL, checks its content and verifies the domain. Easy way to do this is to configure nginx to run on port 80 of the server and to expose the URL.

  2. Configure nginx server documents from C:\inetpub\wwwroot\ directory on port 80. Don't enable secured communication on port 443, it would collide with WCF service.

  3. Install Letsencrypt-win-simple client. And run it by letsencrypt.exe.

    The client will generate certificates to a directory similar to this:

    Saving Certificate to C:\Users\myuser\AppData\Roaming\letsencrypt-win-simple\httpsacme-v01.api.letsencrypt.org\mydomain.com-crt.der
    Saving Issuer Certificate to C:\Users\myuser\AppData\Roaming\letsencrypt-win-simple\httpsacme-v01.api.letsencrypt.org\ca-0A0151530000025395736A0B85ECA708-crt.pem
    Saving Certificate to C:\Users\myuser\AppData\Roaming\letsencrypt-win-simple\httpsacme-v01.api.letsencrypt.org\mydomain.com-all.pfx
    

    But more importantingly it will store the certificate into system's keystore. To list the certificates you can run simple powershell command.

    powershell -Command Get-ChildItem Cert:\LocalMachine\My
    

Bind certificate with port 443 and configure binding auto-refresh

  1. Add new SSL certificate binding via Netsh command add sslcert.

    First, find the certificate fingerprint by a combination of powershell commands for listing and filtering.

    powershell -Command "Get-ChildItem Cert:\LocalMachine\My | Where-Object {$_.Subject -eq 'CN=mydomain.com'}"
    

    Use the returned thumbprint instead of %THUMBPRINT% for follwing command (appid can be random).

    netsh http add sslcert ipport=0.0.0.0:443 certhash=%THUMBPRINT% appid={e2eaacd9-92e6-43cc-b51c-7a7887149607}
    
  2. Create a batch script to refresh certificate binding.

    Use more elaborated powershell command to get thumbprint of a fresh certificate. Then remove existing binding and add new one.

    REM Get certificate thumbprint
    set GET_THUMBPRINT_COMMAND=powershell -Command "Get-ChildItem Cert:\LocalMachine\My | Where-Object {$_.Subject -eq 'CN=mydomain.com'} | Select -ExpandProperty Thumbprint"
    for /f %%i in ('%GET_THUMBPRINT_COMMAND%') do set THUMBPRINT=%%i
    
    
    REM Remove existing binding
    netsh http delete sslcert 0.0.0.0:443
    
    
    REM Add new binding
    netsh http add sslcert ipport=0.0.0.0:443 certhash=%THUMBPRINT% appid={e2eaacd9-92e6-43cc-b51c-7a7887149607}
    
  3. Plan execution of the script in Windows scheduler.