Search code examples
azureazure-bicepazure-container-appsazure-dns

How can I add a custom domain to Azure container app via bicep?


I have a bicep template that creates several container apps. They shall have a custom sub domain in my private DNS zone. However, I have the problem that this leads to a circular dependency: To add the CName and verification TXT record to the DNS zone, I need the FQDN and verification from the container app. On the other hand, the deployment of the container app validates the existance of these records and fails if they are not there.

A workaround I currently use involves a boolean template parameter that must be false on the first run:

param register_custom_domains bool = false

resource container_app 'Microsoft.App/containerapps@2022-03-01' = {
  // ...
  properties: {
    configuration: {
      ingress: {
        customDomains: register_custom_domains ? [
          {
            name: 'name'
            certificateId: certifcate.id
            bindingType: 'SniEnabled'
          }
        ] : null 
      }
    }
  }
}

But this naturally requires to deploy twice. Is there a better way?


Solution

  • There is a solution that works in one pass. It is based on the fact that the verification string is the same for the container app environment and the individual containers. And since the containers will get an default domain name that is composed of the container name and the container environments defaultDomain, the CNAME and TXT records can be created before the containers.

    Here is a step-by-step description to register the container app named my_container as subdomain.my-domain.com:

    1. Create container app environment with SSL certificate:
    resource container_environment 'Microsoft.App/managedEnvironments@2022-06-01-preview' = {
      name: 'cae'
      // ...
    
      resource ssl_certificate 'certificates@2022-03-01' = {
        name: 'my-certificate'
        // ...
      }
    }
    
    1. Create CNAME and TXT records in DNS zone. In my case, since the DNS zone is in another resource group, I had to use a module but this is omitted here.
    resource dns_zone 'Microsoft.Network/dnsZones@2018-05-01' existing = {
      name: 'my-domain.com'
    
      resource cname 'CNAME@2018-05-01' = {
        name: 'subdomain'
        properties: {
          TTL: 3600
          CNAMERecord: {
            cname: '${container_name}.${container_environment.properties.defaultDomain}'
          }
        }
      }
      resource verification 'TXT@2018-05-01' = {
        name: 'asuid.subdomain'
        properties: {
          TTL: 3600
          TXTRecords: [
            {
              value: [container_environment.properties.customDomainConfiguration.customDomainVerificationId]
            }
          ]
        }
      }
    }
    
    1. Create container with custom domain. Here is is important to specify the dependsOn because the bicep compiler cannot know that the domain records are required.
    resource container_app 'Microsoft.App/containerapps@2022-03-01' = {
      dependsOn: [extend_dns_zone_module]
      name: 'my_container'
      properties: {
        // ...
        configuration: {
          // ...
          ingress: {
            // ...
            customDomains: [
              {
                name: 'subdomain.my-domain.com'
                certificateId: container_environment::ssl_certificate.id
                bindingType: 'SniEnabled'
              } 
            ]
          }
       }
    }