Related Documentation
Made by
Kong Inc.
Supported Gateway Topologies
hybrid db-less traditional
Supported Konnect Deployments
hybrid cloud-gateways
Compatible Protocols
grpc grpcs http https

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.

How 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, if config.anonymous is 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 the CertificateRequest.
  • 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-auth Admin API endpoint
  • decK by specifying mtls_auth_credentials in 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.com
    

The following table describes how Consumer mapping parameters work for the Mutual TLS Authentication plugin:

Form Parameter

Default

Description

id
required 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_name
required
none The Subject Alternative Name (SAN) or Common Name (CN) that should be mapped to consumer (in order of lookup).
ca_certificate
optional
none
  • If using the Admin API: UUID of the Certificate Authority (CA).
  • If using declarative configuration: Full PEM-encoded CA certificate.

    The provided CA UUID or full CA Certificate has to be verifiable by the issuing certificate authority for the mapping to succeed. This is to help distinguish multiple certificates with the same subject name that are issued under different CAs.

    If empty, the subject name matches certificates issued by any CA under the corresponding config.ca_certificates.”

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:

  1. Manual mappings with subject_name matching the certificate’s SAN or CN (in that order) and ca_certificate = {issuing authority of the client certificate}.
  2. Manual mappings with subject_name matching the certificate’s SAN or CN (in that order) and ca_certificate = NULL.
  3. If config.consumer_by is not null, Consumer with username and/or id matching the certificate’s SAN or CN (in that order).
  4. The config.anonymous Consumer (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: The custom_id of the Consumer (if set).
  • X-Consumer-Username: The username of the Consumer (if set).
  • X-Credential-Identifier: The identifier of the credential (only if the Consumer is not the anonymous Consumer).
  • X-Anonymous-Consumer: Is set to true if authentication fails, and the anonymous Consumer 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.

Something wrong?

Help us make these docs great!

Kong Developer docs are open source. If you find these useful and want to make them better, contribute today!