This page explains how you can secure a Gateway using various security features:
SSL Policies to 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 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
gcloud components update
.
GKE Gateway controller requirements
- For Standard, GKE version 1.24 or later.
- For Autopilot, GKE version 1.26 or later.
- Google Cloud CLI version 407.0.0 or later.
- The Gateway API is supported on VPC-native clusters only.
- If you are using the internal GatewayClasses, you must enable a proxy-only subnet.
- Your cluster must have the
HttpLoadBalancing
add-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 User
role to the GKE Service account for the service project.
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/certmap
annotation with atls.certificateRefs
on the same Gateway resource. If you reference aCertificateMap
in 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-certificates
annotation.The
appProtocol
field in the Service configuration only accepts capital letters for the protocol value (HTTP
,HTTPS
orHTTP2
). Using lowercase letters results in using HTTP as the protocol with the backends.
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 2048
Replace
PRIVATE_KEY_FILE
with 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 EOF
Replace
CONFIG_FILE
with 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_FILE
Replace
CSR_FILE
with 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 30
Replace
CERTIFICATE_FILE
with 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_FILE
GKE 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/v1beta1 metadata: name: external-http spec: gatewayClassName: gke-l7-global-external-managed listeners: - name: https protocol: HTTPS port: 443 tls: mode: Terminate certificateRefs: - name: store-example-com
This manifest describes a Gateway with the following properties:
gatewayClassName: gke-l7-global-external-managed
: deploys a global external Application Load Balancer.protocol: HTTPS
andport: 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.yaml
Save the following manifest as
store-external-route.yaml
:kind: HTTPRoute apiVersion: gateway.networking.k8s.io/v1beta1 metadata: name: store-external labels: gateway: external-http spec: parentRefs: - name: external-http hostnames: - "store.example.com" rules: - backendRefs: - name: store-v1 port: 8080
This manifest describes an HTTPRoute that matches traffic to
store.example.com
and sends it to thestore-v1
Service.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.12
This 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 -v
Replace 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
--resolve
option 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 * 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
SslCertificate
resource: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/v1beta1 metadata: name: external-http spec: gatewayClassName: gke-l7-global-external-managed listeners: - name: https protocol: HTTPS port: 443 tls: mode: Terminate options: networking.gke.io/pre-shared-certs: store-example-com
This manifest describes a Gateway with the following properties:
gatewayClassName: gke-l7-global-external-managed
: deploys a global external Application Load Balancer.protocol:HTTPS
andport: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.yaml
Save the following HTTPRoute manifest as
store-external-route.yaml
:kind: HTTPRoute apiVersion: gateway.networking.k8s.io/v1beta1 metadata: name: store-external labels: gateway: external-http spec: parentRefs: - name: external-http hostnames: - "store.example.com" rules: - backendRefs: - name: store-v1 port: 8080
Deploy the HTTPRoute in your cluster:
kubectl apply -f store-external-route.yaml
It 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.12
This 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 -v
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.
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
Certificate
resource 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-map
Create a
CertificateMapEntry
which 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
Certificate
resource 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/v1beta1 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
This manifest describes a Gateway with the following properties:
gatewayClassName: gke-l7-global-external-managed
: deploys a global external Application Load Balancer.protocol: HTTPS
andport: 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.yaml
It 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/v1beta1 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: 8080
Apply 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/v1beta1 metadata: name: gateway namespace: corp spec: gatewayClassName: gke-17-regional-external-managed listeners: - name: gateway-pre-shared-certmap protocol: HTTPS port: 443 tls: mode: Terminate options: networking.gke.io/cert-manager-certs: store-example-com-cert1, store-example-com-cert2 allowedRoutes: kinds: - kind: HTTPRoute namespaces: from: All
This manifest describes a Gateway with the following properties:
gatewayClassName
:gke-l7-regional-external-managed
: deploys a regional external Application Load Balancer.protocol: HTTPS
andport: 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
gatewayClassName
togke-17-rilb
. This deploys an internal Application Load Balancer.Apply the manifest to the cluster:
kubectl apply -f external-gateway.yaml
To create an HTTPRoute, save the following manifest as
store-external-route.yaml
:apiVersion: gateway.networking.k8s.io/v1beta1 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: 8080
This manifest describes an HTTPRoute that matches traffic for
store.example.com
and forwards the traffic to thestore-v1
Service.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.12
This 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 -v
Replace 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.
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
, and HTTP2
.
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.