Use Bicep to deploy Azure Container Apps with a free managed certificate
Code description
Context
A few weeks ago when I was migrating Kontext from Azure App Services to Azure Container Apps, there was no free managed certificate. To address that issue, I used Let's Encrypt to create a certificate for Kontext. This process will take me a few minutes every few months .
Now good news is that free managed certificate is also in preview in Azure Container Apps. The following code snippet shows you how to do that in Bicep.
Note:
* when I deploy using Bicep, my container app was already existing. This means the domain verification is already added to my Azure DNS zones. If you are building a new app using managed certificate, I would suggest you do it in two steps:
Bicep code to create container app enivronment, container and DNS records (incl. A record that points to IP of your container app and/or
asuid
verification TXT record).And then update Bicep code to add managed certificate and custom domains. In custom domains, you can reference the managed certificate ID directly. And then deploy Bicep code again with delta changes.
* The container image is from GitHub (not Azure Container Registry) in the following example.
Issues
When I run the deployments, Azure throws out one interim error like the following (however the deployment itself was not failing):
The client 'XXX' with object id 'XXX' does not have authorization to perform action 'Microsoft.App/locations/managedCertificateOperationStatuses/read' over scope '/subscriptions/XXX/providers/Microsoft.App/locations/Australia East/managedCertificateOperationStatuses/XXX' or the scope is invalid. If access was recently granted, please refresh your credentials. (Code: AuthorizationFailed)
After I wait for about 10 minutes the deployment becomes successful as the following screenshot does:
References
Custom domain names and bring your own certificates in Azure Container Apps
Microsoft.App managedEnvironments/managedCertificates 2022-11-01-preview
Code snippet
@description('Change it to your region') param location string = 'australiaeast' @description('Name of the Container App Environment') param containerAppEnvName string = 'container-app-env' @description('Name of the Container App') param webContainerName string = 'web-app' @description('GitHub container registry user') @secure() param gitHubUserName string @description('GitHub container registry user access token') @secure() param gitHubUserAccessToken string param logAnalyticsCutomerId string param logAnalyticsSharedKey string resource myContainerAppEnvironment 'Microsoft.App/managedEnvironments@2022-11-01-preview' = { name: containerAppEnvName location: location properties: { appLogsConfiguration: { destination: 'log-analytics' logAnalyticsConfiguration: { customerId: logAnalyticsCutomerId sharedKey: logAnalyticsSharedKey } } } } resource myManagedCert 'Microsoft.App/managedEnvironments/managedCertificates@2022-11-01-preview' = { name: 'managed-cert' location: location parent: myContainerAppEnvironment properties: { domainControlValidation: 'HTTP' subjectName: 'example-domain.com' } } resource myWebContainerApp 'Microsoft.App/containerApps@2022-11-01-preview' = { name: webContainerName location: location properties: { environmentId: myContainerAppEnvironment.id configuration: { ingress: { external: true targetPort: 8000 allowInsecure: false traffic: [ { latestRevision: true weight: 100 } ] customDomains:[ { bindingType: 'SniEnabled' certificateId: myManagedCert.id name: 'example-domain.com' } ] } registries: [ { server: 'ghcr.io' username: gitHubUserName passwordSecretRef: 'container-registry-password' } ] secrets: [ { name: 'container-registry-password' value: gitHubUserAccessToken } ] } template: { containers: [ { name: webContainerName image: 'ghcr.io/exmaple-org/example-repo:latest' resources: { cpu: any('0.5') memory: '1Gi' } env: [ { name: 'ASPNETCORE_ENVIRONMENT' value: 'AZURE' } ] } ] scale: { minReplicas: 0 maxReplicas: 1 } } } } output customDomainVerificationId string = myWebContainerApp.properties.customDomainVerificationId output appIpAddress string = myContainerAppEnvironment.properties.staticIp