Setting up LetsEncrypt on Windows Server2012/IIS8 with HSTS

It’s been forever since I posted here but as usual, I post when I’ve struggled through something, not found clear solutions and resolved it. Hope this helps.

Situation.

We have a public website http://www.example.com, an Exchange gateway email.example.com and an RDS (terminal services) gateway rds.example.com.

UPDATE: March 6, 2018
The steps outlined here do work for RDS & Exchange but there are problems. Both Exchange and RDS require additional steps to renew certificates, specifically, manually assigning certificates to various services with built in tools (Exchange Admin Console and RDS Connection Broker) so a 90 day LetEncrypt certificate is a huge pain and I’ve paid the big bucks for two year certs from a CA.But as I said, these steps -do- work fine if you run a simple web server, so the post is still valid and I hope it helps some of you.

 

Our public website is set up to use Long Duration HSTS (HTTP Strict Transport Security) and is in fact part of HSTS Preload. I encourage you to read up on HSTS and preloading but basically, this means that browsers know that all pages served must be over HTTPS. Long duration HSTS means that browsers set a flag for the site the first time it is visited that it will only allow pages from that site over HTTPS for the duration set up in the response header

FYI, 31,536,000 seconds is one year. Notice also that the includeSubDomains flag is set. This is important to know for setting up LetsEncrypt in my scenario with the 2 subdomains (email & rds). I’ll get to that in a bit.

Our public website has an EV certificate which allows the pages to be loaded from http://www.example.com and example.com. I can’t use this particular certificate for email and rds. My CA does offer multi-domain EV certs but they are quite expensive.  There’s no real benefit to having an EV cert on those subdomains. (some may argue there’s no benefit to an EV cert at all except for Security Theatre but that’s another post 😉 ) Because of this we’ve had the 2 subdomains on certs from a cheap SSL provider as we are only looking at securing the gateways.

These subdomain certs are up for renewal and I though I’d give LetsEncrypt a try. I looked at it a few years ago, but it was basically built for *nix servers and windows implementations were few, generally terrible and documentation was almost non-existent. And still sort of is…hence this post.

There are now some tools for windows you can use to help get a LetsEncrypt cert installed on Windows, in my case Server 2012 R2 running IIS 8.

My first attempt to get this to work was using Win-Acme. I never got it to work, but I’ll outline what I did for keywords so if others have the same problem maybe they’ll find what I was able to get working (or someone can point out what I did wrong) You can skip this bit and head down to Certify App walkthrough if you want.

Unzip the package to  permanent location on the server (needed for renewal) run Letsencrypt.exe from an admin console.

Select N for Create new Certificate

Select 1 for Single Binding of an IIS site

Quick aside here. You need to make sure that your site bindings in IIS are set up correctly. In our case, we just have a single site per server (and subdomain) so the binding for the Default Website is like this. This may vary depending on your set up. Note that the SSL cert listed here is the expiring one.

Back to Win-Acme. You will be presented with a list of all registered IIS sites. In this case, there’s just the single one, but select the number of the site you want to install the cert on.

The first time you run a request for a site, you will be asked to enter an email address for renewal notifications. Since I’d tried this a couple of times, already, I don’t have a screen shot of that.

Once you’ve done that, Win-Acme will try to install the cert. And, in my case, fail.

There are a couple of things I tried. There apparently needs to be a folder in wwwroot of your site called

.well-known/acme-challenge

for the certification process to work properly. I believe the process just checks to see that a file can be served from the server that you are trying to certify.

First challenge is to create a folder called .well-known because on a windows system, it is impossible to create a folder that starts with a dot using File Explorer. Hang over from the old days I guess. You can do one of 2 things. Create a folder (called LetsEncrypt or anything really) in File Explorer and then create a .well-known Virtual Directory in IIS or simply fire up PowerShell cd to your site root and use

md .well-known

Then you can create your acme challenge folder as a sub of that any way you want.

You also may need to set up IIS to accept requests for extension-less files. Some guides suggest setting accepted Mime Types to * application/octet-stream but that is not a great idea as it basically opens a potential security hole as it allows -any- file to be run on your server.

The more secure method is to add a web.config file to the acme-challenge folder

<?xml version=”1.0″ encoding=”UTF-8″?>

<configuration>
<system.webServer>
<validation validateIntegratedModeConfiguration=”false” />
<staticContent>
<mimeMap fileExtension=”.” mimeType=”text/json” />
</staticContent>
<handlers>
<clear />
<add name=”StaticFile” path=”*” verb=”*” type=”” modules=”StaticFileModule,DefaultDocumentModule,DirectoryListingModule” scriptProcessor=”” resourceType=”Either” requireAccess=”Read” allowPathInfo=”false” preCondition=”” responseBufferLimit=”4194304″ />
</handlers>
</system.webServer>
<system.web>
<authorization>
<allow users=”*” />
</authorization>
</system.web>
</configuration>

Which basically limits the serving of extension-less files from just that folder.

After trying all of that and more, I still was unable to get win-acme to work. Also, know that LetsEncrypt rate limits failures to 5 per hour so you may have to wait if you try and fail several times.

So I moved on to Certify. (which as you’ll see worked so I never did test the PowerShell tool.)

Install the Certify app on your server  and then run it.

Click New Certificate.

Just like win-acme, you’ll be asked to enter an email address for renewal notifications.

Select the IIS site from the drop down, in this case, its Default Website.

Take note of the message

The LetsEncrypt service must be able to access all of these domains via port 80 (for HTTP challenges) or port 443 (for TLS-SNI challenges) for the certification proess to work.

So because my site is HSTS, SSL is always on, I figured I had to use the TLS-SNI challenge type. The advanced tab allows us to select which to use.  And a handy Test button.

Run that and you should get an OK

Click save changes and you will be ready to request a LetsEncrypt certificate.

 

Click on the site in the sidebar and the click request certificate and you’ll get an error?

Specifically Default Web Site: Request failed – no challenge found matching requested type.  What’s that mean?

Well it turns that in January of 2018, LetsEncrypt stopped allowing TLS-SNI requests due to a vulnerability which could allow getting certificates for domains you don’t own. Which is like, really bad.

I assume the TLS-SNI challenge type will eventually be removed (and may already be by the time you read this) from Certify as LetsEncrypt has no plans to reinstate support.

So back to the advanced tab, select http-01 challenge and run a test.

Now you’ll see that the error message that the config failed to verify that the site is publicly accessible and can serve extension-less files. Well, the nice thing about Certify is that it actually creates the .well-known/acme-challenge folder and creates the web.config file as mentioned in the win-acme section above.

So we know we should be able to serve extension-less files and since the folder is in the webroot, it should be publicly accessible. So what’s the problem?

This is where we circle back to HSTS and always on SSL. When the LetEncrypt process uses http-01, it’s expecting a result on port 80 (standard http) but since our site is HTTPS Only, the service can’t get the file.

Now if you read this before you try the first time, you may be able to turn HSTS off to install the certificate (but I can’t verify that) however -don’t- do this unless you want to manually do this every time your certificate needs updating. And that’s a lot because, unlike commercial certs with a 2 year max expiry LetsEncrypt certs expire every 90 -days-.

So we need HTTP to get the cert, but can only use HTTPS. What do we do?

Turns out it’s pretty simple. We use URL Rewrite in IIS.

IMPORTANT: For a standard webserver the following steps work fine. They do -not- work on an Exchange server. Well they do, but setting a URL Rewrite to HTTPS breaks Exchange Management Shell and Exchange Toolbox (Exchange 2013). To set up redirection on an Exchange 2013 server follow the steps HERE .

URL Rewrite is not installed by default in IIS, so either download it from Microsoft  or use the Web Platform installer.

You might have to restart IIS Manager to get it to show up after install.

Head to the root node of your website in IIS Manager and fire up URL Rewrite

Then click Add Rule > Blank Rule

Give it a name (ie: toHTTPS), Select Matches the Pattern & Regular Expressions from the drop downs. Then add the pattern (.*)

Under Conditions, click Add and then add Condition input {HTTPS} Matches the Pattern and ^OFF$

Click OK.

Finally, set your action to Redirect, Redirect URL to https://{HTTP_HOST}/{R:1} and Redirect Type to Permanent (301)

Click apply and you now redirect all HTTP traffic to HTTPS.

How does this help with the Certify issue? Well thankfully, LetsEncrypt only needs to hit port 80. It does not care about what happens after that. The server handles the conversion to HTTPS and everyone is happy. Run the http-01 challenge again and you should see

Now all we need to do is click Save and then Request Certificate again.

And after a few minutes….

Now Certify should automatically set up the binding to the new cert but you’ll want to double check just to make sure.

And yup it’s there and assigned.

And we can view the certificate details and woohoo. We’re good to go.

Now this should automatically renew on May 30, 2018, 89 days from now. If it doesn’t, I’ll be doing another post I expect 🙂

Hope this helps.

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s

%d bloggers like this: