mTLS

Client certificates for outgoing connections and certificate-based authentication of API clients on channels.

Overview

An mTLS security definition describes authentication with client certificates - during the TLS handshake the client presents its own certificate and the server verifies it, so both sides authenticate instead of just the server. There are no headers and no tokens, the authentication happens entirely at the TLS layer.

One definition type serves both directions of traffic, and each direction uses a different set of fields:

  • Outgoing - Zato presents a client certificate when it calls a remote REST or SOAP endpoint that requires one. The definition holds paths to the certificate material mounted into the container.
  • Channels - Zato authenticates API clients by the client certificate they presented to the TLS-terminating proxy in front of the server. The definition contains the match criteria - the expected certificate fingerprint or subject DN.

Definitions are managed in the dashboard under Security > mTLS. There is no password and no change-password action - the certificate material is the credential. Changes take effect immediately, without server restarts.

Definition fields

Fields used by outgoing connections:

FieldNotes
NameA unique name for the definition
Certificate pathPath to the client certificate in PEM format, as mounted into the container
Key pathPath to the certificate's private key in PEM format. Leave empty when the certificate file already contains the key.
CA certificates pathOptional path to a CA bundle that the remote server's certificate must chain up to. When set, it replaces the connection's default TLS verification.

Fields used by channels:

FieldNotes
Client certificate fingerprintThe SHA256 fingerprint of the client's certificate, as a hex string. Colon separators and letter case do not matter.
Client certificate subject DNThe subject DN of the client's certificate, matched by exact string equality against what the proxy reports.

For channels, configure the fingerprint or the subject DN - the fingerprint takes precedence when both are set. A definition with neither accepts any certificate that the proxy verified against the client CA.

Outgoing connections

Assign a definition to an outgoing REST or SOAP connection by selecting mTLS/<name> in the connection's security dropdown. From then on, every call through that connection presents the definition's client certificate during the handshake.

The certificate material is a set of files that you mount into the container, e.g.:

docker run \
    --mount type=bind,source=/path/to/client-cert.pem,target=/opt/hot-deploy/ssl/client-cert.pem \
    --mount type=bind,source=/path/to/client-key.pem,target=/opt/hot-deploy/ssl/client-key.pem \
    zatosource/zato-4.1

The definition then points to the paths as the container sees them - /opt/hot-deploy/ssl/client-cert.pem and /opt/hot-deploy/ssl/client-key.pem in the example above.

When the CA certificates path is set, the remote server's certificate must chain up to that CA - this covers remote endpoints with certificates from a private PKI. When it is empty, the connection's own TLS verification settings apply, e.g. the system trust store.

Channels

TLS for channels terminates at the proxy in front of the server - it is the proxy that sees the handshake and verifies the client certificate against the client CA, not the server itself. After verification, the proxy reports the result in headers injected into each request:

HeaderValue
X-Zato-SSL-Client-VerifySUCCESS when the certificate verified against the client CA
X-Zato-SSL-Client-SHA256The SHA256 fingerprint of the certificate, as a hex string
X-Zato-SSL-Client-Subject-DNThe certificate's subject DN

A channel with an mTLS definition accepts a request when the verify header reports success and the definition's match criteria agree with the reported fingerprint or subject DN. Everything else receives a 401 response.

To enable client certificates in a container, mount the CA that signs your clients' certificates as client-ca.pem:

docker run \
    --mount type=bind,source=/path/to/client-ca.pem,target=/opt/hot-deploy/ssl/client-ca.pem \
    zatosource/zato-4.1

When the file is present, the container's TLS port 11224 requests client certificates during the handshake. By default the certificate is optional - clients without one still connect, and only channels with mTLS definitions reject them. To reject any client without a valid certificate at the handshake itself, set Zato_SSL_Client_Verify=required - details in the SSL/TLS chapter.

The main server certificate is unchanged - mTLS only adds the client CA file next to the existing zato.pem.

An invocation with a client certificate:

$ curl --cert client-cert.pem --key client-key.pem https://localhost:11224/api/orders

To find a certificate's SHA256 fingerprint for the definition:

$ openssl x509 -in client-cert.pem -noout -fingerprint -sha256
sha256 Fingerprint=9F:86:D0:81:88:4C:7D:65:9A:2F:EA:A0:C5:5A:D0:15:...

The colons can stay or go - both sides of the comparison are normalized before matching.

External load balancers

If your own load balancer terminates TLS in front of Zato, the channel side works identically - configure the load balancer to verify client certificates and to inject the same three headers, and the definitions match against them without any other changes. Make sure the load balancer strips any X-Zato-SSL-* headers arriving from clients before injecting its own, otherwise a client could claim a verified certificate by sending the headers itself - the container's built-in proxy already does this.

Enmasse

mTLS definitions are exported and imported with enmasse under the security key, with type: mtls. All the fields round-trip.

security:

  # An outgoing-oriented definition with paths to the certificate material
  - name: partner.api.client.cert
    type: mtls
    cert_path: /opt/hot-deploy/ssl/client-cert.pem
    key_path: /opt/hot-deploy/ssl/client-key.pem
    ca_certs_path: /opt/hot-deploy/ssl/partner-ca.pem

  # A channel-oriented definition with the match criteria
  - name: partner.inbound.cert
    type: mtls
    client_cert_fingerprint: 9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08
    client_cert_subject_dn: CN=partner.client,O=Partner,C=US

channel_rest:
  - name: api.orders
    service: orders.get-list
    url_path: /api/orders
    security: partner.inbound.cert

outgoing_rest:
  - name: partner.api
    host: https://api.partner.example.com
    url_path: /orders
    security: partner.api.client.cert
FieldNotes
nameThe definition's name
typeAlways mtls
cert_pathPath to the client certificate, PEM
key_pathPath to the private key, PEM - optional when the certificate file contains the key
ca_certs_pathOptional CA bundle the remote server's certificate must chain up to
client_cert_fingerprintExpected SHA256 fingerprint of an inbound client certificate
client_cert_subject_dnExpected subject DN of an inbound client certificate

Troubleshooting

Channel-side rejections are logged in the server log with the path and the correlation ID (cid), with the cause in parentheses:

Log messageCause
401 Unauthorized path_info ... (No client certificate)The verify header is absent or does not report success - the client presented no certificate, or the certificate did not verify against the client CA, or the request arrived through the plain-text port
401 Unauthorized path_info ... (Fingerprint mismatch)The certificate verified but its fingerprint is not the configured one
401 Unauthorized path_info ... (Subject DN mismatch)The certificate verified but its subject DN is not the configured one

Outgoing-side failures surface as TLS errors from the remote server, logged with the connection's name - typically SSLError with handshake failure or certificate required when the remote endpoint rejects the presented certificate, and certificate verify failed when the remote server's own certificate does not chain up to the configured CA bundle.

Learn more