Binding Let's Encrypt SSL Certificate to Azure Functions
Tags: azurefunctions, apexdomain, letsencrypt, sslcertificate
Published: 2020-10-16 00:01:54

---
title: "Binding Let's Encrypt SSL Certificate to Azure Functions"
published: true
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/b2mao9t7ry8mtclrympd.png
description: "This post shows how to generate an SSL certificate through Let's Encrypt API and bind the certificate to the custom APEX domain on Azure Functions app."
tags: azurefunctions, apexdomain, letsencrypt, sslcertificate
canonical_url: https://devkimchi.com/2020/10/14/lets-encrypt-ssl-certificate-on-azure-functions/
series: Azure Functions with Custom APEX Domain, SSL Certificate, Azure DNS and GitHub Actions
---

In my [previous post][post 1], I discussed how to map a root domain or APEX domain with an [Azure Functions][az func] instance. Let's bind an SSL certificate to the custom domain, which is generated by [Let's Encrypt][letsencrypt] so that we can enable HTTPS connection through the custom domain.


## Let's Encrypt ##

[Let's Encrypt][letsencrypt] is a non-profit organisation that issues free SSL certificate. Although it's free, it's widely accepted and backed by many tech companies. There are a few limitations, though. It's valid only for three months. In other words, we MUST renew the SSL certificate issued by Let's Encrypt for every three months. But you know, we've got automation! So, don't worry about the certificate renewal as long as we've got the automation process for it.


## Azure App Service Site Extension ##

Azure App Service provides the site extension feature. One of the extensions is the [Let's Encrypt Site Extension][gh site extension]. It's written as the [Azure WebJob][az webjob] style so that the WebJob runs every three months to renew the certificate automatically. It's a pretty useful extension.

![][image-01]

However, this extension has a few critical drawbacks as well.

* It only runs on Windows-based App Service instances (including Azure Functions) because WebJob basically relies on the Windows platform. No Linux-based App Service, unfortunately.
* It shares the runtime environment with the App Service instance. Therefore, whenever we deploy a new App Service instance, we MUST always deploy the extension and configure it.
* If we deploy an application with the "delete all files before deployment" option, the WebJob will get deleted.

It doesn't seem to be a way for production use. What else can we take to bind the SSL certificate for free?


## Azure Functions App Only for SSL Certificate Management ##

We're lucky enough to have [Shibayan][tw shibayan] who publishes an excellent [Azure Function app][gh acmebot keyvault] that manages Let's Encrypt SSL Certificate with no dependency on the App Service instances. Through the application, we can quickly generate and renew as many SSL certificates as we can and store them to [Azure Key Vault][az kv]. The stored SSL certificates are directly bound to Azure Functions instances. How fantastic!

First of all, run the ARM template below to provision an Azure Functions app and Key Vault instance. But, if you like, you can write your own ARM template and run it.

[![](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Fshibayan%2Fkeyvault-acmebot%2Fmaster%2Fazuredeploy.json)

The provisioned Azure Functions app instance got the [Managed Identity][az func mi] feature enabled so the app can directly access to the Key Vault instance to store SSL certificates. Once all relevant resources are provisioned, follow the process below.

> Let's say the Azure Functions app instance for the SSL certificate management as `https://ssl-management.azurewebsites.net`.


### Authentication / Authorisation ###

The provisioned Azure Functions app includes an admin UI which is only accessible through authentication. Therefore, activate the [Authentiation / Authorisation][az func auth] feature like below:

![][image-02]

Then, configure the Azure Active Directory for authentication. We use the account registered to Azure Active Directory. Set the management mode to `Express` and put the app name. The default value of the app name is the Function app name. We don't need to change it.

![][image-03]

Now, we got the Azure Functions app configured for SSL certificate management.


### Azure DNS Configuration ###

I'm assuming that we use [Azure DNS][az dns] for domain management. Go to the resource group where the Azure DNS instance is provisioned and select `Access control (IAM)` blade, then assign a role to the Azure Functions app for SSL certificate management.

![][image-04]

* `Role`: DNS Zone Contributor
* `Assign access to`: Function App
* `Selected members`: Azure Functions app for SSL certificate management. Only apps that [Managed Identity feature][az func mi] enabled appear here.


## SSL Certificate Generation ##

Open a web browser and access to the admin UI for the SSL certificate management, by accessing to `https://ssl-management.azurewebsites.net/add-certificate`. If it's the first time for you to access, you'll be asked to log-in.

![][image-05]

Once logged-in, the admin UI appears. For APEX domain, enter nothing to the `Record name` field then click the `Add` button. If you want to issue the certificate for subdomains, add the subdomain to the `Record name` field. You can also issue one certificate for as many domains as you want. Here we generate one certificate for both `cnts.com` and `dev.cnts.com`.

![][image-06]

> If you prefer to creating a separate certificate for each domain, `cnts.com` and `dev.cnts.com`, then run the registration twice.

Once completed, the pop-up appears like:

![][image-07]

Let's go to the [Azure Key Vault][az kv] instance to check whether the SSL certificate has been generated or not.

![][image-08]


## SSL Certificate Binding to APEX Custom Domain on Azure Functions ##

We've got the custom APEX domain, mapped from the [previous post][post 1]. Now, it's time to bind the certificate with the domain. Go to the Azure Functions instance that I want to attach the certificate and select the `TLS/SSL settings` blade. Click the `Private Key Certificates (.pfx)` tab then `Import Key Vault Certificate` button to import the one stored in our Key Vault instance.

![][image-09]

Once imported, you can see the screen below. As we generated one certificate for both `cnts.com` and `dev.cnts.com`, it's normal to see both domain names.

![][image-10]

Let's select the `Custom domains` blade. The domain is still not bound with the SSL certificate that we just imported. Click the `Add binding` link, choose `cnts.com` for the `Custom domain` field, `cnts.com,dev.cnts.com` for the `Private Certificate Thumbprint` field. And finally, choose `SNI SSL` for the `TLS/SSL Type` field.

![][image-11]

Now we can see the SSL certificate is properly bound with the custom APEX domain.

![][image-12]

---

So far, we've walked through how [Let's Encrypt][letsencrypt] SSL certificate can be bound with a Custom APEX domain on [Azure Functions][az func] instance. In the next post, I'll discuss how the inbound IP of the Azure Functions instance is automatically updated to the A Record of [Azure DNS][az dns].


[image-01]: https://sa0blogs.blob.core.windows.net/devkimchi/2020/10/lets-encrypt-ssl-certificate-on-azure-functions-01-en.png
[image-02]: https://sa0blogs.blob.core.windows.net/devkimchi/2020/10/lets-encrypt-ssl-certificate-on-azure-functions-02-en.png
[image-03]: https://sa0blogs.blob.core.windows.net/devkimchi/2020/10/lets-encrypt-ssl-certificate-on-azure-functions-03-en.png
[image-04]: https://sa0blogs.blob.core.windows.net/devkimchi/2020/10/lets-encrypt-ssl-certificate-on-azure-functions-04-en.png
[image-05]: https://sa0blogs.blob.core.windows.net/devkimchi/2020/10/lets-encrypt-ssl-certificate-on-azure-functions-05-en.png
[image-06]: https://sa0blogs.blob.core.windows.net/devkimchi/2020/10/lets-encrypt-ssl-certificate-on-azure-functions-06-en.png
[image-07]: https://sa0blogs.blob.core.windows.net/devkimchi/2020/10/lets-encrypt-ssl-certificate-on-azure-functions-07-en.png
[image-08]: https://sa0blogs.blob.core.windows.net/devkimchi/2020/10/lets-encrypt-ssl-certificate-on-azure-functions-08-en.png
[image-09]: https://sa0blogs.blob.core.windows.net/devkimchi/2020/10/lets-encrypt-ssl-certificate-on-azure-functions-09-en.png
[image-10]: https://sa0blogs.blob.core.windows.net/devkimchi/2020/10/lets-encrypt-ssl-certificate-on-azure-functions-10-en.png
[image-11]: https://sa0blogs.blob.core.windows.net/devkimchi/2020/10/lets-encrypt-ssl-certificate-on-azure-functions-11-en.png
[image-12]: https://sa0blogs.blob.core.windows.net/devkimchi/2020/10/lets-encrypt-ssl-certificate-on-azure-functions-12-en.png

[post 1]: /azure/3-ways-to-map-apex-domains-to-azure-functions-4m6i/
[post 2]: /azure/binding-let-s-encrypt-ssl-certificate-to-azure-functions-529a
[post 3]: /2020/10/21/tbp/
[post 4]: /2020/10/28/tbp/

[az func]: https://docs.microsoft.com/azure/azure-functions/functions-overview?WT.mc_id=devto-blog-juyoo
[az func mi]: https://docs.microsoft.com/azure/app-service/overview-managed-identity?tabs=dotnet&WT.mc_id=devto-blog-juyoo
[az func auth]: https://docs.microsoft.com/azure/app-service/overview-authentication-authorization?WT.mc_id=devto-blog-juyoo

[az webjob]: https://docs.microsoft.com/azure/app-service/webjobs-create?WT.mc_id=devto-blog-juyoo
[az kv]: https://docs.microsoft.com/azure/key-vault/general/overview?WT.mc_id=devto-blog-juyoo
[az dns]: https://docs.microsoft.com/azure/dns/dns-overview?WT.mc_id=devto-blog-juyoo

[gh site extension]: https://github.com/sjkp/letsencrypt-siteextension
[gh acmebot keyvault]: https://github.com/shibayan/keyvault-acmebot

[letsencrypt]: https://letsencrypt.org/

[tw shibayan]: https://twitter.com/shibayan