Certificates have various uses in AppServices. The most obvious one is to enable SSL for your application. Another use it 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 you 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.

{
   "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 your 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.”.

Also for Azure to allow you to use a domain specific name server records must be set. The easiest is to add a CNAME record for a subdomain pointing to the Azure App Service provided hostname (i.e. 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 you’ve deployed you have your custom domaina and SSL set-up. See here for a solution on how to enforce SSL in Azure App Service.

By the way 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 recomended for specific use cases and testing.

Open a 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 anyhow.

$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. Next the Export-PfxCertificate cmdlet exports the certificate to a .pfx file. The file is protected by the password you set above.

$file = $dnsName + '.pfx'
$certStore = 'cert:LocalMachineMy'
$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.

Advertisement