Azure resources that participate in service-to-service communications can authenticate their peers with client certificates, in a mutual TLS handshake. Disabling that mechanism leaves the endpoint relying on weaker controls, such as passwords or network position alone, to establish trust between the two parties.

Why is this an issue?

Several Azure services let workloads authenticate their peers with client certificates over TLS, establishing mutual trust between the two ends of the connection. Unlike a shared password, a certificate cannot be forged or replayed by a man-in-the-middle, and its private key never leaves the holder, which makes it considerably harder to steal.

This rule targets resources used for internal, machine-to-machine traffic, where mTLS is the industry-standard authentication mechanism. Externally-facing endpoints handling browser or mobile traffic are out of scope, since certificate-based authentication is impractical there.

Disabling client certificate authentication on an internal resource, or selecting an authentication mode that does not require a certificate, removes the mutual-trust guarantee. The endpoint must then rely on weaker controls, such as passwords or network reachability, to decide whether the caller is legitimate.

Certificates also support precise incident response. Compromised certificates can be revoked individually, and an issuing certificate authority can be revoked to invalidate every certificate it produced. Authentication mechanisms that do not rely on certificates do not offer that level of traceability and containment.

What is the potential impact?

Without client certificate authentication, an attacker who learns a shared password or reaches the endpoint over the network can impersonate the legitimate caller. Depending on what the affected resource handles, this exposes data flowing through the endpoint, the credentials it stores, or any downstream system it integrates with.

Recovery is also harder. A password leak typically forces a rotation across every caller that knows it, whereas certificate-based authentication scopes the blast radius to a single revoked credential and preserves an audit trail of which certificate was used.

How to fix it in Azure App Service

Set clientCertEnabled to true and clientCertMode to Required on the Microsoft.Web/sites (or Microsoft.Web/sites/slots) resource.

Code examples

The following code disables client certificate authentication on an Azure resource, leaving the endpoint to rely on weaker controls such as passwords, or on no peer authentication at all.

Noncompliant code example

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "resources": [
    {
      "type": "Microsoft.Web/sites",
      "apiVersion": "2022-03-01",
      "name": "internal-api",
      "properties": {
        "publicNetworkAccess": "Disabled",
        "clientCertEnabled": true,
        "clientCertMode": "Optional"
      }
    }
  ]
}
resource internalApi 'Microsoft.Web/sites@2022-03-01' = {
  name: 'internal-api'
  properties: {
    publicNetworkAccess: 'Disabled'
    clientCertEnabled: true
    clientCertMode: 'Optional' // Noncompliant
  }
}

Compliant solution

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "resources": [
    {
      "type": "Microsoft.Web/sites",
      "apiVersion": "2022-03-01",
      "name": "internal-api",
      "properties": {
        "publicNetworkAccess": "Disabled",
        "clientCertEnabled": true,
        "clientCertMode": "Required"
      }
    }
  ]
}
resource internalApi 'Microsoft.Web/sites@2022-03-01' = {
  name: 'internal-api'
  properties: {
    publicNetworkAccess: 'Disabled'
    clientCertEnabled: true
    clientCertMode: 'Required'
  }
}

How to fix it in Azure SignalR Service

Set tls.clientCertEnabled to true on the Microsoft.SignalRService/signalR or Microsoft.SignalRService/webPubSub resource.

Code examples

The following code disables client certificate authentication on an Azure resource, leaving the endpoint to rely on weaker controls such as passwords, or on no peer authentication at all.

Noncompliant code example

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "resources": [
    {
      "type": "Microsoft.SignalRService/webPubSub",
      "apiVersion": "2021-10-01",
      "name": "internal-bus",
      "properties": {
        "publicNetworkAccess": "Disabled",
        "tls": {
          "clientCertEnabled": false
        }
      }
    }
  ]
}
resource internalBus 'Microsoft.SignalRService/webPubSub@2021-10-01' = {
  name: 'internal-bus'
  properties: {
    publicNetworkAccess: 'Disabled'
    tls: {
      clientCertEnabled: false // Noncompliant
    }
  }
}

Compliant solution

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "resources": [
    {
      "type": "Microsoft.SignalRService/webPubSub",
      "apiVersion": "2021-10-01",
      "name": "internal-bus",
      "properties": {
        "publicNetworkAccess": "Disabled",
        "tls": {
          "clientCertEnabled": true
        }
      }
    }
  ]
}
resource internalBus 'Microsoft.SignalRService/webPubSub@2021-10-01' = {
  name: 'internal-bus'
  properties: {
    publicNetworkAccess: 'Disabled'
    tls: {
      clientCertEnabled: true
    }
  }
}

How to fix it in Azure Container Apps

Set configuration.ingress.clientCertificateMode to require on the Microsoft.App/containerApps resource.

Code examples

The following code disables client certificate authentication on an Azure resource, leaving the endpoint to rely on weaker controls such as passwords, or on no peer authentication at all.

Noncompliant code example

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "resources": [
    {
      "type": "Microsoft.App/containerApps",
      "apiVersion": "2022-10-01",
      "name": "internal-worker",
      "properties": {
        "configuration": {
          "ingress": {
            "external": false,
            "clientCertificateMode": "accept"
          }
        }
      }
    }
  ]
}
resource internalWorker 'Microsoft.App/containerApps@2022-10-01' = {
  name: 'internal-worker'
  properties: {
    configuration: {
      ingress: {
        external: false
        clientCertificateMode: 'accept' // Noncompliant
      }
    }
  }
}

Compliant solution

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "resources": [
    {
      "type": "Microsoft.App/containerApps",
      "apiVersion": "2022-10-01",
      "name": "internal-worker",
      "properties": {
        "configuration": {
          "ingress": {
            "external": false,
            "clientCertificateMode": "require"
          }
        }
      }
    }
  ]
}
resource internalWorker 'Microsoft.App/containerApps@2022-10-01' = {
  name: 'internal-worker'
  properties: {
    configuration: {
      ingress: {
        external: false
        clientCertificateMode: 'require'
      }
    }
  }
}

How to fix it in Azure API Management

Set negotiateClientCertificate to true on the Microsoft.ApiManagement/service/gateways/hostnameConfigurations resource.

Code examples

The following code disables client certificate authentication on an Azure resource, leaving the endpoint to rely on weaker controls such as passwords, or on no peer authentication at all.

Noncompliant code example

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "resources": [
    {
      "type": "Microsoft.ApiManagement/service/gateways/hostnameConfigurations",
      "apiVersion": "2022-11-01",
      "name": "service/gateway/m2m-host",
      "properties": {
        "negotiateClientCertificate": false
      }
    }
  ]
}
resource m2mHost 'Microsoft.ApiManagement/service/gateways/hostnameConfigurations@2022-11-01' = {
  name: 'm2m-host'
  properties: {
    negotiateClientCertificate: false // Noncompliant
  }
}

Compliant solution

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "resources": [
    {
      "type": "Microsoft.ApiManagement/service/gateways/hostnameConfigurations",
      "apiVersion": "2022-11-01",
      "name": "service/gateway/m2m-host",
      "properties": {
        "negotiateClientCertificate": true
      }
    }
  ]
}
resource m2mHost 'Microsoft.ApiManagement/service/gateways/hostnameConfigurations@2022-11-01' = {
  name: 'm2m-host'
  properties: {
    negotiateClientCertificate: true
  }
}

How to fix it in Azure Data Factory

Data Factory linked services of type Web or HttpServer, and pipeline WebActivity / WebHook activities, call external endpoints from the integration runtime. The authenticationType field selects how the runtime authenticates to the remote endpoint, and any value other than ClientCertificate disables certificate-based authentication.

Code examples

The following code disables client certificate authentication on an Azure resource, leaving the endpoint to rely on weaker controls such as passwords, or on no peer authentication at all.

Noncompliant code example

A linked service authenticating with a basic password:

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "resources": [
    {
      "type": "Microsoft.DataFactory/factories/linkedservices",
      "apiVersion": "2018-06-01",
      "name": "factories/example",
      "properties": {
        "type": "Web",
        "typeProperties": {
          "authenticationType": "Basic"
        }
      }
    }
  ]
}
resource example 'Microsoft.DataFactory/factories/linkedservices@2018-06-01' = {
  name: 'example'
  properties: {
    type: 'Web'
    typeProperties: {
      authenticationType: 'Basic' // Noncompliant
    }
  }
}

A pipeline WebActivity authenticating with a basic password:

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "resources": [
    {
      "type": "Microsoft.DataFactory/factories/pipelines",
      "apiVersion": "2018-06-01",
      "name": "factories/example",
      "properties": {
        "activities": [
          {
            "name": "CallEndpoint",
            "type": "WebActivity",
            "typeProperties": {
              "url": "https://example.com",
              "method": "POST",
              "authenticationType": "Basic"
            }
          }
        ]
      }
    }
  ]
}
resource example 'Microsoft.DataFactory/factories/pipelines@2018-06-01' = {
  name: 'example'
  properties: {
    activities: [
      {
        name: 'CallEndpoint'
        type: 'WebActivity'
        typeProperties: {
          url: 'https://example.com'
          method: 'POST'
          authenticationType: 'Basic' // Noncompliant
        }
      }
    ]
  }
}

Compliant solution

A linked service authenticating with a client certificate:

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "resources": [
    {
      "type": "Microsoft.DataFactory/factories/linkedservices",
      "apiVersion": "2018-06-01",
      "name": "example",
      "properties": {
        "type": "Web",
        "typeProperties": {
          "authenticationType": "ClientCertificate"
        }
      }
    }
  ]
}
resource example 'Microsoft.DataFactory/factories/linkedservices@2018-06-01' = {
  name: 'example'
  properties: {
    type: 'Web'
    typeProperties: {
      authenticationType: 'ClientCertificate'
    }
  }
}

A pipeline WebActivity authenticating with a client certificate:

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "resources": [
    {
      "type": "Microsoft.DataFactory/factories/pipelines",
      "apiVersion": "2018-06-01",
      "name": "example",
      "properties": {
        "activities": [
          {
            "name": "CallEndpoint",
            "type": "WebActivity",
            "typeProperties": {
              "url": "https://example.com",
              "method": "POST",
              "authenticationType": "ClientCertificate"
            }
          }
        ]
      }
    }
  ]
}
resource example 'Microsoft.DataFactory/factories/pipelines@2018-06-01' = {
  name: 'example'
  properties: {
    activities: [
      {
        name: 'CallEndpoint'
        type: 'WebActivity'
        typeProperties: {
          url: 'https://example.com'
          method: 'POST'
          authenticationType: 'ClientCertificate'
        }
      }
    ]
  }
}

How to fix it in Azure Container Registry

A Container Registry token can authenticate clients with either certificates or passwords. Defining only passwords leaves the registry without a certificate-based credential, so clients fall back to shared secrets that are easier to steal and harder to revoke individually.

Code examples

The following code disables client certificate authentication on an Azure resource, leaving the endpoint to rely on weaker controls such as passwords, or on no peer authentication at all.

Noncompliant code example

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "resources": [
    {
      "type": "Microsoft.ContainerRegistry/registries/tokens",
      "apiVersion": "2022-12-01",
      "name": "registries/example",
      "properties": {
        "credentials": {
          "passwords": [
            {
              "name": "password1"
            }
          ]
        }
      }
    }
  ]
}
resource example 'Microsoft.ContainerRegistry/registries/tokens@2022-12-01' = {
  name: 'example'
  properties: {
    credentials: {
      passwords: [ // Noncompliant
        {
          name: 'password1'
        }
      ]
    }
  }
}

Compliant solution

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "resources": [
    {
      "type": "Microsoft.ContainerRegistry/registries/tokens",
      "apiVersion": "2022-12-01",
      "name": "example",
      "properties": {
        "credentials": {
          "certificates": [
            {
              "name": "certificate1",
              "encodedPemCertificate": "[base64-encoded certificate]"
            }
          ]
        }
      }
    }
  ]
}
resource example 'Microsoft.ContainerRegistry/registries/tokens@2022-12-01' = {
  name: 'example'
  properties: {
    credentials: {
      certificates: [
        {
          name: 'certificate1'
          encodedPemCertificate: '[base64-encoded certificate]'
        }
      ]
    }
  }
}

The same pattern of providing a list of accepted client certificates also applies to two other Azure resources that the rule flags. On Microsoft.DocumentDB/cassandraClusters, populate clientCertificates with the operator certificates that should be allowed to connect. On Microsoft.ServiceFabric/clusters, populate clientCertificateCommonNames or clientCertificateThumbprints with the same intent. In both cases, leaving the list empty (or omitting it) leaves the resource without certificate-based authentication.

Resources

Documentation

Standards