Ahoy there folks. I recently received an email from my SSL provider advising the certificate on this blog was about to expire. Just as I was about to click the renew button I remembered reading a tweet from my good friend and ex-colleague @KennyLowe. In that tweet, he advised he’d just switched the SSL provider for his Azure Web App hosted blog to Let’s Encrypt. Now I’d heard about Let’s Encrypt a while ago but hadn’t yet had cause to make use of it, so decided to go through the same process he did and make the switch. One of the added bonuses is that Simon J.K. Pedersen has developed an awesome site extension aptly named “Let’s Encrypt Site Extension”, and this extension handles the installation and update of your Let’s Encrypt SSL certificate…thanks for the awesome work Simon 🙂
Having now run through the process, I decided to spin up a dummy Azure Web App, go through the process again, and blog it…cause why not, right?
- Configure a Custom Domain on a Web App
- Create an Azure Storage Account
- Add Web Job Connection Strings
- Create an Azure AD Application
- Configure Resource Group Permissions
- Install and Configure Let’s Encrypt Site Extension
- Validation and Optional Config Changes
Here’s a list of the information/resources you’ll need to run through this guide, where it makes sense I’ll also include the process for deploying these resources. Let’s crack on shall we.
- An Azure Web App with a custom domain configured
NOTE: Check if your Web App and App Service Plan are in the same Resource Group, as if they’re not it will change part of the process later in the guide
- Your Azure Tenant name (something.onmicrosoft.com)
- An Azure Storage Account – required to store the extension state
- A connection string for the above Storage Account
- An Azure AD Service Principal Client
- You’ll need both the “Application ID” and the “Client Secret”
Configure a Custom Domain on a Web App
Now it’s very likely you’ve already done this but for the sake of completeness, I’ll run through it. I’m also assuming you’ve already registered a domain name and have access to it’s DNS control panel as you’ll need to add/modify a CNAME record.
Before we get started, make sure you’re logged into your Azure AD tenant at https://portal.azure.com
- Navigate to your Web App, select the “Custom domains” blade located under “Settings”
- Click “Add custom domain”
- Enter your “Custom domain”
- Click “Validate”
Azure will now run a validation check against your domain to make sure that the hostname is available and that you can prove ownership. The ownership validation should fail as we’ll need to add a CNAME record into DNS first and run the validation again.
NOTE: You’ll notice mine passed, that’s because I have already added the CNAME before writing this guide and couldn’t be bothered removing/re-adding it 🙂
Just pretend “Domain ownership” shows as red cross
- For “Hostname record type”, select “CNAME…”
- Now go to the DNS control panel for your custom domain and a the following CNAME record:
- TYPE = CNAME
- NAME = Your domain or subdomain e.g. letsencryptdemo.davidfleming.org
- VALUE = The value in the “CNAME” field, see screenshot below for an example
NOTE: If this is a new host you’re adding then DNS propagation is unlikely to be an issue but if you’re changing an existing one then you may have a wait before things will successfully validate.
Assuming that you’ve now added the DNS record correctly and propagation has take place…
- Click “Validate” again
- Assuming everything is now showing green (See screenshot below), click “Add custom domain”
You’ll notice that your custom domain has now been added but has a “State” of “Not secure”, don’t worry about that for the time being, it’s exactly what we’ll be addressing in this guide.
Now if we browse to my dummy site on HTTPS, we can see that it responds on the new custom domain but shows as “Not secure”, as expected.
Create an Azure Storage Account
As mentioned in the “Overview” section, we’ll need to have a storage account available for the Let’s Encrypt site extension to store it’s state. It’s likely you already have one deployed but again for the sake of completeness, here’s the process for deploying one.
- From the “Dashboard”, select “+Create a resource”
- Select “Storage”
- Select “Storage account”
- Select the “Resource Group” that holds your Web App and App Service Plan
- Enter a sensible “Storage Account Name” (lower case and no special characters)
- Select the “Region” your Web App and App Service Plan are deployed into
- For “Performance”, select “Standard”
- For “Account kind”, select “StorageV2…”
- Choose your preferred “Replication” level
- For “Access tier default”, select “Cool”
- Click “Review + Create” to accept all other defaults
- Assuming validation succeeds, click “Create”
Later in the guide we’ll need a “Connection String” for the Storage Account we just deployed, let’s go get that now.
From the “Dashboard”
- Navigate to “Resource groups”
- Select the Resource Group that holds the Storage Account you just deployed
- Select your Storage Account
- Select the “Access keys” blade under “Settings”
- Copy one of the two available “Connection string” values and store it for use later in the guide
Add Web Job Connection Strings
When we come to configure the Let’s Encrypt site extension later in the guide, we’ll be choosing the “Web Job” option as this has the benefit of auto-renewing our certificate 14 days before it’s set to expire (every 3 months). To allow this to take place, we need to configure two “Application Settings” within our Web App. The names of these settings are as follows:
The value for both of these will be the Storage Account Access Key you grabbed earlier. With the explanation out of the way, let’s get them added shall we?
- Within your Web App, select the “Configuration” blade under “Settings”
- Click “New application setting”
- For “Name”, enter “AzureWebJobsDashboard”
- For “Value”, enter the Storage Account connection string from earlier
- Click “Update”
- Repeat the process, this time give it a “Name” of “AzureWebJobsStorage”
Your “Application settings” should now look something like this:
- Click “Save”
With that in place, we can move on to the last prerequisite task.
Create an Azure AD Application
For the Let’s Encrypt site extension to do it’s thing, it needs some permissions over the Resource Group that holds our Web App and App Service Plan. These permissions are provided by way of an Azure AD Application/Service Principal…think of this like a service account the site extension will use to automate our certificate installations, both initially and any renewals.
Without further ado:
- From the “Dashboard”, select “All services”
- Search for “Azure Active Directory” and select it
The UI for this next piece was updated recently, so let’s use the new way shall we?
- Select the “App registrations” blade, under “Manage”
- Click “New registration”
- Enter a “Name” for your application
- For “Supported account types”, select “Accounts in this organizational directory only…”
- For “Redirect URI…”, select “Web” from the drop-down and enter your site address into the available field
- Click “Register”
Once created, you’ll be taken to the new application “Overview” blade
- Copy the “Application (client) ID” and store it somewhere safe, we’ll need it later
- Now select the “Certificates and secrets” blade, under “Manage”
- Click “New client secret”
- Enter something descriptive into…“Description” 🙂
- For “Expires”, select “Never”
- Click “Add”
- Copy the key “Value” field of your new “Client secret”
NOTE: If you don’t copy this now, you’ll lose it and will have to create a new “Client secret”
OK, so now we have our shiny new app, but currently it doesn’t have permissions to do anything, let’s attend to that now.
Configure Resource Group Permissions
As mentioned earlier in the guide, the Let’s Encrypt site extension will need certain permissions over the Resource Group that holds our Web App and App Service Plan, so let’s give it some.
- Navigate to the “Resource Group” that holds the above mentioned resources
- Select the “Access control (IAM)” blade
- Click “Role assignments”
- Click “+Add”
- Click “Add roles assignments”
- For “Role”, select “Contributor”
- For “Assign access to”, leave the default option
- For “Select”, search for the Azure AD app we created earlier and click it
- Click “Save”
NOTE: If your Web App and App Service plan are in different Resource Groups, repeat the above section to make sure your Azure AD App has the required permissions over both of them.
OK, we should now be in a good place to crack on and install the Let’s Encrypt site extension.
Install and Configure Let’s Encrypt Site Extension
Right, so with all that out of the way let’s get this extension installed and configured shall we?
- Navigate to your Web App select the “Extensions” blade, under “Development Tools”
- Click “+Add”
- Click “Choose extension”
- Select “Azure Let’s Encrypt”
NOTE: Be careful not to select the extension named “Azure Let’s Encrypt (No Web Jobs)”, as we need dem jobs.
- Click “Legal Terms” and accept them by click “OK”
- Click “OK” again to install the extension
Now we need to go ahead and configure the extension, which we’ll do using the Kudu “Advanced Tools” blade.
- Select the “Advanced Tools” blade, under “Development Tools”
- Click “Go” to open Kudu services in a new tab
In the new tab you just opened:
- Select “Site extensions” from the top menu
- Click the “Play” button on the “Azure Let’s Encrypt” extension to launch it
NOTE: You may see the error below when launching the extension, if so restart your Web App to resolve it.
To restart your Web App:
- Select the “Overview” blade
- Click “Restart”
- Click “Yes” when prompted
NOTE: As well as using the above method, you can also browse directly to the Let’s Encrypt site extension using the following URL:
In my case: https://letsencryptdemo.scm.azurewebsites.net/letsencrypt/
With your Web App restarted, go back to the tab that posted the “No route…” error and refresh the page. You should now be looking at the “Authentication Settings” page. We’re interested in the “Automated Installation…” section at the bottom of the page.
To configure the extension, you’ll need:
- Your Azure AD “Tenant” Name i.e. “something.onmicrosoft.com”
NOTE: The above could be a custom domain if you have one configured within Azure AD.
- The “SubscriptionID” where your Web App resides
- The “ClientID” and “ClientSecret” you noted down earlier when creating the Azure AD Application
- The “ResourceGroupName” where your Web App resides
- The “ServicePlanResourceGroupName” where your App Service Plan resides
NOTE: If your Web App and App Service Plan are in the same Resource Group, you’ll enter the same value for those last two bullet points.
NOTE: If you’re not sure where to get your Subscription ID, navigate to the “Overview” blade of your Web App and you can copy it from there.
With all fields populated correctly, it should look something like the screenshot below:
NOTE: Your Web App will restart again.
- Now click “Next”
You should now be looking at the following screen while the required settings are being applied:
Once the settings have been applied, you should be looking at the “Custom Domains and SSL” page:
- Click “Next”
On the “Request and Install Certificate” page
- If there are multiple “Hostnames”, select then by holding “CTRL” as you click them
- Enter an “Email” address to create a Let’s Encrypt account
- Click “Request and Install certificate”
Assuming your certificate was installed and set up correctly, you should be looking a a page similar to this:
…and that’s it, your site now has an SSL certificate installed for the next 3 months and it’ll automatically renew within 14 dates of it’s expiry date…noice!
We probably shouldn’t just take this on faith though, let’s go and have a look and make a few little changes to the site config while we’re at it.
Validation and Optional Config Changes
Let’s confirm our SSL is installed and working as expected.
- Navigate to your Web App and select the “Custom domains” blade, under “Settings”
The custom domain you added earlier should now be showing green and “Secure”. While I’m in here I’m also going to flip the “HTTPS Only” option to “On” to redirect all traffic to the site to HTTPS
We can also browse to the site and confirm there is indeed a certificate installed and all is looking good.
By default, Azure Web Apps are configured to spin down in times of low/no traffic. Unfortunately this could cause our automated certificate renewal Web Jobs a problem, so let’s go and deal with that.
- Select the “Configuration” blade, under “Settings”
- Click “General settings”
- Flip “Always On” to “On”
- Click “Save”
While you’re in there, you may want to change some other settings depending on your use case, e.g:
- Platform: From “32 Bit” to “64 Bit”
- HTTP Version: From “1.1” to “2.0”
- ARR affinity: From “On” to “Off”
NOTE: The above aren’t strictly recommendations and are only listed to bring your attention to the options available to you within your Web App.
If you’re just interested or need to troubleshoot issues with the Web Jobs configured as part of this process, you can have a look at them by:
- Select the “Web Jobs” blade, under “Settings”
- Highlight the “letsencrypt…” Web Job
- Click “Logs” at the top of the blade which will open in a new tab
Here you can see the status of the tasks running as part of the Web Job. You can also click “Toggle Output” to see some fairly detailed logs…useful stuff.
I think that about covers it for this post, as usual it went on a little longer than I expected but hopefully it helps someone other than me 🙂
See you in the next one.
3 Replies to “Secure an Azure Web App Using Let’s Encrypt”
An amazing post Mr. Fleming. Both for its usefulness (I got certs!) and incredible detail and accuracy. Thank you sir!
I found only one issue and was able to extrapolate around it – the Automated Installation steps don’t include adding the storage account connection string. However the screen didn’t show the associated field, so that was kinda weird.
You’re very welcome and thanks for the feedback, glad it helped 🙂
It’s possible the process has changed slightly. I’ll have a look when I get a minute and update the guide accordingly.