Certificates have various uses in AppServices. The most obvious one is to enable SSL for your application. Another use is to authenticate towards Azure KeyVault to retrieve confidential values.
In this post, we will be uploading a certificate to KeyVault. Then we will deploy it to an AppService with Azure Resource Manager. Finally, we will set a custom domain binding to use the certificate for SSL.
(If you would like to test this without buying a certificate, see below on how to create a self-signed certificate.)
Adding a Certificate to KeyVault
In PowerShell, run this script to set a couple of variables. Replace $pwd
with the password for your .pfx
file. In $file
, put the path to your file or just the name if it resides in the current folder:
$pwd = 'Password12!'
$file = 'test.local.pfx'
Next, run the following script which will extract the certificate contents. After executing, the variable $certSecureString
will contain the certificate:
$fullPath = Get-ChildItem $file
$certCollection = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2Collection
$certCollection.Import($fullPath.FullName, $pwd, [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::Exportable)
$certExport = $certCollection.Export([System.Security.Cryptography.X509Certificates.X509ContentType]::Pkcs12)
$certb64 = [System.Convert]::ToBase64String($certExport)
$certSecureString = ConvertTo-SecureString -String $certb64 -AsPlainText -Force
Finally, you can upload it to your KeyVault using the following cmdlet. Remember to replace the VaultName
with your vault’s name. Also, provide a name that is appropriate to your environment and usage:
Set-AzureKeyVaultSecret -VaultName demokeyvault -Name democert1 -SecretValue $certSecureString -ContentType 'application/x-pkcs12'
You have now deployed the certificate to KeyVault and can use it in resource templates.
Deploying a Certificate from KeyVault
To deploy a certificate from KeyVault, use the Microsoft.Web/certificate
type. First, you must grant access to the Microsoft.Web provider using the following:
Set-AzureRmKeyVaultAccessPolicy -VaultName keyvault-bhany3pt7zg6k -ServicePrincipalName abfa0a7c-a6b6-4736-8310-5855508787cd -PermissionsToSecrets get
The service principal name is a constant across all Azure subscriptions and for all resource providers. You have now given the provider read access to the vault.
Here is an example resource template:
{
"apiVersion": "2015-08-01",
"location": "[resourceGroup().location]",
"name": "kvcertificate1",
"type": "Microsoft.Web/certificates",
"properties": {
"keyVaultId": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', resourceGroup().name, '/providers/Microsoft.KeyVault/vaults/', 'demo-keyvault')]",
"keyVaultSecretName": "demo-cert1",
"serverFarmId": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', resourceGroup().name, '/providers/Microsoft.Web/serverfarms/', 'demo-asp1')]"
}
}
Provide the keyVaultId
like you would for deploying simple secrets. The keyVaultSecretName
is the name you provided to the Set-AzureKeyVaultSecret
cmdlet in step 1. Finally, serverFarmId
is the App Service Plan you want to deploy to. You deploy certificates at the App Service Plan level and reference them from the App Service.
Using the Certificate for a Custom Domain Binding and SSL
You can use a custom domain name for any AppService, but the underlying App Service Plan must run at least on tier Basic. Otherwise, you get a cryptic error message: “The parameter App Service Plan has an invalid value.”
Additionally, Azure requires specific DNS records for your domain. The easiest approach is to add a CNAME record for a subdomain pointing to the Azure App Service-provided hostname (e.g., something.azurewebsites.net). Once completed, you can use the following resource template to deploy the domain and SSL:
{
"type": "Microsoft.Web/sites/hostnameBindings",
"name": "[concat(variables('appName'), '/', 'demo.example.org')]",
"apiVersion": "2016-03-01",
"location": "[resourceGroup().location]",
"properties": {
"sslState": "SniEnabled",
"thumbprint": "[reference(resourceId('Microsoft.Web/certificates', 'democert1')).Thumbprint]"
},
"dependsOn": ["[concat('Microsoft.Web/certificates/', 'democert1')]"]
}
The property sslState
can be either SniEnabled
or IpBasedEnabled
. The thumbprint
references the certificate installed above, so it also needs a dependsOn
.
Once deployed, you have your custom domain and SSL set up. See here for a solution on how to enforce SSL in Azure App Service.
If you only want to assign the custom domain, leave the properties
object empty.
Bonus: Creating a Self-Signed Certificate for Test Purposes
If you don’t have a certificate available, you can create your own. This is only recommended for specific use cases and testing.
Open PowerShell in Administrator Mode. First, set a variable to a password of your choice. Set a second variable to a name of your choice. For testing, you can use both values provided here. The password will be removed before uploading to Azure anyway:
$pwd = 'Password12!'
$dnsName = 'test.local'
Next, execute the following script. It will use the New-SelfSignedCertificate
cmdlet to create a certificate in your local certificate store. This is why you need administrative rights to run this script. The Export-PfxCertificate
cmdlet then exports the certificate to a .pfx
file. The file is protected by the password you set above:
$file = $dnsName + '.pfx'
$certStore = 'cert:LocalMachine\My'
$cert = New-SelfSignedCertificate -DnsName $dnsName -CertStoreLocation $certStore
$certPath = $certStore + '\' + $cert.Thumbprint
$certPwd = ConvertTo-SecureString -String $pwd -Force -AsPlainText
Export-PfxCertificate -Cert $certPath -FilePath $file -Password $certPwd
You can now use this file to run through the steps above.