The MTLS Auth plugin lets you add mutual TLS authentication based on a client-supplied or a server-supplied certificate, and on the configured trusted certificate authority (CA) list.
Mutual TLS Authentication
Enterprise onlyHow does the mTLS plugin work?
The mTLS plugin automatically maps certificates to Consumers based on the common name field. To authenticate a Consumer with mTLS, it must provide a valid certificate and complete a mutual TLS handshake with Kong Gateway.
The plugin validates the certificate provided against the configured CA list based on the requested Route or Service:
- If the certificate is not trusted, or expired, the response is
HTTP 401 TLS certificate failed verification. - If no valid certificate is provided (including HTTP requests), the response is
HTTP 401 No required TLS certificate was sent.
However, ifconfig.anonymousis set, the request is allowed using the anonymous Consumer.
Client certificate request
Client certificates are requested during the ssl_certificate_by_lua phase, where Kong Gateway doesn’t have access to Route or Workspace information.
Because of this, Kong Gateway requests a client certificate during every TLS handshake if the mtls-auth plugin is configured on any Route or Service.
In most cases, if a client doesn’t present a certificate, it won’t affect proxying—unless the specific Route or Service requires mtls-auth.
The main exception is desktop browsers, which may prompt users to select a certificate, potentially causing a confusing user experience even when the certificate isn’t needed.
To optimize TLS handshakes, Kong Gateway builds an in-memory map of SNIs from Routes that require client certificates.
This helps limit unnecessary certificate requests while ensuring mTLS is enforced when needed.
The map relies on Routes having the SNIs attribute set.
If any Route lacks an SNI, Kong Gateway must request a client certificate during every TLS handshake.
Certificate request behavior based on plugin scope:
- Plugin applied globally: mTLS is enforced on every request across all Workspaces.
- Plugin applied at the Service level: If any associated Route lacks an SNI, mTLS is enforced on every request.
-
Plugin applied at the Route level:
- If any Route lacks an SNI, mTLS is enforced on every request.
- If all Routes have SNIs, mTLS is enforced only for matching SNI requests.
SNIs must be set for all Routes that mutual TLS authentication uses.
When using the plugin with expressions routes, the client certificate will always be requested, even if the routes are configured with SNIs.
Sending the CA DNs during TLS handshake
By default, Kong Gateway does not send the CA Distinguished Name (CA DN) list during the TLS handshake. Specifically, the certificate_authorities field in the CertificateRequest message is empty.
Some clients use the CA DN list to help select the correct certificate. To support this, set config.send_ca_dn to true.
This adds the CA certificates defined in config.ca_certificate to the appropriate SNI entries.
As noted in Client certificate request, Kong Gateway does not have access to Route information during the ssl_certificate_by_lua phase.
Instead, it builds an in-memory map of SNIs.
The CA DN list is linked to these SNIs, and if multiple mtls-auth plugins with different config.ca_certificate values are applied to the same SNI, their CA DNs are merged.
CA DN list association depends on plugin scope:
- Global scope: CA DNs are linked to a special SNI
*. - Service level:
- CA DNs are associated with each SNI of the Service’s Routes.
- If a Route has no SNI, CA DNs are linked to
*.
- Route level:
- CA DNs are associated with each SNI on the Route.
- If no SNI is configured, CA DNs are linked to
*.
During the mTLS handshake:
- If the client includes a known SNI in the
ClientHello, the corresponding CA DN list is sent in theCertificateRequest. - If the client does not send an SNI or sends an unknown one, Kong Gateway only sends the CA DN list associated with
*—and only if a client certificate is being requested.
Manual mappings between Certificate and Consumer objects
Sometimes, you might not want to use automatic Consumer lookup, or you have certificates that contain a field value not directly associated with Consumer objects. In those situations, you can manually assign one or more subject names to the Consumer entity for identifying the correct Consumer.
Note: Subject names refer to the certificate’s Subject Alternative Names (SAN) or Common Name (CN). CN is only used if the SAN extension does not exist.
You can create a Consumer mapping with either of the following:
- The
/consumers/{consumer}/mtls-authAdmin API endpoint -
decK by specifying
mtls_auth_credentialsin the configuration like the following:consumers: - custom_id: my-consumer username: example-consumer mtls_auth_credentials: - id: bda09448-3b10-4da7-a83b-2a8ba6021f0c subject_name: test@example.comCopied!
The following table describes how Consumer mapping parameters work for the Mutual TLS Authentication plugin:
|
Form Parameter |
Default |
Description |
|---|---|---|
idrequired for declarative config |
none | UUID of the Consumer mapping. Required if adding mapping using declarative configuration, otherwise generated automatically by Kong Gateway’s Admin API. |
subject_namerequired |
none |
The Subject Alternative Name (SAN) or Common Name (CN) that should be mapped to consumer (in order of lookup).
|
ca_certificateoptional |
none |
|
Matching behaviors
After a client certificate has been verified as valid, the Consumer object is determined in the following order, unless config.skip_consumer_lookup is set to true:
- Manual mappings with
subject_namematching the certificate’s SAN or CN (in that order) andca_certificate = {issuing authority of the client certificate}. - Manual mappings with
subject_namematching the certificate’s SAN or CN (in that order) andca_certificate = NULL. - If
config.consumer_byis not null, Consumer withusernameand/oridmatching the certificate’s SAN or CN (in that order). - The
config.anonymousConsumer (if set).
Note: Matching stops as soon as the first successful match is found.
Upstream headers
When a client has been authenticated, the plugin appends some headers to the request before proxying it to the upstream service, so that you can identify the Consumer in your code:
-
X-Consumer-ID: The ID of the Consumer in Kong Gateway. -
X-Consumer-Custom-ID: Thecustom_idof the Consumer (if set). -
X-Consumer-Username: Theusernameof the Consumer (if set). -
X-Credential-Identifier: The identifier of the credential (only if the Consumer is not theanonymousConsumer). -
X-Anonymous-Consumer: Is set totrueif authentication fails, and theanonymousConsumer is set instead.
You can use this information on your side to implement additional logic.
You can use the X-Consumer-ID value to query the Admin API and retrieve
more information about the Consumer.
When config.skip_consumer_lookup is set to true, Consumer lookup is skipped and instead of appending aforementioned headers, the plugin appends the following two headers:
-
X-Client-Cert-Dn: The distinguished name of the client certificate -
X-Client-Cert-San: The SAN of the client certificate
Once config.skip_consumer_lookup is applied, any client with a valid certificate can access the Service/API.
To restrict usage to only some of the authenticated users, also add the ACL plugin and create
allowed or denied groups of users using the same
certificate property being set in config.authenticated_group_by.
Troubleshooting authentication failure
When authentication fails, the client doesn’t have access to any details that explain the failure. The security reason for this omission is to prevent malicious reconnaissance.
Instead, the details are recorded inside Kong Gateway’s error logs under the [mtls-auth] filter.