Skip to content

mTLS Failures

Symptom

  • The app never sees X-Forwarded-Client-Cert.
  • Ingress returns 403 when clientCertificateMode=require.
  • App code reports certificate parsing or chain validation failures.
  • Dapr sidecar logs show mTLS handshake or invocation failures.
  • Traffic inside the environment appears unencrypted after peer encryption was expected.
flowchart TD
    Start[mTLS failure] --> Edge{Edge or internal?}
    Edge -->|Ingress| IngressCheck[Check clientCertificateMode and client cert send path]
    Edge -->|App code| AppCheck[Parse and validate leaf certificate]
    Edge -->|Dapr| DaprCheck[Review Dapr sidecar logs and App IDs]
    Edge -->|Peer encryption| EnvCheck[Review managed environment encryption settings]
    IngressCheck --> Fix[Apply targeted fix and retest]
    AppCheck --> Fix
    DaprCheck --> Fix
    EnvCheck --> Fix

Possible Causes

  • clientCertificateMode is ignore, so ingress never forwards the header.
  • The client does not actually send a certificate during the TLS handshake.
  • App code parses the entire XFCC header instead of the leaf Cert= segment.
  • The Dapr caller uses the wrong App ID or bypasses the sidecar.
  • Environment peer encryption was never enabled or was enabled in a different environment than expected.

Diagnosis Steps

1. Missing X-Forwarded-Client-Cert header at the app

Check ingress mode first:

az containerapp show \
  --name "$APP_NAME" \
  --resource-group "$RG" \
  --query "properties.configuration.ingress.clientCertificateMode" \
  --output tsv
Command Why it is used
az containerapp show ... Reads the Container App configuration so the documented setting can be verified.

If the value is ignore, the absence of the header is expected.

2. 403 from ingress with clientCertificateMode=require

Test the endpoint with and without a client certificate:

curl --include "https://${FQDN}/cert-info"

curl --include \
  --cert "./client.pem" \
  --key "./client.key" \
  "https://${FQDN}/cert-info"

If only the second call succeeds, ingress enforcement is working and the first caller simply lacked a certificate.

3. Chain validation or parsing failure in app code

Look for these anti-patterns:

  • Parsing the whole header instead of Cert=.
  • Treating escaped newlines as literal text.
  • Comparing the wrong thumbprint algorithm.
  • Validating only CN when your policy actually depends on issuer or SAN.

4. Dapr sidecar mTLS handshake issues

Check Dapr configuration and app identity:

az containerapp show \
  --name "$APP_NAME" \
  --resource-group "$RG" \
  --query "properties.configuration.dapr" \
  --output json

az containerapp logs show \
  --name "$APP_NAME" \
  --resource-group "$RG" \
  --type system
Command Why it is used
az containerapp show ... Reads the Container App configuration so the documented setting can be verified.

Confirm that:

  • Dapr is enabled on both caller and callee.
  • The caller uses the correct Dapr App ID.
  • The app is calling localhost:3500 and not bypassing the sidecar by accident.

5. Environment-internal traffic still looks unencrypted

Review the managed environment:

az containerapp env show \
  --name "$ACA_ENV_NAME" \
  --resource-group "$RG" \
  --query "properties.peerTrafficConfiguration" \
  --output json
Command Why it is used
az containerapp env show ... Reads managed environment settings for networking, logging, or workload profile verification.

If the property is empty or encryption is disabled, peer encryption was never turned on for that environment.

Resolution

  • Set clientCertificateMode to require or accept when the app needs XFCC.
  • Ensure testing clients provide both --cert and --key.
  • Parse only the leaf Cert= element from X-Forwarded-Client-Cert.
  • Correct Dapr App IDs and force all Dapr traffic through the sidecar endpoint.
  • Enable peerTrafficConfiguration.encryption.enabled on the managed environment when direct internal traffic must be encrypted.

Prevention

  • Keep ingress mode, certificate policy, and route ownership documented together.
  • Add a /cert-info or equivalent diagnostics endpoint in lower environments.
  • Monitor Dapr system logs during rollout of new App IDs or sidecar config.
  • Validate managed environment encryption settings as part of environment provisioning.

See Also

Sources