Back to blog
AzureBest PracticesCloud SecurityCompute & ContainersNetworking

Azure Container App Allows Insecure HTTP: Why It Matters and How to Fix It

Learn why Azure Container Apps allowing insecure HTTP is a security risk and how to force HTTPS with CLI, Bicep, Terraform, and Azure Policy.

TL;DR

This check flags Azure Container Apps that accept plain HTTP traffic instead of forcing HTTPS. That leaves credentials and session data exposed to interception. Set allowInsecure to false on the ingress config to force every request onto TLS.

Azure Container Apps gives you a managed way to run containers without babysitting the underlying Kubernetes cluster. Part of that convenience is built-in ingress, complete with automatic TLS certificates for your app's default domain. But ingress has a setting that quietly undoes all of that: allowInsecure. When it's set to true, your app happily serves traffic over unencrypted HTTP, and this Lensix check exists to catch exactly that.

This post walks through what the check looks at, the real risk of leaving HTTP open, and how to lock it down with CLI, Bicep, and policy so it doesn't creep back in.


What this check detects

The containerapps_nohttps check inspects the ingress configuration of each Azure Container App in scope. Specifically, it looks at the ingress.allowInsecure property. When that property is true, the app responds to HTTP requests on port 80 without redirecting them to HTTPS, and the check fails.

By default, Container Apps redirect HTTP to HTTPS, so this is usually the result of someone explicitly turning the redirect off, often during early testing or to work around a client that struggled with TLS.

Note: Even with allowInsecure set to false, your app still listens on port 80. The difference is that Azure returns an HTTP 301 redirect to the HTTPS endpoint instead of serving the response in the clear. The container itself can stay on plain HTTP internally because TLS is terminated at the ingress.


Why it matters

Plain HTTP means every byte between the client and your ingress travels unencrypted. Anyone positioned on the network path, a compromised Wi-Fi access point, a malicious proxy, an ISP intermediary, can read and modify it. For a public-facing app that handles logins, API tokens, or any personal data, this is a direct path to credential theft.

A few concrete scenarios:

  • Session hijacking: An attacker on the same network captures a session cookie sent over HTTP and replays it to impersonate the user.
  • Credential interception: A login form posted over HTTP leaks the username and password in cleartext.
  • Response tampering: Without TLS integrity, an attacker can inject malicious JavaScript into the response, turning your app into a delivery vehicle for their payload.
  • Downgrade attacks: If clients can reach you over HTTP at all, an attacker can strip the redirect and keep the victim on the insecure channel.

There's a compliance angle too. PCI DSS, HIPAA, and most data protection frameworks require encryption of data in transit. An app serving HTTP fails that requirement outright, which can stall audits or block a product from handling regulated data.

Warning: "It's an internal app" is not a safe excuse. Internal networks are routinely the soft target after an initial breach, and lateral movement relies on sniffing exactly this kind of unencrypted traffic. Treat internal HTTP with the same suspicion as public HTTP.


How to fix it

The fix is to disable insecure connections on the app's ingress. You can do this from the CLI, the portal, or your infrastructure-as-code definitions.

Azure CLI

Update the ingress with the containerapp ingress command and set the insecure flag off:

az containerapp ingress update \
  --name my-container-app \
  --resource-group my-resource-group \
  --allow-insecure false

Verify the change took effect:

az containerapp ingress show \
  --name my-container-app \
  --resource-group my-resource-group \
  --query "allowInsecure"

It should return false. A quick functional check confirms the redirect:

curl -sI http://my-container-app.region.azurecontainerapps.io | grep -i location

You should see a Location header pointing to the https:// version of the URL.

Warning: If any clients are hardcoded to call your app over http:// and don't follow redirects, they'll break after this change. Audit your callers, especially server-to-server integrations and IoT devices that ignore 301 responses, before flipping the switch in production.

Azure Portal

  1. Open your Container App in the Azure Portal.
  2. Under Settings, select Ingress.
  3. Find the Insecure connections option and uncheck or disable Allow insecure connections.
  4. Click Save.

Bicep

If you manage Container Apps with Bicep, set allowInsecure to false in the ingress block:

resource containerApp 'Microsoft.App/containerApps@2024-03-01' = {
  name: 'my-container-app'
  location: location
  properties: {
    managedEnvironmentId: environmentId
    configuration: {
      ingress: {
        external: true
        targetPort: 8080
        allowInsecure: false
        transport: 'auto'
      }
    }
    // ... template config
  }
}

Terraform

For the AzureRM provider, the equivalent argument lives in the ingress block:

resource "azurerm_container_app" "app" {
  name                         = "my-container-app"
  container_app_environment_id = azurerm_container_app_environment.env.id
  resource_group_name          = azurerm_resource_group.rg.name
  revision_mode                = "Single"

  ingress {
    external_enabled = true
    target_port      = 8080
    allow_insecure_connections = false

    traffic_weight {
      latest_revision = true
      percentage      = 100
    }
  }

  # ... template config
}

Tip: In Terraform, allow_insecure_connections defaults to false, so simply omitting it gives you the secure behavior. Add it explicitly anyway, it documents intent and prevents a future edit from accidentally enabling HTTP.


How to prevent it from happening again

Fixing one app is easy. Keeping every app secure as your environment grows is the real work. Push the guardrails left so a misconfiguration never reaches production.

Azure Policy

Azure Policy can audit or deny Container Apps that allow insecure ingress. Here's a custom policy definition that denies any Container App with allowInsecure set to true:

{
  "properties": {
    "displayName": "Container Apps must not allow insecure HTTP",
    "policyType": "Custom",
    "mode": "All",
    "policyRule": {
      "if": {
        "allOf": [
          {
            "field": "type",
            "equals": "Microsoft.App/containerApps"
          },
          {
            "field": "Microsoft.App/containerApps/configuration.ingress.allowInsecure",
            "equals": true
          }
        ]
      },
      "then": {
        "effect": "deny"
      }
    }
  }
}

Assign it at the subscription or management group scope. Start with audit as the effect to find existing offenders, then switch to deny once you've cleaned them up.

Danger: Rolling out a deny policy across a management group will block deployments of any non-compliant template, including legitimate ones that simply haven't been updated yet. Run it in audit mode first and remediate every flagged resource before enforcing, or you risk breaking unrelated pipelines.

CI/CD gates

Catch the problem before it deploys. If you use Bicep or Terraform, add a check to your pipeline that fails the build when insecure ingress is declared. A simple grep-based guard works for a quick win:

# Fail the pipeline if any Bicep file enables insecure ingress
if grep -rn "allowInsecure: true" ./infra; then
  echo "ERROR: Container App ingress allows insecure HTTP. Set allowInsecure to false."
  exit 1
fi

For Terraform, tfsec and checkov both ship rules that flag insecure Container App ingress, so wiring one of those into your plan stage covers this and a long list of related issues at once.

Tip: Run Lensix continuously against your live subscriptions rather than relying only on pre-deploy scans. Out-of-band changes, someone toggling a setting in the portal during an incident, never touch your IaC, and only a runtime scan will catch them.


Best practices

  • Default to deny insecure traffic everywhere. Make allowInsecure: false the standard in every template and module you maintain so secure-by-default is the path of least resistance.
  • Use a custom domain with a managed certificate. The default azurecontainerapps.io domain gets TLS automatically, but production apps should run on your own domain with a managed certificate so the HTTPS guarantee extends to the name users actually see.
  • Combine with HSTS. Have your app send the Strict-Transport-Security header so browsers refuse to connect over HTTP after the first visit, closing the downgrade-attack window.
  • Limit ingress exposure. If an app only serves internal callers, set external: false so it isn't reachable from the public internet at all. HTTPS plus restricted exposure is far stronger than either alone.
  • Review ingress settings during incident postmortems. Temporary debugging changes are a classic source of long-lived misconfigurations. If someone flipped a setting during an outage, make sure it gets reverted when the dust settles.

Forcing HTTPS on a Container App is a one-line change with an outsized payoff. The harder part is making sure it stays that way across dozens of apps and frequent deployments, which is where policy, pipeline checks, and continuous scanning earn their keep.

Fix Insecure HTTP on Azure Container Apps | Lensix | Lensix