# Securing frontend client traffic using mutual TLS Type of document: How-to guide Product: NGINX Gateway Fabric --- Learn how to configure mutual TLS (mTLS) between clients and NGINX Gateway Fabric to validate both the client and Gateway. ## Overview This guide shows how to configure client-to-Gateway validation using the Gateway's Listener HTTPS (HTTP over TLS) settings together with the Gateway's Frontend TLS settings. The example demonstrates how to validate client certificates and present the Gateway's certificate to the client. This ensures communication between the client and the Gateway is protected with mutual TLS, and only authorized requests are processed and sent to the backend. With Frontend TLS, the Gateway validates incoming client certificates against one or more CA certificates. You can configure validation at two levels: - **Default**: Applies frontend validation to all HTTPS listeners on the Gateway. - **Per-port**: Overrides the default frontend validation for specific listener ports. Both **Default** and **Per-port** can be configured with one of two validation modes: - **AllowValidOnly** (default): When set, a valid client certificate must be presented. Connections without a valid certificate are rejected. - **AllowInsecureFallback**: When set, all connections with either a valid or invalid certificate are allowed, as well as no certificate. CA certificates can be stored in either a `Secret` or a `ConfigMap`, and must contain the `ca.crt` key. The following diagram shows how the TLS handshake takes place between the client and NGINX Gateway Fabric: ```mermaid sequenceDiagram participant client as Client participant gw as NGINX Gateway Fabric participant app as Backend application client->>gw: Send request and present cert for validation gw->>client: Present certificate from Secret: cafe-secret client->>client: Validate Gateway's certificate gw->>gw: Validate client certificate with CA Secret gw->>app: Request to backend app-->>gw: Response gw-->>client: Response ``` ## Before you begin Before starting, you will need: - Administrator access to a Kubernetes cluster. - [Helm](https://helm.sh/) and [kubectl](https://kubernetes.io/docs/tasks/tools/#kubectl) must be installed locally. - [NGINX Gateway Fabric deployed](/ngf/install/) in the Kubernetes cluster. ## Install cert-manager Frontend TLS requires CA certificates for client certificate validation. This example uses [cert-manager](https://cert-manager.io/) to issue these certificates. Add the Helm repository: ```shell helm repo add jetstack https://charts.jetstack.io helm repo update ``` Install cert-manager: ```shell helm install \ cert-manager jetstack/cert-manager \ --namespace cert-manager \ --create-namespace \ --set config.apiVersion="controller.config.cert-manager.io/v1alpha1" \ --set config.kind="ControllerConfiguration" \ --set config.enableGatewayAPI=true \ --set crds.enabled=true ``` ## Create CA certificates and issuers Create a CA issuer to generate our certificates. **Note:** This example uses a `selfSigned` Issuer, which should not be used in production environments. For production environments, use a real [CA issuer](https://cert-manager.io/docs/configuration/ca/). Next, we create the following resources: 1. A self-signed issuer. 2. A CA certificate named `default-validation-ca-secret` for our **default** frontend TLS validation. 3. A CA certificate named `per-port-validation-ca-secret` for our **perPort** frontend TLS validation. 4. A CA certificate named `cafe-secret`. The HTTPS listeners on the Gateway reference this certificate and present it to the client during the TLS handshake. This is required for mutual TLS. **Note:** For the Gateway's certificate, replace `cafe.example.com` with the correct hostname for your environment ```yaml kubectl apply -f - < GW_PER_PORT= ``` ## Create HTTPRoutes Copy the YAML code below into your terminal to create HTTPRoutes to route traffic to the backend applications: ```yaml kubectl apply -f - < -- Status: Parents: Conditions: Last Transition Time: 2026-05-06T06:57:53Z Message: The Route is accepted Observed Generation: 1 Reason: Accepted Status: True Type: Accepted Last Transition Time: 2026-05-06T06:57:53Z Message: All references are resolved Observed Generation: 1 Reason: ResolvedRefs Status: True Type: ResolvedRefs Controller Name: gateway.nginx.org/nginx-gateway-controller Parent Ref: Group: gateway.networking.k8s.io Kind: Gateway Name: gateway Namespace: default Section Name: https Events: ``` ## Setup configuration test To send requests to the Gateway, you must provide a valid certificate and key signed by a valid Certificate Authority (CA). Copy the following block into your terminal to create two Certificate resources. This will create two `Secret` resources with TLS certs and keys signed by the CAs created earlier in this example. **Note:** Replace `cafe.example.com` with the correct hostname for your environment ```yaml kubectl apply -f - <