3 minute read

Create a (free!) App Services Managed Certificate with Bicep

An certificates in Azure App Services is bind to an host name, this can be an apex (or naked) domain (https://robertdeveen.com) or a subdomain (https://www.robertdeveen.com or https://subdomain.robertdeveen.com), or a combination of these two (for example one certificate for https://robertdeveen.com and https://www.robertdeveen.com).

To create an App Services Managed Certificate there are two ways to create a certificate with Bicep. One for a apex domain and one for an subdomain. The validation of the ownership of the domain is the main difference. To generate a certificate the certificate authority would like to validate that the domain you try to get a certificate for is yours. That you are the owner of that (sub)domain name.

As a prerequisite you need to have an App Service Plan and an App Service or Function App with a custom domain ready. The Web App does not have a valid certificate already configured.

Create a Host Name binding without a certificate

param customHostname string = 'www.robertdeveen.com'
param webAppName string = 'robertdeveen'

resource hostNameBindingWithoutCertificate 'Microsoft.Web/sites/hostNameBindings@2022-03-01' = {
  name: '${webAppName}/${customHostname}'
  properties: {
    siteName: webAppName
    hostNameType: 'Verified'
    azureResourceType: 'Website'
    azureResourceName: webAppName
    customHostNameDnsRecordType: 'CName'
    sslState: 'Disabled'
  }
}

Create a App Services Managed Certificate for a subdomain

Create a CName record

In the DNS Zone, create a CName record pointing to *.azurewebsite.net. This is needed for the validation of the ownership of the domain.

Type Record Value
CName www.robertdeveen.nl robertdeveen.azurewebsites.net

Create a App Services Managed Certificate


param canonicalName string = 'www.robertdeveen.com'
param appServicePlanName string = 'robertdeveen-plan'
param location string = 'westeurope'

resource appServicePlan 'Microsoft.Web/serverfarms@2022-03-01' existing =  {
  name: appServicePlanName
}

resource certificate 'Microsoft.Web/certificates@2022-03-01' = {
  name: '${canonicalName}-certificate'
  location: location
  properties: {
    serverFarmId: appServicePlanResourceId
    // domainValidationMethod: 'cname-delegation' // or 'http-token'
    hostNames: [ canonicalName ]
    canonicalName: canonicalName
  }
}

Note: The documentation is not clear about the meaning of the domainValidationMethod field, it is a string. But the value that is accepted should be cname-delegation or http-token. Other values give the error message: “The parameter Properties.DomainValidationMethod has an invalid value.” The value cname-delegation is the only one working these days. The value http-token is not working anymore and just waiting a long time to end. The best solution is to not add that field.

Create a App Services Managed Certificate for an apex domain

Create a A record

In the DNS Zone, create an A records pointing to the IP address of the webapp. This is needed for the validation of the ownership of the domain.

Type Record Value
A robertdeveen.nl IP-address-of-webapp
param canonicalName string = 'robertdeveen.com'
param location string = 'westeurope'

resource nakedCertificate 'Microsoft.Web/certificates@2022-09-01' = {
  name: '${canonicalName}-certificate'
  location: location
  properties: {
    serverFarmId: appServicePlan.id
    canonicalName: canonicalName
  }
}

Create a App Services Managed Certificate for an apex and subdomain

THIS DOESN’T WORK! The documentation is not clear about this, but it is not possible to create a certificate for an apex and subdomain at the same time. You need to create two certificates, one for the apex and one for the subdomain.

// param canonicalName string = 'robertdeveen.com'
// param hostNames = [ 'www.robertdeveen.com', 'robertdeveen.com' ]
// param location string = 'westeurope'

// resource nakedCertificate 'Microsoft.Web/certificates@2022-09-01' = {
//   name: '${canonicalName}-certificate'
//   location: location
//   properties: {
//     serverFarmId: appServicePlan.id
//     hostNames: [ hostNames ]
//     canonicalName: canonicalName
//   }
// }

Bind certificate to the host name

We need to use a module to enable the certificate on the host name, as Bicep/ARM forbids using resource with this same type-name combination twice in one deployment.

module hostnameBindingWithCertificate './modules/hostname-binding.Bicep' = {
  name: '${customHostname}-hostnamebinding'
  params: {
    certificateThumbprint: certificate.outputs.thumbprint
    customHostname: customHostname
    webAppName: webAppName
  }
}

./module/hostname-binding.Bicep

resource hostNameBindingWithCertificate 'Microsoft.Web/sites/hostNameBindings@2022-03-01' = {
  name: '${webAppName}/${customHostname}'
  properties: {
    siteName: webAppName
    sslState: 'SniEnabled'
    thumbprint: certificateThumbprint
  }
}

Comments