App Service Certificates with Azure App Service
Azure app services allow you to apply a custom domain to let users of your app access it from your own URL, for example, myapp.mydomain.com
.
To be able to use a custom URL you must own the domain that you're trying to add (you need to have purchased the domain through a domain registrar).
When you want to secure the custom domain for your app service, you will need an SSL certificate. These days this is non-negotiable, as almost every browser will show security warnings if you don't have one.
One option for an SSL that Azure provides is an App Service Certificate (ASC), not to be confused with an Azure Managed App Service Certificate, which is a topic for another day. An App Service Certificate is a resource you can purchase in Azure and is provided via GoDaddy which acts as the certificate authority.
This comes with some great benefits:
- The certificate is managed within Azure alongside your other resources, and so forms part of the overall solution
- There is direct integration with many services in Azure, such as key vault and app service
- You can include the certificate resource as part of automation
- Azure provides the option to auto-renew the certificate (this is very useful and the main reason for choosing it)
How the App Service Certificate is Configured
Before we can add the certificate to our app there are some key things to be aware of:
- The app service certificate will need to be configured to be stored within an Azure Key Vault
- This key vault must be using the Access Policies authorization mode (not RBAC)
- The certificate itself is stored as a 'secret' object within the Key Vault, not a 'certificate' object
Point 3 can be a little confusing to get your head around. Basically the content of the certificate is stored as a secret value within the Key Vault, with a content type of application/x-pkcs12
. It will then have a Download as a certificate
button in the secret:
At no point is the certificate imported into the Key Vault as a certificate object. You can do this manually if you want to, which can be useful to integrate with other services in Azure. Just remember though that when your certificate renews, you will need to re-import it as a certificate within the Key Vault.
Some Azure services are setup to be able to handle the fact the certificate is stored as a secret (app service being one of them).
Adding the Certificate to an App Service
Setting the custom domain
To add the certificate to the app we need to first check that the custom domain is set up. Note that custom domains are only supported on app service plans of 'Shared' or higher.
You need to ensure that the corresponding TXT record has been added to your domain provider's DNS before you can set the custom domain. This proves to Azure that you actually own the domain you're trying to use.
This TXT record needs to have a host of asuid
and a value of the custom domain verification Id for your web app, which you can find on the custom domains blade in the Azure portal:
Here is some PowerShell that can help add the custom domain, or you can add this directly within the Azure portal.
# Define some variables
$AppServiceResourceGroupName = "rg-js-blog"
$AppServiceName = "app-joesumpner-blog"
$DomainName = "joesumpner.com"
# First get the web app - this assumes the app exists
$webApp = Get-AzWebApp `
-ResourceGroupName $AppServiceResourceGroupName `
-Name $AppServiceName
Write-Host "You need to configure the following DNS record at your domain provider before continuing:" -ForegroundColor Cyan
Write-Host "A TXT record that maps 'asuid.$DomainName' to the domain verification ID $($webApp.CustomDomainVerificationId)" -ForegroundColor Cyan
Write-Host ""
Read-Host "Once complete, press [Enter] to continue..."
# Add the custom domain by updating the host names (this will overwrite any existing ones!)
# Note that to use custom domains your app service must be on at least the 'Shared' tier
Set-AzWebApp `
-Name $AppServiceName `
-ResourceGroupName $AppServiceResourceGroupName `
-HostNames @($DomainName,"$AppServiceName.azurewebsites.net")
Write-Host "Custom domain '$DomainName' set" -ForegroundColor Green
You can check the domain has been successfully added in the portal (at this point there will still be no SSL binding):
Import the app service certificate
To secure the custom domain, we need to bind the app service certificate to it. For that we need the certificate to be imported into the app service. I find this easier to do within PowerShell, as the experience in the portal doesn't seem to be able to pick up certificates that are stored as secrets by default.
We start by getting a reference to the app service certificate resource (there's no set of cmdlets that let us do this directly, so we use Get-AzResource
):
$CertSubscriptionId = "<subscription-id-containing-the-app-service-certificate>"
$CertResourceGroupName = "<resource-group-containing-the-app-service-certificate>"
$CertName = "<app-service-certificate-resource-name>" # This is NOT the domain name
$ascResourceId = "/subscriptions/$CertSubscriptionId/resourceGroups/$CertResourceGroupName/providers/Microsoft.CertificateRegistration/certificateOrders/$CertName"
$ascResource = Get-AzResource -ResourceId $ascResourceId -ExpandProperties
This gives us access to the keyVaultId
and keyVaultSecretName
properties we can use to import the certificate:
$kvId = $ascResource.Properties.certificates[0].$CertName.keyVaultId
$keyVaultSecretName = $ascResource.Properties.certificates[0].$CertName.KeyVaultSecretName
Grant permissions for the app service to the certificate
Now we can import the certificate to the app service. To do that, the app service will need to have write permissions on the key vault. It's not exactly clear why this is, and it's not very well documented, but it won't work without this.
To be clear, this needs to be write permissions at the resource level within the RBAC model (even though the key vault needs to be set up to use Access Policies). I managed to get this to work by assigning the app service system-assigned managed identity the Contributor
role on the key vault containing the app service certificate.
You will also need to give the 'Microsoft Azure App Service' principal the Secrets:Get
permission as an access policy. This is used internally by Azure to access the certificate and import it into the app.
Now we can import the certificate:
# Note that the 'CertName' parameter is actually the secret name when using an App Service Certificate
# App Service Certificates create a secret in the key vault which contains the contents of the certificate
# They don't actually create a certificate object
# App service is set up to handle this though and will still pick up the certificate properly
# If the certificate already exists it will just be overwritten
Import-AzWebAppKeyVaultCertificate `
-ResourceGroupName $AppServiceResourceGroupName `
-WebAppName $AppServiceName `
-KeyVaultName $kvId `
-CertName $keyVaultSecretName
Once that's complete, we should have the certificate available as a .pfx under 'Bring your own certificates (.pfx)'
Bind the SSL certificate to the custom domain
Now we have the certificate and the custom domain we can bind them together. Again we can do this directly in the portal, or here is a way via PowerShell.
First we need the thumbprint of the certificate, which we can get from the app service certificate resource we got earlier:
$thumbprint = $ascResource.Properties.signedCertificate.thumbprint
Then we can add the SSL binding:
# If the binding already exists it will just be overwritten
New-AzWebAppSSLBinding `
-ResourceGroupName $AppServiceResourceGroupName `
-WebAppName $AppServiceName `
-Thumbprint $thumbprint `
-Name $DomainName
The custom domain should then show as verified with the binding in the portal.
Conclusion
App Service Certificates are a great way to simplify some of the management of SSL certificates in Azure and to secure the custom domains on your web apps. There are however some pitfalls/configuration to be aware of to make sure it all works smoothly.
The key things to remember are:
- Your key vault must be using the 'Access Policies' authorization mode
- The certificate is stored as a secret object in the key vault, not a certificate object
- The 'Microsoft Azure App Service' service principal must have the
Secrets:Get
permission on the key vault - The app service must have write permissions on the key vault (via a managed identity), e.g. the Contributor RBAC role
- You need to set up the verification TXT record within DNS for your custom domain