Skip to content

Secure your Azure Container Apps Environment (Part 01)

By now we all know Azure Container Apps is an amazing service, which provides us with a quick way to get up and running with the deployment of our containerized workloads. Azure Container Apps also gives us the opportunity of using containers at scale without the complexities of managing our own Kubernetes cluster. However, Azure Container apps is a configurable PaaS service and is not secure by default. In this article, which is part 01 of a series, I will cover some of the configuration options we have available to make our deployments more secure.

Securing the development process

Typically, the container development lifecycle would look something like this.

In this process we have a couple of steps where vulnerabilities can creep in. In the spirit of shifting security left, we can make some important decisions about the development cycle, which can already give us a much stronger overall security posture.

Giving developers the correct level of permissions to Azure DevOps

A common pitfall is giving developers way too much access on Azure DevOps projects. Developers do not need Project Administrator permissions on Azure DevOps to perform development activities. Scope permissions to the correct projects and give least privilege permissions in Azure DevOps.

Use private Azure DevOps agents and a private Azure Container Registry

If we are using a private Azure Container registry, we need to be able to reach this registry over the private network. This forces us to use either self-hosted DevOps agents or a managed Azure DevOps pool.

Configure a Service principal for deployment of containers

  1. Create an app registration in Microsoft Entra and copy the "Application (client) ID" value: Create app registration

  2. Create a client secret and copy the secret value: Add credentials - add client secret

  3. Assign the AcrPush role to the create app registration on your Azure Container Registry resource

  4. Create a service connection in Azure DevOps:

    • Service Connection Type: Docker registry -> Others

    • Use the Application ID and Secret values from the created app registration

  5. Use this service principal in your Azure DevOps pipelines to login to container registry

    - task: Docker@2
      displayName: Login to ACR
      inputs:
        command: login
        containerRegistry: <Docker Service Connection name> 

Reference secrets from Key Vault reducing risk of exposure of secrets

Unlike other Azure services like Azure App service, secrets cannot directly be referenced from using environment variables from the Azure Key Vault using Azure Container Apps. In order to reference secrets from Azure Key Vault we need to do the following:

  1. Add secrets to Azure Key Vault, either manually or with a pipeline.
  2. Assign the secretsUser role to the user/system assigned managed identity assigned to your container app.
  3. Create a bicep deployment of the Azure Container App with secrets defined. Bicep reference
secrets: [
  {
    name: "<secretName>"
    keyVaultUrl: "https://<keyVaultName>.vault.azure.net/secrets/<secretName>"
    identity: "<user/system assigned identity ID>"
  }
]
  1. Reference the secrets created in your environment variables. Bicep reference
"env": [
  {
    "name": "<envVarName>",
    "secretRef": "<secretName>"
  }
]
  1. Access the environment variables in your container code

Securing Identity

In the development process we have already used secure identities by using the user/system assigned managed identities to make connections from Azure Container Apps to other Azure services. Some examples:s

  • Use managed identity of the Azure Container App to use secrets from the Azure Key Vault (with secretsUser RBAC role)
  • Use Azure Container App to pull images from Azure Container Registry (with acrPull RBAC role)
  • Created app registration and Service Connection in Azure DevOps to push container images to Azure Container Registry (using acrPush RBAC role)

Securing the network

Next we will look into securing the Azure Container environment from a network perspective. The image below, describes a baseline for network security in aligment with Azure security baseline for Azure Container Apps

The implementation conforms with the baseline as a result of the following controls:

  1. Establish network segmentation boundaries The Azure Container Apps Environment is deployed into the VNet by using the internal flag and referencing a subnetId. bicep reference
resource containerAppEnv 'Microsoft.App/managedEnvironments@2022-03-01' = {
  name: containerAppEnvName
  location: location
  properties: {
    appLogsConfiguration: {
      destination: 'log-analytics'
      logAnalyticsConfiguration: {
        customerId: logAnalytics.properties.customerId
        sharedKey: logAnalytics.listKeys().primarySharedKey
      }
    }
    vnetConfiguration: {
      infrastructureSubnetId: vnet.properties.subnets[0].id
      internal: true
    }
  }
}

Network security groups can be configured on the Container App Environment infra subnet

  1. Secure cloud services with network controls

As a result of the Container App Environment being deployed into the private virtual network and the Container App Environment only having a private IP, network traffic can be controlled to and from the private subnet.

Ingress network traffic can be routed through an Azure Front Door or an Application Gateway, with the appropriate WAF rules applied. Egress traffic from the Container Apps Environment can be routed through the Hub Azure Firewall using User Defined Routes, to ensure good network segmentation and avoid other vulnerabilities, such as data exfiltration.

In Part 02 of this series we will look into some more detail on how to configure the deployment of an internal Container Apps Environment and supporting components. We will also look into solving internal DNS challenges by registering your Azure Container Apps private DNS zones.