Serverless Let's Encrypt certificate renewal on Azure
- Let's Encrypt ACME certificate renewal using Azure Functions and PowerShell (Posh-ACME).
- Domain verification is performed automatically by Posh-ACME using its Azure DNS plugin and the Function App's System-Assigned Managed Identity.
- Upon renewal, updated certificate is automatically imported to Azure Key Vault as a new version of the existing certificate.
- Posh-ACME state is maintained in an Azure Storage Account Blob container, and kept in sync with the Function App using Azure PowerShell.
Setup
The following instructions assume that you are using Azure DNS with your domain. If you are not, follow the Microsoft documentation to set up an Azure DNS Zone for your domain. Tutorial: Host your domain in Azure DNS.
Installation
- Install the Posh-ACME PowerShell module on your workstation.
- Clone this git repository to your workstation.
- Deploy required Azure resources using the steps in the Infrastructure section of this document.
Generate a certificate locally
- Configure your Posh-ACME environment by following the module's tutorial.
- Generate a certificate locally by following the module's Azure tutorial.
Usage
Infrastructure
This application can be deployed to Azure by clicking the Deploy to Azure button below. NOTE: Your Azure DNS Zone must be in a Resource Group in the same Subscription as the Resource Group you are deploying to.
This application can also be deployed to Azure programmatically using Azure PowerShell or the Azure CLI.
# Azure PowerShell
New-AzResourceGroupDeployment -ResourceGroupName 'testing' -TemplateFile ./Infrastructure/main.bicep -dnsZoneName 'my-domain.com' -Verbose
# Azure CLI
az group deployment create --resource-group 'testing' --template-file ./Infrastructure/main.bicep --parameters "{ \"dnsZoneName\": { \"value\": \"my-domain.com\" } }" --verbose
Add Posh-ACME config to Storage Account
Using the Azure Storage Explorer, upload the content of your local $env:POSHACME_HOME
directory to the acme
container within the Storage Account that was created as part of the Infrastructure deployment.
Function App
- The Function App's only Function,
RenewLECerts
, is configured with a timer trigger that executes the Function once per week. You can also execute the function at-will from the VS Code extension. - If everything is configured correctly, the Function will:
- Create a Storage Account Context using the Function App's MSI.
- Use Azure PowerShell to copy the Posh-ACME state from a Blob Container to the Function App.
- Use Posh-ACME to check if the certificate(s) need to be renewed:
- If it/they does:
- Renew the certificate(s) using Posh-ACME.
- Add the updated certificate(s) to Azure Key Vault (overwriting the expired certificate(s)).
- Push the updated Posh-ACME state from the Function App to the Blob Container, ensuring only modified files are updated.
- If it/they do(es) not, do nothing.
- If it/they does:
Optional
Configure Azure CDN custom domain to use Key Vault certificate
- Navigate to your CDN profile, then to the endpoint using the Azure Portal.
- Open the CDN endpoint's custom domain that you want to assign the certificate to.
- In the custom domain, select the Key Vault certificate you just imported (make sure the Azure CDN identity can access the Key Vault).