Scott Hanselman

Securing an Azure App Service Website under SSL in minutes with Let's Encrypt

May 29, '18 Comments [21] Posted in Azure
Sponsored By

A screenshot that says "Your connection to this site is not secure."Let’s Encrypt is a free, automated, and open Certificate Authority. That means you can get free SSL certs and change your sites from http:// to https://. What's the catch? The SSL Certificates only last 90 days - not a year or years. They do this to encourage automation. If you set this up, you'll want to have some scripts or background process to automatically renew and install the certificates.

I run nearly two dozen websites (some small, some significant) on Azure. Given that Chrome 68+ is going to call out non HTTPS sites explicitly as "Not secure" in July, now's as good a time as any for us to get our sites - large and small - encrypted. I have some small static "brochure-ware" sites like http://babysmash.com that just aren't worth the money for a cert. Now it's free, so let's do it.

In some theorectical future, I hope that Azure and Clouds like it will have a single "encrypt it" button and handle the details for us, but as of the date of this blog post, there's some manual initial setup and some great work from the community.

There's a protocol for getting certificates called "ACME" - Automated Certificate Management Environment - and the EFF has a tool called Certbot that helps you request and deploy certs. There is a whole ecosystem around it, and if you are running Windows/IIS you can use a great simple ACME client called "Win-ACME." There are also UI's like Certify SSL Manager and PowerShell commands for ACME and systems like "GetSSL - Azure Automation," so you can feel free to roll your own script in an afternoon. Again, if you have a Windows VM and IIS, it's pretty straightforward and getting easier every day.

I'm currently using Simon J.K. Pedersen's lovely (and volunteer and unsupported, so be nice) Azure Let's Encrypt Web App Site Extension. I followed the instructions here but hit a few snags and a few things that aren't totally obvious. Many kudos and thanks to Simon for his hard work on this, as he's saving us all many hours of trouble!

Securing an Azure Web App with Let's Encrypt and the (unofficial) SJKP Let's Encrypt Site Extension

I'll go and secure BabySmash.com right now. Make a text file and keep track of these few things.

What's our checklist?

  • Azure Storage connection string - You'll need one for the extension to store state.
  • App Service Hosting Plan and App Service Resource Group Name - Ideally your "plan" (the VM your site runs on) and your site are in the same Resource Group (a resource group is just a name for a pile of stuff)
  • Service Principal Client/Application ID - This is like an account that the Site Extension will run as to do its job. It's an "on behalf of" delegate that will automate the changes to your site. You might see "client id" or "application id," they are the same thing.
  • Service Principal Client Secret - You'll make a new Key in your Service Principal. I called mine "login" but it doesn't matter, then some value like a generated password (also doesn't matter) and then hit Save. You'll then get a long hashed value - THAT is your Client Secret. Save it, you'll never see it again and you can't get it back.

Cool. Let's do it. Again, following along with the wiki, I'll make an App under Active Directory | App Registrations in the Azure Portal at https://portal.azure.com

Add a new App Registration in the Azure Portal

Make a new app...

Creating a new App Registration

Now grab the Application ID, aka Client ID and save that in your scratch space/notepad/sticky note/smart brain/don't lose it.

Copying the App Registration ClientID

Now click Settings, Keys, make a new one called "login" with a password and click Save. COPY THAT VALUE. You'll never see it again.

Adding a Key to the App Registration

Now, go to the Resource Group for your App Service and App Service Plan. Ideally it'll be the same one, but if it's not, go to each one and keep track of the names. I went there with the search box at the top of the Azure Portal.

Going to the Resource Group

The Portal changes sometimes, and this next step didn't line up to the Wiki instructions exactly. Click add, then make your new App Registration from above a "Contributor" to your Resource Group.

Adding the App as a Contributor to the Resource Group

Now head over to your actual App Service, and click Extensions.

App Service Extentions

I picked Azure Let's Encrypt to have this run as a Web Job in the background.

Adding the Let's Encrypt App Service Extension

Now, while you're at your Web App/Site, go to Settings and make sure you've set the following two Connection strings AzureWebJobsDashboard and AzureWebJobsStorage - Don't forget this step or it'll all work once but fail in 3 months during the renewal.

Both of these should be set to your Azure Storage Account connection string, e.g. DefaultEndpointsProtocol=https;AccountName=[myaccount];AccountKey=[mykey];

Remember the Web Job needs this storage so it can renew the certs every 3 months. Add them as "Custom."

Connection Strings in App Settings

Next, the instructions say to "configure the Site Extension." That can be confusing until you realize a Site Extension is really a "Side car web site." It is its own little website, running off to the side of your site. It will be at http://YOURSITENAME.scm.azurewebsites.net/LetsEncrypt so mine is at http://babysmash.scm.azurewebsites.net/LetsEncrypt.

You'll then want to full this form out. Your "Tenant ID" is your Azure Active Directory URL. You'll find your SubscriptionId in the "Overview" tab.

Configuring the Let's Encrypt Extension

Next next, and then hold down CTRL (as this is a multi-selection dialog) and pick the sites you want a certificate for. Note that www.yourdomin and and .yourdomain (the naked domain) are two different certs.

Requesting two SSL Certs

You'll want to confirm you see "Certificate successfully installed."

Certificate successfully installed.

Then head back over to the Azure Portal and turn on HTTPS Only if you'd like Azure itself (versus your code) to ensure and redirect all non-secure links to https://. Also confirm your SSL Bindings are correct. They should have been set up automatically.

HTTPS Only in the Azure Portal

Now I'll go hit https://babysmash.com and...

A screenshot that says "Your connection to this site is not secure."

It's not secure! Ah, now my site is in "mixed mode." That means that some of the resources like gifs or css were fetched with non-ssl (HTTP://) links. I'll update my site and all its external resources like YouTube embeds and fonts with https:// so that everything is secure. Since I'm using Git Deploy with Azure Web Apps (Azure App Service) I'll just make the changes and push the site again. You can also look at the elements as they load in F12 Browser Tools if you are having trouble finding out which image, css, or js file came in over http://

I'll redeploy and after a few tries, boom.

https://www.babysmash.com

And there's the cert. Note its expiration date. If the Site Extension does its job it will renew the cert before it expires!

A Let's Encrypt SSL Cert

Once I knew what I was doing, it took about 10 minutes per site. Thanks Simon for your work, and while there are multiple ways to do this, I found Simon's App Service Extension the easiest. I hope the Azure team comes up with a "One Click Solution" to this.

What do you think?


Sponsor: Learn how .NET in 2018 addresses the challenges developers are working on with future-focused technology. Get the new whitepaper on "The State of .NET in 2018" by the Progress Telerik team!

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb
Wednesday, 30 May 2018 04:58:48 UTC
I think this post is great but in my experience there is one critical mistake.Please do not set the Azure Web App to be https only.

Let's Encrypt extension is using http-01 mechanism in ACME to validate your ownership of the domain. The extension will place a randomly generated token in a file on your web server and Let's Encrypt CA will attempt to retrieve that document over http. If you set Azure Web App to https only, that validation request will get denied by Azure Web App infra and you are going to see failure in renewal/creation.

Also, I would have given the (3rd party) extension's service principal permission only to Web App and Service Plan, not to the entire group.
Wednesday, 30 May 2018 05:34:50 UTC
Excellent point. Let me look into clear solutions and I’ll update the post tomorrow.
Scott Hanselman
Wednesday, 30 May 2018 07:51:22 UTC
I'm sure the community would love a check-box to turn on Lets Encrypt in Azure but also a simple ASP.NET Core middleware that does the same if we want to host it ourselves.
Wednesday, 30 May 2018 08:09:46 UTC
Agree 100% with Abhay re. forcing the app to be HTTPS only. I enforce HTTPS by using a rewrite rule with an exception for the .well-known path. This is my rule from production; feel free to use it in your post. :)

<rule name="HTTP to HTTPS redirect" stopProcessing="true">
<match url="(.*)"/>
<conditions>
<add input="{HTTPS}" pattern="off" ignoreCase="true"/>
<add input="{HTTP_HOST}" pattern="localhost" negate="true"/>
<add input="{REQUEST_URI}" pattern=".well-known/" negate="true"/>
</conditions>
<action type="Redirect" url="https://{HTTP_HOST}/{R:1}" redirectType="Permanent"/>
</rule>
Richard Mercer
Wednesday, 30 May 2018 08:24:48 UTC
Hey man,

Nice post! But could you please help me out wich SubscriptionId I have to use when I have multiple subscriptions on my azure?
Wouter
Wednesday, 30 May 2018 08:27:01 UTC
Check out letsencrypt-webapp-renewer which is based on the letsencrypt-siteextension, but has the benefits of not requiring Azure Storage and not having to be installed on every web app you want to secure (to name a few).
Joakim Fiskvik
Wednesday, 30 May 2018 08:30:46 UTC
I'm using the "WebJob approach" (based on the same site-extension): https://github.com/ohadschn/letsencrypt-webapp-renewer
I like that it is independant from the actual site and runs the job for all sites in one job.
Christoph Fink
Wednesday, 30 May 2018 11:30:48 UTC
I would love to see Azure support something equivalent to the Certificate Manager in AWS. AWS basically gives free certificates for resources within their cloud.
Jon
Wednesday, 30 May 2018 12:53:55 UTC
LetsEncrypt is really great but I found out that using Cloudflare's free plan and its https proxy you can also have SSL for free.
Troy Hunt has done a blog post about this a while ago: a@https://www.troyhunt.com/how-to-get-your-ssl-for-free-on-shared/
Tony
Wednesday, 30 May 2018 13:58:14 UTC
I want to point out also that ohadschn's approach is better.

Since one can create a single app that works as a let's ecnrypt renewal application which configures other apps automatically. It also retains the settings between publish.

If you use the instructions in the Hanselman's post, I believe the settings will be cleared each time one does a publish with delete extra files checkbox turned on from the Visual Studio.
Wednesday, 30 May 2018 17:51:22 UTC
I'm looking at the code and it seems the web job will follow redirects so as long as I'm listening on 80 for the initial .well-known call, it will follow it, so the renewal will work. It's only when the website *literally isn't listening on 80 at all* that the renewal will fail.

So I'm taking that to mean:

* Do you listen on 80 and redirect to 443? You're OK
* Do you NOT listen on 80 at all? Use Richard's Web.config method of SSL redirection

Fair? Thoughts?
Scott Hanselman
Wednesday, 30 May 2018 18:18:57 UTC
Here's the issue to vote on if you think this should be included in Azure.

https://feedback.azure.com/forums/170024-additional-services/suggestions/16957756-add-integration-with-let-s-encrypt

This blog post clearly demonstrates that it is too complicated today and could be made much simpler.

Estyn
Wednesday, 30 May 2018 19:02:16 UTC
Thanks for the attention Scott. As people mentions there are several ways to use lets encrypt in Azure. I built the extension for a few of my personal sites, if you have many sites a single function or webjob that does it for all web apps i probably an easier solution.

And yes be careful if you delete the App_Data folder in your web app, the web job will be wiped too, and you will not get certs renewed. However if that happens, lets encrypt will send you a nice email 20 days before the cert expires warning you, so as long as you pay attention to that, and signed up with your real email you should be fine.

I personally also hoped that MS would bring this to Azure, from what I understand it is something that have their attention, but there is no timeline yet.

Wednesday, 30 May 2018 19:38:48 UTC
This nonsense is making me feel stupid. This is the 3rd time I've attempted the process, and the 3rd time the instructions did not in any way match what the azure/lets encrypt actually do.

Just when I think I've entered all the magic strings, I get this under ClientId:
The ClientId registered under application settings 00000000-0000-0000-0000-000000000000 does not match the ClientId you entered here [Redacted]

What does it mean by the zeros in "application settings"?
Russ Painter
Wednesday, 30 May 2018 19:54:23 UTC
I think it's also worth mentioning to set TLS to a minimum of 1.1 while you're enabling "HTTPS only". The Azure team should set it to 1.1 by default if you ask me, but until then.
David
Saturday, 02 June 2018 04:20:52 UTC
What great timing - I was just looking at trying to get this sorted.

I'm having trouble with the 'Grant permissions to the Service Principal' step. I'm on the blade for my resource group that has the app service plan & app service(s). I'm on the 'overview' tab. When I click '+ Add' button, I go to the 'Add resource' blade, not the 'Add permissions' that I'm looking for. I can't find that anywhere. The SJKP article says to 'click the Access button', but as Scott says the Portal has changed.

Can someone clarify what the steps are here please. Thanks so much.
Saturday, 02 June 2018 04:26:35 UTC
It's on the 'Access control (IAM)' tab. I found it literately 10 seconds after posting...
Tuesday, 05 June 2018 13:46:36 UTC
Thank you for this tutorial! I've tried to configure let's encrypt in the past but had some problems. I started to walk through your tutorial and when I reached the Add Extension step I suddenly remembered what the problem was: I'm on the Shared plan and that one doesn't support SSL. Duh!

I really, really, really want to use Azure for some small side projects. But I can't justify paying almost $55 for each site just to get SSL.

What to do? :(
Johan
Tuesday, 05 June 2018 20:41:20 UTC
Johan:
"I really, really, really want to use Azure for some small side projects. But I can't justify paying almost $55 for each site just to get SSL.
What to do? :("


SSL on App Services is supported from the B1, which costs $32/month. Moreover you can run multiple WebApps on the same App Service (basically all of them), so you need to pay only once for all your webapps.
Mark Szabo
Thursday, 07 June 2018 20:29:12 UTC
Thanks for sharing Scott, this is great. It took me a good 45 minutes to get my first one setup but for a free certificate (that crossing my fingers should auto-renew) I'm not complaining.

I would love to see full blown Microsoft support for LetEncrypt that makes the creation of all the moving parts.
Monday, 11 June 2018 12:14:27 UTC
Thanks a lot, finally I found a guide I could actually follow and get to work :)

Good work.
Søren Reinke
Comments are closed.

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.