# mTLS

Mutual TLS (mTLS), also called mutual authentication, adds a client check to the TLS handshake: the client presents a certificate too, and the server validates it. On a [workload](/en/documentation/platform/workloads/), Azion validates the client certificate against a Trusted CA certificate, one of the types listed in [Certificates](/en/documentation/platform/workloads/certificate-manager/certificates/). mTLS is optional on a workload, and the Open Banking model requires it, so workloads that serve financial services and payments often need it. For the `mtls` row among every other workload field, refer to [Workload settings](/en/documentation/platform/workloads/settings/#mtls).

---

## Fields

The `mtls` object of a workload turns the client certificate check on and names what the workload checks against. Set it with `PATCH /v4/workspace/workloads/{workload_id}`, or in the JSON file of `azion update workload --file`, which reads the workload ID from an `"id"` key in the file.

| API field                  | Type                                           | Values                                                   | Default | CLI flag      |
| -------------------------- | ---------------------------------------------- | -------------------------------------------------------- | ------- | ------------- |
| `mtls.enabled`             | boolean                                        | `true` turns the check on, `false` turns it off          | `false` | `--file` only |
| `mtls.config.certificate`  | integer, or `null`                             | the ID of a certificate of type `trusted_ca_certificate` | `null`  | `--file` only |
| `mtls.config.crl`          | array of integer, at most 100 items, or `null` | the IDs of certificate revocation lists (CRLs)           | `null`  | `--file` only |
| `mtls.config.verification` | enum, or `null`                                | `enforce`, `permissive`                                  | `null`  | `--file` only |

The Trusted CA certificate is the certificate of the authority that signs your clients' certificates. You upload it with no private key, and the API refuses the ID of a server certificate in `mtls.config.certificate`. A Trusted CA certificate reads `inactive` in Certificate Manager until a workload names it, and `active` from then on.

A CRL lists certificates that their issuer revoked before they expired. A CRL is attached to a workload only through `mtls.config.crl`, on a workload with `mtls.enabled` set to `true`, and one workload can name several CRLs in the same array.

For example, a workload that admits only clients your certificate authority signed, and attaches one CRL, sends this file, saved as `mtls.json`:

```json
{
  "id": <workload-id>,
  "mtls": {
    "enabled": true,
    "config": { "certificate": <trusted-ca-id>, "crl": [<crl-id>], "verification": "enforce" }
  }
}
```

Apply it with the CLI:

```bash
azion update workload --file mtls.json
```

The command prints the ID of the workload it changed:

```text
Updated Workload with ID <workload-id>
```

The workload then reads back with this `mtls` object:

```json
{
 "mtls": { "config": { "certificate": <trusted-ca-id>, "crl": [<crl-id>], "verification": "enforce" }, "enabled": true }
}
```

On API v3, mTLS belonged to the domain object, in `is_mtls_enabled`, `mtls_verification`, and `mtls_trusted_ca_certificate_id`. On API v4 the same settings are `mtls.enabled`, `mtls.config.verification`, and `mtls.config.certificate` on the workload. For the full mapping between the two models, refer to [API v4 Migration](/en/documentation/fundamentals/api-v4-migration/).

---

## Verification modes

The `mtls.config.verification` field decides what a workload does with a client that presents no certificate, or a certificate the Trusted CA did not sign. In `enforce` mode, the workload requests the client certificate during the TLS handshake and ends the handshake when the check fails. The table shows what each client receives from a workload in each mode:

| Client presents                        | `enforce`                                                           | `permissive`                                                      |
| -------------------------------------- | ------------------------------------------------------------------- | ----------------------------------------------------------------- |
| No certificate                         | The handshake fails, and the request never reaches the application. | The handshake completes, and the request reaches the application. |
| A certificate the Trusted CA signed    | The handshake completes, and the request reaches the application.   | The handshake completes, and the request reaches the application. |
| A certificate another authority signed | The handshake fails, and the request never reaches the application. | The handshake completes, and the request reaches the application. |

`enforce` blocks every client whose identity the workload cannot verify, on your own domains and on the workload domain alike. Use it when every legitimate client holds a certificate your certificate authority signed.

`permissive` lets every client complete the handshake and leaves the decision to your rules. Use it to test mTLS, or to admit clients under specific conditions. To refuse the rest, add a firewall rule on the Client Certificate Validation variable, as the section Client certificate data in rules describes.

A change to `mtls` takes several minutes to reach all of Azion's distributed infrastructure, and propagation is best-effort. Until it completes, some requests meet the old mode and others the new one. Before you rely on a change, send a request with no client certificate and confirm that the result matches the new mode.

---

## Client certificate data in rules

Rules Engine reads details of the client certificate, so a rule can act on the identity of the client.

In Rules Engine for Firewall, the Client Certificate Validation variable evaluates whether the certificate in the request is valid against the workload's Trusted CA. On a workload in `permissive` mode, a rule that denies requests where Client Certificate Validation is not equal to `true` returns `403 Forbidden` to every client without a valid certificate. The Client Certificate Validation criterion appears only on an account where mTLS is activated.

A firewall rule can also match attributes of the client certificate, such as the Common Name (CN), the issuer, or the fingerprint, which the mTLS header variables carry. Those variables must be set in your application before a firewall rule can use them as criteria.

An application sets the mTLS header variables as request headers, for example to meet Open Banking requirements. The list of variables Rules Engine accepts is on [Rules Engine for Applications](/en/documentation/platform/applications/rules-engine/). For the rule configuration step by step, refer to [Configure mTLS on a workload](/en/documentation/guides/application-security/tls-and-certificates/associate-an-mtls-certificate/).

---

## Requirements

A workload checks client certificates only when these conditions hold:

- **mTLS is activated on your account.** Azion activates mTLS per account. To activate it, contact the Sales team.
- **The workload serves HTTPS.** The client certificate travels in the TLS handshake, so mTLS works only on HTTPS connections. mTLS settings on a workload that serves HTTP only check nothing.
- **A Trusted CA certificate exists in Certificate Manager.** A third-party certificate authority issues it, and you upload it before you set `mtls.config.certificate`. A certificate that Azion generates, such as the Azion SAN certificate, cannot serve as the Trusted CA.
- **Clients send SNI in `enforce` mode.** Server Name Indication (SNI) is the TLS extension that names the host in the handshake. A connection without SNI reaches the default configuration, which presents the Azion SAN certificate. On a workload in `enforce` mode, Azion closes such a connection before it resolves a route of your application.

For the number of certificates an account can hold and the maximum size of a Trusted CA certificate, refer to [Workloads limits](/en/documentation/platform/workloads/limits/).

---

## Errors

The API refuses the first two requests below with the message in the first column. The CLI prints the message inside `Error: Failed to update the Workload: [...]`, followed by `Check your settings and try again. If the error persists, contact Azion support.` The last row is what a client sees, not an API message.

| Message                                                                                                                 | Cause                                                                                                                    | What to do                                                                                                                                                                          |
| ----------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Invalid certificate type, MUST be a Trusted CA.`                                                                       | `mtls.config.certificate` holds the ID of a server certificate, of type `edge_certificate`.                              | Send the ID of a certificate of type `trusted_ca_certificate`.                                                                                                                      |
| `Invalid certificate type, MUST be an Edge Certificate.`                                                                | `tls.certificate` holds the ID of a Trusted CA certificate, which belongs in `mtls.config.certificate`.                  | Move the ID to `mtls.config.certificate`, and send the ID of an `edge_certificate`, or `null`, in `tls.certificate`.                                                                |
| curl exits with code `56` after the server's certificate request; LibreSSL reports `reason(1116)`, certificate required | The workload is in `enforce` mode, and the client presented no certificate or a certificate the Trusted CA did not sign. | Present a client certificate the Trusted CA signed, with the `--cert` and `--key` options of curl, or set `mtls.config.verification` to `permissive` and decide in a firewall rule. |

The handshake failure shows in verbose curl output. Send a request with no client certificate to a workload in `enforce` mode:

```bash
curl -skv https://<your-domain>/ -o /dev/null
```

The workload requests a certificate, the client sends none, and the connection ends:

```text
* (304) (IN), TLS handshake, Request CERT (13):
* (304) (IN), TLS handshake, Certificate (11):
* (304) (IN), TLS handshake, CERT verify (15):
* (304) (IN), TLS handshake, Finished (20):
* (304) (OUT), TLS handshake, Certificate (11):
* (304) (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / AEAD-AES256-GCM-SHA384 / [blank] / UNDEF
* LibreSSL SSL_read: LibreSSL/3.3.6: error:1404C45C:SSL routines:ST_OK:reason(1116), errno 0
```

---

## Related resources

- [Certificates](/en/documentation/platform/workloads/certificate-manager/certificates.md): The Trusted CA certificates and CRLs a workload names in mTLS, and how to upload each one.
- [Configure mTLS on a workload](/en/documentation/guides/application-security/tls-and-certificates/associate-an-mtls-certificate.md): The steps that upload a Trusted CA, turn on mTLS on a workload, and add a permissive rule.
- [Workload settings](/en/documentation/platform/workloads/settings.md): Every other field of a workload, from domains and ports to the server certificate in TLS.
- [Workloads limits](/en/documentation/platform/workloads/limits.md): The bounds on certificates per account and on the size of a Trusted CA certificate.
