SSL/TLS configuration
Secure your APIs and the Dashboard with your own certificate or a generated one.
Each Zato component that accepts incoming connections listens on two ports, one for plain-text connections and one for TLS connections. By default, the TLS port is the one directly after the plain-text port:
| Component | Plain-text port | TLS port |
|---|---|---|
| API load balancer | 11223 | 11224 |
| Dashboard | 8183 | 8184 |
| OpenAPI console | 8185 | 8186 |
| HL7 MLLP | 11553 | 11554 |
All the TLS ports present the same certificate, which means that you configure it only once for the whole environment. Zato looks for the certificate in the following order and uses the first one that it finds:
Your own certificate, if you mount
zato.pem.A self-signed certificate that the container generates on startup.
The plain-text ports are convenient during development, but in production you should publish only the TLS ports, so that all the connections to your environment are encrypted. For details, see Disable the plain-text ports.
Use your own SSL certificate
If your organization already has a certificate for the host that Zato runs on, for instance one issued by a commercial CA or by your internal PKI, you can use it instead of a generated one.
To do it, create a PEM file named zato.pem. The file must contain the following, in this order:
- The server certificate.
- The intermediate CA certificates, if your CA uses any.
- The private key.
If your CA does not use intermediate certificates, the file contains only the server certificate followed by the private key, as in this example:
-----BEGIN CERTIFICATE-----
MIIFeTCCA2GgAwIBAgIUd/cKqWLuUNvn1
...
19f67nsJo8Cd6ESCTPFjQ/eX91jl+y7==
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
MIIJQgIBADANBgkqhkiG9w0BAQEFAA3gk
...
JScexp8NvHy850wldVG01wtYNdg37rg==
-----END PRIVATE KEY-----
Next, mount the file at /opt/hot-deploy/ssl/zato.pem in the command that starts your container:
The file must be owned by the zato user inside the container, not by root.
Zato loads the certificate on startup and presents it on all the TLS ports, so no further configuration is required. The only exception is the Dashboard - if you access it under a custom domain name, you must also set the CSRF trusted origins, as described in the next section.
Set CSRF trusted origins for the Dashboard
The Dashboard protects its forms against cross-site request forgery (CSRF) by checking the origin of each request. When you access the Dashboard over HTTPS under a custom domain name, you need to declare that origin as trusted. To do it, set Zato_Dashboard_CSRF_Trusted_Origins to the full address of the Dashboard, including the protocol and the port.
If the variable is not set, the Dashboard rejects such requests with the error "CSRF verification failed. Request aborted."
For example, if your certificate is issued for my.dashboard and the address of the Dashboard is https://my.dashboard:8184, start the container as follows:
docker run \
-e Zato_Dashboard_CSRF_Trusted_Origins="https://my.dashboard:8184" \
--mount type=bind,source=/path/to/zato.pem,target=/opt/hot-deploy/ssl/zato.pem \
zatosource/zato-4.1
Require client certificates
In addition to presenting its own certificate, port 11224 can also verify the certificates that API clients present. This is the mechanism that mTLS security definitions rely on, and channels use these definitions to decide which clients may invoke them.
To enable the verification, mount the certificate of the CA that signs your client certificates as client-ca.pem:
Once client-ca.pem is mounted, the following applies:
- Port 11224 requests a client certificate during the TLS handshake and verifies it against the CA.
- Port 11554, the TLS port for HL7 MLLP, verifies the certificates of connecting senders against the same CA. Plain-text MLLP on port 11553 is not affected.
- The server certificate does not change. Clients are still presented with
zato.pemor the generated certificate, andclient-ca.pemis used only to verify the clients.
By default, a client certificate is optional. Clients without a certificate can still connect, and the mTLS security definition of each channel determines whether a given request is accepted. This lets you run channels that require client certificates and channels that do not, all on the same port.
If all your clients use certificates, you can reject the ones without a valid certificate already during the TLS handshake, before any request reaches a channel. To do it:
- Set
Zato_SSL_Client_Verifytorequired. - Do not publish port 11223. Plain-text connections never present a client certificate, so they would bypass the verification.
docker run \
-e Zato_SSL_Client_Verify=required \
--mount type=bind,source=/path/to/client-ca.pem,target=/opt/hot-deploy/ssl/client-ca.pem \
zatosource/zato-4.1
If the certificates of your clients are signed by more than one CA, concatenate all the CA certificates into a single client-ca.pem file. Zato then accepts a client certificate signed by any of them.
Trust custom Certificate Authorities
When Zato connects to your backend systems over TLS, it verifies their certificates against the system trust store of the container. The trust store already contains the public CAs, but if your backend systems use certificates signed by a private CA, which is common in organizations with an internal PKI, you must add that CA to the trust store before Zato can connect to them.
To do it, save the CA certificate in PEM format, for example as my-ca.crt, and mount it under /usr/local/share/ca-certificates/:
Then, set Zato_Update_CA_Certificates to True:
On startup, the container adds all the certificates from /usr/local/share/ca-certificates/ to the system trust store. To trust more than one CA, mount each certificate under a different file name in the same directory.
Disable the plain-text ports
The plain-text ports are convenient during development, when you access Zato from your own machine, but in production all the connections should be encrypted. To achieve that, publish only the TLS ports 8184 and 11224, and do not publish the plain-text ports 8183 and 11223:
docker run \
-p 8183:8183 \ # Remove this line
-p 8184:8184 \
-p 11223:11223 \ # Remove this line
-p 11224:11224 \
zatosource/zato-4.1
With this configuration, the Dashboard and your APIs accept TLS connections only. The plain-text ports are still used inside the container, but they cannot be reached from outside of it.
The same applies to the OpenAPI console and HL7 MLLP. If you use them, publish 8186 and 11554 instead of 8185 and 11553.
Generated certificates and SSL variables
If you do not mount zato.pem, Zato generates a self-signed certificate on startup. This lets you use the TLS ports right away, for instance during development, without obtaining a certificate first. Clients do not trust self-signed certificates by default, so in production, use your own certificate instead.
The generated certificate is saved to /opt/hot-deploy/ssl/auto.pem. A new certificate and private key are generated each time the container starts, so the certificate changes after each restart.
You can adjust the generated certificate, as well as the TLS configuration in general, through the following environment variables. In the "Auto-gen only" column:
- Yes - the variable applies only to generated certificates. Zato ignores it when you mount
zato.pem. - --- - the variable applies to all TLS connections.
| Variable | Default | Auto-gen only | Description |
|---|---|---|---|
| Zato_SSL_Subject | /C=US/ST=State/L=City/O=Organization/CN=localhost | Yes | Certificate subject - the DNS name or IP address of the server |
| Zato_SSL_Subject_Alt_Name | subjectAltName=DNS:localhost,IP:127.0.0.1 | Yes | Additional DNS names and IP addresses in the certificate |
| Zato_SSL_Cert_Days | 3650 | Yes | Validity period in days |
| Zato_SSL_Key_Algorithm | ecdsa | Yes | Key algorithm, ecdsa or rsa |
| Zato_SSL_Key_Size | 4096 | Yes | Key size if the algorithm is RSA |
| Zato_SSL_Protocols | (empty) | --- | Minimum protocol version, TLSv1.2 or TLSv1.3 |
| Zato_SSL_Ciphers | (empty) | --- | Allowed cipher suites |
| Zato_SSL_DH_Params | (empty) | --- | Path to the Diffie-Hellman parameters file |
| Zato_SSL_Extra_Options | (empty) | --- | Additional HAProxy SSL options, for example ALPN |
| Zato_SSL_Client_Verify | optional | --- | Set to required to reject clients without a valid certificate during the TLS handshake. Applies only if client-ca.pem is mounted. |
| Zato_Update_CA_Certificates | False | --- | Set to True to add the certificates from /usr/local/share/ca-certificates/ to the system trust store |
For instance, the following command generates a certificate with a custom subject, a DNS name and an IP address as additional names, and a validity period of one year:
docker run \
-e Zato_SSL_Subject="/C=GB/ST=London/L=London/O=MyCompany/CN=api.mycompany.com" \
-e Zato_SSL_Subject_Alt_Name="subjectAltName=DNS:api.example.com,IP:192.168.1.100" \
-e Zato_SSL_Cert_Days=365 \
zatosource/zato-4.1
See also
| Page | What it covers |
|---|---|
| Ports and network | Which ports to publish |
| Environment variables | Reference of all the Zato_SSL_* variables |
| mTLS | Client certificate enforcement per channel |