This page explains how you can secure a Gateway using various security features:
SSL Policies to help ensure the Gateway is using the required secure protocols and algorithms
Certificates to secure Client-to-Gateway and Gateway-to-Backends traffic with TLS
Google Cloud Armor security policy to protect Services from DDoS attacks
Identity-Aware Proxy (IAP) to provide a layer of authentication and authorization before allowing access to a Service
To learn more about Gateway security, see Gateway security.
Before you begin
Before you start, make sure that you have performed the following tasks:
- Enable the Google Kubernetes Engine API. Enable Google Kubernetes Engine API
- If you want to use the Google Cloud CLI for this task,
install and then
initialize the
gcloud CLI. If you previously installed the gcloud CLI, get the latest
version by running the
gcloud components updatecommand. Earlier gcloud CLI versions might not support running the commands in this document.
GKE Gateway controller requirements
- Gateway API is supported on VPC-native clusters only.
- If you are using the regional or cross-region GatewayClasses, you must enable a proxy-only subnet.
- Your cluster must have the
HttpLoadBalancingadd-on enabled. - If you are using Istio, you must upgrade Istio to one of the following
versions:
- 1.15.2 or later
- 1.14.5 or later
- 1.13.9 or later.
If you are using Shared VPC, then in the host project, you need to assign the
Compute Network Userrole to the GKE Service account for the service project.Ensure that you have an existing Autopilot or Standard cluster. If you need one, create an Autopilot cluster.
Restrictions and limitations
In addition to the GKE Gateway controller restrictions and limitations, the following limitations apply specifically to Gateway security:
TLS configurations using either an SSL Certificate or Certificate Manager on Gateways are not supported with GKE version 1.28.4-gke.1083000. Use a Kubernetes secret as a workaround for this GKE version.
You cannot use the
networking.gke.io/certmapannotation with atls.certificateRefson the same Gateway resource. If you reference aCertificateMapin a Gateway, GKE will treat this as an error.Certificate Manager supports both self-managed and Google-managed certificates. Google-managed certificates are compatible with regional Gateways and global Gateways.
When using Google-managed SSL certificates, you must create the SSL certificates outside of GKE before you attach them to your Gateway.
You cannot use the same service as a backend to a regional and a global Gateway if you are referencing a Google Cloud Armor backend security policy in your GCPBackendPolicy. You must create two separate services and policies for this use case.
The Gateway controller does not support the ManagedCertificate resource.
The Gateway controller does not support the
networking.gke.io/managed-certificatesannotation.If you configure Cloud CDN with GKE Gateway, you can't enable both IAP and Cloud CDN with the same Gateway, including individual routes with Cloud CDN. If you need to enable Cloud CDN for a route that uses a GCPHTTPFilter resource, you must first remove any existing GCPBackendPolicy that configures IAP for that Gateway.
TrustConfig quota. For information about the total size of all TrustConfig resources in each location, see Resource quotas and limits.
Location alignment. The referenced TrustConfig resource must exist in the same location (global or specific region) as the Gateway that uses the Service.
Namespace constraint. The BackendTLSPolicy resource and its target resource must be in the same namespace.
For a list of supported Gateway API fields and capabilities of the GatewayClass resources available on GKE, see GatewayClass capabilities.
Secure a Gateway using a Kubernetes Secret
In this example, you configure a Gateway using a Kubernetes Secret.
Store a certificate in a Kubernetes Secret
You can use a certificate issued and validated by your certificate authority (CA) or create a self-signed certificate. The following steps use a self-signed certificate.
Create a private key:
openssl genrsa -out PRIVATE_KEY_FILE 2048Replace
PRIVATE_KEY_FILEwith the name of your private key file, such asprivate-key.pem. For more information, see Select or create a private key.Create an Open SSL configuration file:
cat <<EOF >CONFIG_FILE [req] default_bits = 2048 req_extensions = extension_requirements distinguished_name = dn_requirements prompt = no [extension_requirements] basicConstraints = CA:FALSE keyUsage = nonRepudiation, digitalSignature, keyEncipherment subjectAltName = @sans_list [dn_requirements] 0.organizationName = example commonName = store.example.com [sans_list] DNS.1 = store.example.com EOFReplace
CONFIG_FILEwith the name for the new config file, such asconfig-file.cnf.Create a certificate signing request (CSR) file:
openssl req -new -key PRIVATE_KEY_FILE \ -out CSR_FILE \ -config CONFIG_FILEReplace
CSR_FILEwith the name of the new CSR file, such ascert.pem. For more information, see Create a CSR.Sign the CSR:
openssl x509 -req \ -signkey PRIVATE_KEY_FILE \ -in CSR_FILE \ -out CERTIFICATE_FILE \ -extfile CONFIG_FILE \ -extensions extension_requirements \ -days 30Replace
CERTIFICATE_FILEwith the path and name of the file that the command generates, such ascert-file.pem. For more information, see Sign the CSR.Create a Kubernetes TLS Secret using the key and the certificate file that you created:
kubectl create secret tls store-example-com \ --cert=CERTIFICATE_FILE \ --key=PRIVATE_KEY_FILEGKE saves the certificate and key as a Kubernetes resource that you can attach to your Gateway.
Create a Gateway and HTTPRoute
Save the following manifest as
external-gateway.yaml:kind: Gateway apiVersion: gateway.networking.k8s.io/v1 metadata: name: external-http spec: gatewayClassName: gke-l7-global-external-managed listeners: - name: https protocol: HTTPS port: 443 tls: mode: Terminate certificateRefs: # Directly reference the Kubernetes Secret containing the TLS certificate and private key. - name: store-example-com # The name of the TLS secret.This manifest describes a Gateway with the following properties:
gatewayClassName: gke-l7-global-external-managed: deploys a global external Application Load Balancer.protocol: HTTPSandport: 443: required for enabling TLS.tls: references the Kubernetes Secret created in the previous step.
Apply the manifest to the cluster:
kubectl apply -f external-gateway.yamlSave the following manifest as
store-external-route.yaml:kind: HTTPRoute apiVersion: gateway.networking.k8s.io/v1 metadata: name: store-external labels: gateway: external-http spec: parentRefs: - name: external-http # Link this route to the 'external-http' Gateway. hostnames: - "store.example.com" # Match traffic for this hostname. rules: - backendRefs: # Define where to forward the traffic. - name: store-v1 port: 8080This manifest describes an HTTPRoute that matches traffic to
store.example.comand sends it to thestore-v1Service.Apply the manifest to the cluster:
kubectl apply -f store-external-route.yaml
Verify the Gateway
Verify that the Gateway works by sending a request over the internet.
Get the IP address of the Gateway:
kubectl get gateway external-http -o=jsonpath="{.status.addresses[0].value}"The output is similar to the following:
203.0.113.12This output is a public IP address, which means any client with internet access can connect to it.
Access the domain of the Gateway using
curl:curl https://store.example.com --resolve store.example.com:443:GATEWAY_IP_ADDRESS --cacert CERTIFICATE_FILE -vReplace the following:
GATEWAY_IP_ADDRESS: the IP address of the Gateway load balancer.CERTIFICATE_FILE: the certificate file that you generated. You must save this file on the machine that you are using to connect to the Gateway. The certificate is required to authenticate the Gateway because the Gateway uses a self-signed certificate.
The
--resolveoption resolves the domain name to the IP address of the Gateway, which is required because DNS is not configured for this domain.The output is similar to the following:
... * TLSv1.2 (OUT), TLS handshake, Client hello (1): * TLSv1.2 (IN), TLS handshake, Server hello (2): * TLSv1.2 (IN), TLS handshake, Certificate (11): * TLSv1.2 (IN), TLS handshake, Server key exchange (12): * TLSv1.2 (IN), TLS handshake, Server finished (14): * TLSv1.2 (OUT), TLS handshake, Client key exchange (16): * TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1): * TLSv1.2 (OUT), TLS handshake, Finished (20): * TLSv1.2 (IN), TLS change cipher, Change cipher spec (1): * TLSv1.2 (IN), TLS handshake, Finished (20): * SSL connection using TLSv1.2 / ECDHE-RSA-CHACHA20-POLY1305 * ALPN, server accepted to use h2 # This block shows the certificate details presented by the Gateway. # The value of the 'common name' field matches the requested hostname. * Server certificate: * subject: O=example; CN=store.example.com * start date: Apr 19 15:54:50 2021 GMT * expire date: Apr 19 15:54:50 2022 GMT * common name: store.example.com (matched) * issuer: O=example; CN=store.example.com * SSL certificate verify ok. ... { "cluster_name": "gw", "host_header": "store.example.com", "metadata": "store-v1", "node_name": "gke-gw-default-pool-51ccbf30-yya8.c.agmsb-k8s.internal", "pod_name": "store-v1-84b47c7f58-tj5mn", "pod_name_emoji": "😍", "project_id": "agmsb-k8s", "timestamp": "2021-04-19T16:30:08" # Several lines of output omitted here. }This output includes a successful TLS handshake followed by a response from the application. The TLS connection is terminated at the Gateway and the application responds to the client securely.
Secure a Gateway using an SSL certificate
In this example, you configure a Gateway with a Google-managed SSL certificate.
Create an SSL certificate
Create a Google-managed global
SslCertificateresource:gcloud compute ssl-certificates create store-example-com \ --domains=store.example.com \ --global
Create a Gateway and HTTPRoute
Save the following manifest as
external-gateway.yaml:kind: Gateway apiVersion: gateway.networking.k8s.io/v1 metadata: name: external-http spec: gatewayClassName: gke-l7-global-external-managed listeners: - name: https protocol: HTTPS port: 443 tls: mode: Terminate # Terminate TLS using your SSL certificate. options: networking.gke.io/pre-shared-certs: store-example-com # Specify the Google Cloud SSL certificate resource name.This manifest describes a Gateway with the following properties:
gatewayClassName: gke-l7-global-external-managed: deploys a global external Application Load Balancer.protocol:HTTPSandport:443: required for enabling TLS.tls.mode:Terminate: terminates TLS using your SSL certificate.
Apply the manifest to your cluster:
kubectl apply -f external-gateway.yamlSave the following HTTPRoute manifest as
store-external-route.yaml:kind: HTTPRoute apiVersion: gateway.networking.k8s.io/v1 metadata: name: store-external labels: gateway: external-http spec: parentRefs: - name: external-http hostnames: - "store.example.com" rules: - backendRefs: - name: store-v1 port: 8080Deploy the HTTPRoute in your cluster:
kubectl apply -f store-external-route.yamlIt might take several minutes for GKE to deploy the Gateway.
Verify the Gateway
Get the IP address of the Gateway:
kubectl get gateway external-http -o=jsonpath="{.status.addresses[0].value}"The output is similar to the following:
203.0.113.12This output is a public IP address, which means any client with internet access can connect to it.
Update an A or AAAA record to direct your domain to the IP address of the Gateway.
This step is only necessary if you are configuring a Google-managed SSL certificate. If you are configuring a self-managed certificate, you can skip this step.
After the DNS records are updated, it can take up to 10 minutes for your load balancer to begin using the Google-managed certificate.
Verify that the Gateway is working by sending a request over the internet using
curl:curl https://store.example.com -vThe output is similar to the following:
... * TLSv1.2 (OUT), TLS handshake, Client hello (1): * TLSv1.2 (IN), TLS handshake, Server hello (2): * TLSv1.2 (IN), TLS handshake, Certificate (11): * TLSv1.2 (IN), TLS handshake, Server key exchange (12): * TLSv1.2 (IN), TLS handshake, Server finished (14): * TLSv1.2 (OUT), TLS handshake, Client key exchange (16): * TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1): * TLSv1.2 (OUT), TLS handshake, Finished (20): * TLSv1.2 (IN), TLS change cipher, Change cipher spec (1): * TLSv1.2 (IN), TLS handshake, Finished (20): * SSL connection using TLSv1.2 / ECDHE-RSA-CHACHA20-POLY1305 * ALPN, server accepted to use h2 * Server certificate: * subject: O=example; CN=store.example.com * start date: Apr 19 15:54:50 2021 GMT * expire date: Apr 19 15:54:50 2022 GMT * common name: store.example.com (matched) * issuer: O=example; CN=store.example.com * SSL certificate verify ok. ... { "cluster_name": "gw", "host_header": "store.example.com", "metadata": "store-v1", "node_name": "gke-gw-default-pool-51ccbf30-yya8.c.agmsb-k8s.internal", "pod_name": "store-v1-84b47c7f58-tj5mn", "pod_name_emoji": "😍", "project_id": "agmsb-k8s", "timestamp": "2021-04-19T16:30:08", "zone": "us-west1-a" }This output includes a successful TLS handshake and a response from the application. TLS is terminated at the Gateway correctly and the application responds to the client securely.
Secure a Gateway using Certificate Manager
In this example, you configure a Gateway using Certificate Manager.
Create a Certificate
Global Gateway
To create a global Gateway, you reference a certificate map resource that contains one or more certificates. You must create at least one certificate and add it as an entry to your certificate map.
To create a certificate, first create a private key and certificate file.
Create a
Certificateresource by loading your self-managed certificate and key:gcloud certificate-manager certificates create store-example-com-cert \ --certificate-file="cert.pem" \ --private-key-file="PRIVATE_KEY_FILE"Create a
CertificateMap:gcloud certificate-manager maps create store-example-com-mapCreate a
CertificateMapEntrywhich assigns the certificate to theCertificateMap:gcloud certificate-manager maps entries create store-example-com-map-entry \ --map=store-example-com-map \ --hostname=store.example.com \ --certificates=store-example-com-cert
Regional Gateway
For a regional Gateway, you create a Certificate which will be specified
directly when creating the Gateway. Unlike a global Gateway, you don't need to
create a CertificateMap to which certificates are assigned.
Create a private key and certificate file.
Create a
Certificateresource by uploading your certificate file and key:
gcloud certificate-manager certificates create "CERTIFICATE_NAME" \
--certificate-file="CERTIFICATE_FILE" \
--private-key-file="PRIVATE_KEY_FILE" \
--location="REGION"
Replace the following:
CERTIFICATE_NAME: the name of your certificate, for examplestore-example-com-cert.CERTIFICATE_FILE: the name of the certificate file, for example,cert.pem.PRIVATE_KEY_FILE: the name of your private key file, such asprivate-key.pem. For more information, see Select or create a private key.REGION: the name of the region in which you are configuring the Gateway, for exampleus-central1.
Create a Gateway and HTTPRoute
Global Gateway
To create a global Gateway, complete the following steps:
Save the following manifest as
cert-map-gateway.yaml:kind: Gateway apiVersion: gateway.networking.k8s.io/v1 metadata: name: external-http annotations: networking.gke.io/certmap: store-example-com-map spec: gatewayClassName: gke-l7-global-external-managed listeners: - name: https protocol: HTTPS port: 443 # No TLS section is included here because TLS is handled by the certmap annotation.This manifest describes a Gateway with the following properties:
gatewayClassName: gke-l7-global-external-managed: deploys a global external Application Load Balancer.protocol: HTTPSandport: 443: required for enabling TLS.
There is no TLS section because TLS is configured with Certificate Manager using the annotation
networking.gke.io/certmap.Apply the manifest to the cluster:
kubectl apply -f cert-map-gateway.yamlIt might take several minutes for GKE to deploy the Gateway.
To create an HTTPRoute, save the following manifest as
cert-map-http-route.yaml:apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: foo namespace: default spec: parentRefs: - name: external-http hostnames: - foo.example.com rules: - matches: - path: value: / backendRefs: - name: foo-v1 port: 8080Apply the manifest to the cluster:
kubectl apply -f cert-map-http-route.yaml
Regional Gateway
When creating a regional Gateway, you can specify certificates managed by Certificate Manager and certificates managed by Compute Engine.
To create a regional external Gateway, save the following manifest as
external-gateway.yaml:kind: Gateway apiVersion: gateway.networking.k8s.io/v1 metadata: name: gateway namespace: corp spec: gatewayClassName: gke-l7-regional-external-managed listeners: - name: gateway-pre-shared-certmap protocol: HTTPS port: 443 tls: mode: Terminate # TLS is terminated at the Gateway. options: # Specifies a comma-separated list of Certificate Manager certificates to use for TLS termination. networking.gke.io/cert-manager-certs: store-example-com-cert1, store-example-com-cert2 # These certificates are directly managed by Certificate Manager. allowedRoutes: kinds: - kind: HTTPRoute namespaces: from: AllThis manifest describes a Gateway with the following properties:
gatewayClassName:gke-l7-regional-external-managed: deploys a regional external Application Load Balancer.protocol: HTTPSandport: 443: required for enabling TLS.options:networking.gke.io/cert-manager-certs: certificates managed by Certificate Manager.
To create a regional internal Gateway, in the preceding example, change the value of
gatewayClassNametogke-l7-rilb. This deploys an internal Application Load Balancer.Apply the manifest to the cluster:
kubectl apply -f external-gateway.yamlTo create an HTTPRoute, save the following manifest as
store-external-route.yaml:apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: store-external labels: gateway: external-http spec: parentRefs: - name: external-http hostnames: - "store.example.com" rules: backendRefs: - name: store-v1 port: 8080This manifest describes an HTTPRoute that matches traffic for
store.example.comand forwards the traffic to thestore-v1Service.Apply the manifest to the cluster:
kubectl apply -f store-external-route.yaml
Verify the Gateway
Get the IP address of the Gateway:
kubectl get gateway external-http -o=jsonpath="{.status.addresses[0].value}"The output is similar to the following:
203.0.113.12This output is a public IP address, which means any client with internet access can connect to it.
Update an A or AAAA record to direct your domain to the IP address of the Gateway.
This step is only necessary if you are configuring a Google-managed SSL Certificate. If you are configuring a self-managed certificate, you can skip this step.
After the DNS records are updated, it can take up to 10 minutes for your load balancer to begin using the Google-managed certificate.
Access the domain of the Gateway using
curl:curl https://store.example.com --resolve store.example.com:443:GATEWAY_IP_ADDRESS --cacert CERTIFICATE_FILE -vReplace the following:
GATEWAY_IP_ADDRESS: the IP address of the Gateway load balancer.CERTIFICATE_FILE: the certificate file that you generated. You must save this file on the machine that you are using to connect to the Gateway. The certificate is required to authenticate the Gateway because the Gateway uses a self-signed certificate.
The output is similar to the following:
... * TLSv1.2 (OUT), TLS handshake, Client hello (1): * TLSv1.2 (IN), TLS handshake, Server hello (2): * TLSv1.2 (IN), TLS handshake, Certificate (11): * TLSv1.2 (IN), TLS handshake, Server key exchange (12): * TLSv1.2 (IN), TLS handshake, Server finished (14): * TLSv1.2 (OUT), TLS handshake, Client key exchange (16): * TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1): * TLSv1.2 (OUT), TLS handshake, Finished (20): * TLSv1.2 (IN), TLS change cipher, Change cipher spec (1): * TLSv1.2 (IN), TLS handshake, Finished (20): * SSL connection using TLSv1.2 / ECDHE-RSA-CHACHA20-POLY1305 * ALPN, server accepted to use h2 * Server certificate: * subject: O=example; CN=store.example.com * start date: Apr 19 15:54:50 2021 GMT * expire date: Apr 19 15:54:50 2022 GMT * common name: store.example.com (matched) * issuer: O=example; CN=store.example.com * SSL certificate verify ok. ... { "cluster_name": "gw", "host_header": "store.example.com", "metadata": "store-v1", "node_name": "gke-gw-default-pool-51ccbf30-yya8.c.agmsb-k8s.internal", "pod_name": "store-v1-84b47c7f58-tj5mn", "pod_name_emoji": "😍", "project_id": "agmsb-k8s", "timestamp": "2021-04-19T16:30:08", "zone": "us-west1-a" }This output includes a successful TLS handshake and a response from the application. TLS is terminated at the Gateway correctly and the application responds to the client securely.
Configure frontend mTLS for a Gateway
You can configure client certificate validation, also known as frontend mTLS,
for your GKE Gateway. Frontend mTLS is supported for the
gke-l7-global-external-managed, gke-l7-regional-external-managed, and
gke-l7-rilb GatewayClasses and lets the Gateway authenticate the
certificates presented by clients. Frontend mTLS configuration is valid for
HTTPS listeners that use Terminate mode.
You can configure frontend mTLS in one of the following ways:
- Use Gateway API configuration (recommended).
- Use a self-managed
TrustConfigannotation on the Gateway (advanced).
Configure frontend mTLS using Gateway API configuration (recommended)
Using Gateway API is the recommended way to configure client certificate validation. This method involves storing trust sources in a Kubernetes ConfigMap and referencing this ConfigMap in the Gateway specification.
Create trust sources.
Trust sources establish and validate the root of trust for client certificates that are presented to the load balancer. GKE Gateway supports trust sources based on root certificates.
To create certificates, see Create the root and intermediate certificates.
Create a ConfigMap.
Store your trust sources in a Kubernetes ConfigMap. Each key in the ConfigMap must contain exactly one PEM-encoded CA certificate in a valid x509 format. You must create this ConfigMap in the same namespace as your Gateway resource unless you use a ReferenceGrant. To reference a ConfigMap in a different namespace, see ReferenceGrant.
Place the certificate data under the
ca.crtkey:apiVersion: v1 kind: ConfigMap metadata: name: my-cert data: ca.crt: | -----BEGIN CERTIFICATE----- <PEM_DATA> -----END CERTIFICATE-----To create a ConfigMap with your certificates, run the following command:
kubectl create configmap my-config \ --from-file=ca.crt=ROOT_CERT_PATHReplace
ROOT_CERT_PATHwith the path to your certificate file. A ConfigMap can contain only one certificate.Configure the Gateway.
Attach the ConfigMap to your Gateway by adding a
tlssection that contains thefrontendValidationfield to your Gateway specification. Thedefaultconfiguration is required and applies to all HTTPS listeners that useTerminatemode unless you specify a per-port configuration. The following example shows an end-to-end Gateway configuration that includes both a server certificate (by using thecertmapannotation) and client certificate validation (by using thetls.frontendValidationfield):apiVersion: gateway.networking.k8s.io/v1 kind: Gateway metadata: name: mtls-example annotations: networking.gke.io/certmap: store-example-com-map spec: gatewayClassName: gke-l7-global-external-managed tls: frontendValidation: default: caCertificateRefs: - kind: ConfigMap group: "" name: my-config listeners: - name: foo-https protocol: HTTPS port: 443 hostname: foo.example.com tls: mode: Terminate # No certificateRefs needed when using the certmap annotationOverride configuration per port.
You can also specify unique trust sources for individual ports. A per-port configuration overrides the default configuration for all listeners configured for that port.
apiVersion: gateway.networking.k8s.io/v1 kind: Gateway metadata: name: mtls-port-override annotations: networking.gke.io/certmap: store-example-com-map spec: gatewayClassName: gke-l7-global-external-managed tls: frontendValidation: default: caCertificateRefs: - kind: ConfigMap group: "" name: global-ca-config perPort: - port: 8443 tls: validation: caCertificateRefs: - kind: ConfigMap group: "" name: port-specific-ca-config listeners: - name: https-default protocol: HTTPS port: 443 tls: mode: Terminate - name: https-override protocol: HTTPS port: 8443 tls: mode: TerminateOptional: configure the client validation mode.
By default, GKE Gateways enforce strict client certificate validation (
AllowValidOnly). To allow invalid or missing client certificates, in thefrontendValidation.defaultconfiguration, set the value of themodekey toAllowInsecureFallback:apiVersion: gateway.networking.k8s.io/v1 kind: Gateway metadata: name: mtls-example annotations: networking.gke.io/certmap: store-example-com-map # Add this annotation spec: gatewayClassName: gke-l7-global-external-managed tls: frontendValidation: default: caCertificateRefs: - kind: ConfigMap group: "" name: my-config mode: AllowInsecureFallback listeners: - name: foo-https protocol: HTTPS port: 443 hostname: foo.example.com tls: mode: Terminate # No certificateRefs needed when using the certmap annotation
Use a self-managed TrustConfig (advanced)
Alternatively, configure client certificate validation by annotating your Gateway with a TrustConfig resource. Use this self-managed method if you need additional flexibility or if your configuration exceeds standard Gateway API limitations. This method is mutually exclusive with the Gateway API configuration method and applies to all HTTPS listeners on the Gateway (per-port overrides are not supported).
Create a TrustConfig resource. For instructions, see Create a trust config resource.
When you create the TrustConfig resource, specify
globalfor global Gateways (gke-l7-global-external-managed) or the appropriate region (for example,us-central1) for regional Gateways (gke-l7-regional-external-managedandgke-l7-rilb).Attach the TrustConfig to your Gateway by using the
networking.gke.io/frontend-trust-configannotation.The following example shows an end-to-end Gateway configuration that includes both a server certificate (using the
certmapannotation) and client certificate validation (using theTrustConfigannotation):apiVersion: gateway.networking.k8s.io/v1 kind: Gateway metadata: name: mtls-example annotations: networking.gke.io/frontend-trust-config: my-trust-config networking.gke.io/certmap: store-example-com-map # Add this annotation spec: gatewayClassName: gke-l7-global-external-managed listeners: - name: foo-https protocol: HTTPS port: 443 hostname: foo.example.com tls: mode: Terminate # Remove certificateRefs and replace with the comment # No certificateRefs needed when using the certmap annotationOptional: configure the client validation mode.
By default, GKE Gateways enforce strict client certificate validation (
REJECT_INVALID). To allow invalid or missing client certificates, set thenetworking.gke.io/allow-invalid-or-missing-client-certannotation totrue.
Configure backend TLS for a Gateway
Backend TLS enables the GKE Gateway load balancer to verify the identity of the backends it connects to. Backend TLS adds an explicit verification step during the TLS handshake between the Gateway and the backend Pod. The Gateway acts as the TLS client, validating the backend server's certificate against a set of trusted Certificate Authorities (CAs) that you configure. This verification occurs when a new connection is established, ensuring the Gateway communicates only with trusted backends and enhancing overall security.
You can configure backend authenticated TLS using a BackendTLSPolicy resource attached to a Service, InferencePool, ServiceImport, or GCPInferencePoolImport. The BackendTLSPolicy must reside in the same namespace as the target resource.
Backend TLS is supported for the following GatewayClasses:
gke-l7-global-external-managedandgke-l7-global-external-managed-mc(supports only Service and ServiceImport backends)gke-l7-regional-external-managedandgke-l7-regional-external-managed-mcgke-l7-rilbandgke-l7-rilb-mcgke-l7-cross-regional-internal-managed-mc
Use a Kubernetes ConfigMap (Standard)
In this method, you provide the CA certificate directly in a Kubernetes ConfigMap.
Create a ConfigMap resource containing your PEM-encoded CA certificates. For more information, see certificate requirements. Each ConfigMap must contain only one CA certificate. You must create this ConfigMap in the same namespace as your BackendTLSPolicy resource. BackendTLSPolicy doesn't support cross-namespace references to ConfigMap resources.
The certificate data must be placed under the
ca.crtkey:apiVersion: v1 kind: ConfigMap metadata: name: my-backend-ca data: ca.crt: | -----BEGIN CERTIFICATE----- PEM_DATA -----END CERTIFICATE-----Replace
PEM_DATAwith the Base64-encoded, PEM-formatted content of your CA certificate.Target a Service, InferencePool, ServiceImport, or GCPInferencePoolImport with a BackendTLSPolicy that references the ConfigMap:
Service
The following manifest shows a BackendTLSPolicy targeting a Service:
apiVersion: gateway.networking.k8s.io/v1 kind: BackendTLSPolicy metadata: name: secure-backend-policy spec: targetRefs: - group: "" # empty group means Core API. kind: Service name: my-service-name validation: hostname: "backend.example.com" caCertificateRefs: - group: "" # empty group means Core API. kind: ConfigMap name: my-backend-caInferencePool
The following manifest shows a BackendTLSPolicy targeting an InferencePool:
apiVersion: gateway.networking.k8s.io/v1 kind: BackendTLSPolicy metadata: name: secure-backend-policy-inferencepool spec: targetRefs: - group: "inference.networking.k8s.io" # For InferencePool kind: InferencePool name: my-inference-pool validation: hostname: "backend.example.com" caCertificateRefs: - group: "" # empty group means Core API. kind: ConfigMap name: my-backend-caServiceImport
The following manifest shows a BackendTLSPolicy targeting a ServiceImport:
apiVersion: gateway.networking.k8s.io/v1 kind: BackendTLSPolicy metadata: name: secure-backend-policy-serviceimport spec: targetRefs: - group: "net.gke.io" # For ServiceImport kind: ServiceImport name: my-service-import validation: hostname: "backend.example.com" caCertificateRefs: - group: "" # empty group means Core API. kind: ConfigMap name: my-backend-caGCPInferencePoolImport
The following manifest shows a BackendTLSPolicy targeting a GCPInferencePoolImport:
apiVersion: gateway.networking.k8s.io/v1 kind: BackendTLSPolicy metadata: name: secure-backend-policy-gcpinferencepoolimport spec: targetRefs: - group: "networking.gke.io" # For GCPInferencePoolImport kind: GCPInferencePoolImport name: my-gcp-inference-pool-import validation: hostname: "backend.example.com" caCertificateRefs: - group: "" # empty group means Core API. kind: ConfigMap name: my-backend-ca
Use a self-managed TrustConfig (Advanced)
This method lets you reference a TrustConfig resource that you manage independently in Google Cloud Certificate Manager.
Create a TrustConfig resource in Certificate Manager. The TrustConfig must be created in the same project and location as the Gateway.
- For global or multi-cluster Gateways (including regional
multi-cluster) and cross-regional Gateways, use the
globallocation. - For regional single-cluster Gateways, use the same region as the Gateway.
- If your Service is used by multiple Gateways in different locations, you must create a TrustConfig resource with the same name in each of those locations.
- For global or multi-cluster Gateways (including regional
multi-cluster) and cross-regional Gateways, use the
Target a Service with a BackendTLSPolicy that references the external TrustConfig resource through the
optionsfield:apiVersion: gateway.networking.k8s.io/v1 kind: BackendTLSPolicy metadata: name: secure-backend-policy spec: targetRefs: - group: "" # empty group means Core API. kind: Service name: my-service-name validation: wellKnownCACertificates: "System" hostname: "backend.example.com" options: networking.gke.io/backend-trust-config: "my-trust-config-name"
BackendTLSPolicy field reference
The following table describes the key fields in a BackendTLSPolicy resource:
| Field | Description |
|---|---|
targetRefs | The backend
resources to which this policy applies. Supports Service (group:
""), InferencePool (group:
"inference.networking.k8s.io"), ServiceImport (group:
"net.gke.io"), or GCPInferencePoolImport (group:
"networking.gke.io"). Note: For
gke-l7-global-external-managed and
gke-l7-global-external-managed-mc GatewayClasses, only
Service and ServiceImport backends are supported. |
validation.hostname |
The hostname (SNI) used by the Gateway during the TLS handshake with the backend pods. |
validation.subjectAltNames |
Optional. Defines one or more Subject Alternative Names (SANs) to
validate against the backend's certificate. Supports Hostname
and URI (such as SPIFFE IDs). |
validation.caCertificateRefs |
Standard method. References a list of ConfigMap resources
(up to eight) in the same namespace. Each ConfigMap must contain a single
PEM-encoded CA certificate under the ca.crt key.
Cross-namespace references are not supported. |
validation.wellKnownCACertificates |
Advanced method. Set the value to System when using a self-managed TrustConfig. |
options | A map for
GKE-specific options. Use the
networking.gke.io/backend-trust-config setting to reference
an external TrustConfig resource. |
Verify the Backend TLS configuration
After applying the BackendTLSPolicy, verify that the Gateway controller has accepted the configuration by checking the policy status:
kubectl describe backendtlspolicy POLICY_NAME
Replace POLICY_NAME with the name of your policy.
A policy is successfully applied if it contains Accepted and ResolvedRefs
conditions with Status: "True" in the Status.Ancestors section:
Status:
Ancestors:
- Ancestor Ref:
Group: gateway.networking.k8s.io
Kind: Gateway
Name: my-gateway-name
Namespace: default
Conditions:
- Last Transition Time: "2026-02-17T15:19:26Z"
Message: ""
Reason: Accepted
Status: "True"
Type: Accepted
- Last Transition Time: "2026-02-17T15:19:26Z"
Message: ""
Reason: ResolvedRefs
Status: "True"
Type: ResolvedRefs
Controller Name: networking.gke.io/gateway
If Status is False for any of these conditions, it indicates the policy has
not been applied. Check the Reason and Message fields for more details.
Common errors include referencing a ConfigMap in caCertificateRefs that
does not exist or is missing the ca.crt key.
This status confirms that the Gateway has successfully validated the policy and applied the TLS settings to the backends of the target Service or InferencePool. The BackendTLSPolicy resource must reside in the same namespace as the target resource.
Secure load balancer to application traffic using TLS
You can encrypt traffic from the load balancer to backend Pods using the
ports[].appProtocol field. The supported fields for appProtocol are: HTTP,
HTTPS, HTTP2, and kubernetes.io/h2c.
The following manifest describes a Service that specifies the load balancer must use HTTPS traffic to communication with the backend Pods:
apiVersion: v1
kind: Service
metadata:
name: store-v2
spec:
selector:
app: store
version: v2
ports:
- port: 8080
targetPort: 8080
appProtocol: HTTPS
The load balancer does not verify the certificate used by backend Pods. It is your responsibility to ensure the certificate used on the backend Pods is valid.
Secure client to load balancer traffic using SSL policies
When your applications are exposed through an external gateway that uses HTTPS, it is important to use the latest protocols or specify the minimum SSL or TLS version. You can secure the client to load balancer traffic by using SSL policies.
To know more about SSL policies that can be attached to your Gateway and how to create them, see Configure SSL Policies to secure client to load balancer traffic.
Protect your backends using Google Cloud Armor
Google Cloud Armor security policies
help you protect your load-balanced applications from web-based attacks. Once
you have configured a Google Cloud Armor security policy,
you can reference it in a GCPBackendPolicy applied to your Kubernetes Services.
To configure Google Cloud Armor policies with Gateway, see Configure Google Cloud Armor security policy to secure your backend Services.
Authenticate requests to your backends using Identity-Aware Proxy
Identity-Aware Proxy helps you protect your backends from
unwanted traffic by authenticating clients sending requests to your applications
and enforcing role-based traffic authorization. After you enable Identity-Aware Proxy
for GKE, you can reference
your OAuth credentials in a GCPBackendPolicy applied to your Kubernetes
Services.
To configure Identity-Aware Proxy with Gateway, see Configure Identity-Aware Proxy.
What's next
- Learn more about Gateway security.
- Learn how to configure Gateway resources using Policies.
- Learn how to deploy Gateways.
- Learn more about Gateway API