Skip to main content

mTLS

Use mTLS profiles when client identity is established at TLS termination.

Runtime caveat (code-grounded)

  • Gateway middleware does not parse/verify certificates itself for profile auth type mtls.
  • Certificate validation is expected at ingress/TLS layer.
  • Zerq still enforces profile checks, IP/method restrictions, and policy limits after ingress.

Required headers and behavior

  • X-Client-ID: identifies the calling app or partner integration.
  • X-Profile-ID: selects the active policy/auth profile.
  • Authorization: typically not required for mTLS profile auth itself.

Status-code mapping

  • 403: IP restrictions, collection access deny, or profile mismatch
  • 405: method not allowed by profile
  • 429: policy/rate limits

401 for certificate failures usually comes from ingress/LB, not gateway middleware.

Example

curl -i https://gateway.example.com/orders/123 \
-H "X-Client-ID: acme-mobile" \
-H "X-Profile-ID: partner-prod" \
--cert client.pem --key client.key \
-H "Accept: application/json"

Expected outcomes: successful request returns 200; missing or untrusted cert should return 401; mapped policy deny should return 403.

Certificate example (test setup)

Create a client certificate and key for test traffic:

# 1) Private key
openssl genrsa -out client.key 2048

# 2) CSR (example subject values)
openssl req -new -key client.key -out client.csr \
-subj "/CN=acme-mobile/OU=partner-prod/O=ExampleCorp/C=US"

# 3) Sign with your CA
openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key \
-CAcreateserial -out client.crt -days 365 -sha256

Practical mapping commonly used at the edge:

  • CN -> client identity (example: acme-mobile)
  • OU -> profile identity (example: partner-prod)

Edge proxy forwarding example (nginx)

ssl_client_certificate /etc/nginx/certs/ca.crt;
ssl_verify_client on;

location / {
proxy_pass http://backend:8080;
proxy_set_header X-Client-ID $ssl_client_s_dn_cn;
proxy_set_header X-Profile-ID $ssl_client_s_dn_ou;
}

Use this pattern only behind trusted ingress where clients cannot spoof these headers directly.

Evidence to capture

  • Policy decision records tied to X-Client-ID and X-Profile-ID.
  • Authentication reason codes for denied requests (401 vs 403).
  • Final profile-policy mapping used by the request.

Extra negative test

Use a valid Authorization token with a client ID not bound to the profile. Zerq should deny with 403 and log a client-profile mismatch.

Rollback checkpoint

If policy updates over-block traffic, restore the previous client/profile binding set and retest one approved path and one denied path before reapplying finer-grained rules.