Day Two Operations of Gateway API

Patrik Hörlin
Predictly on Tech
Published in
5 min readJan 16, 2024

In my previous article, I showed how the new Gateway compares to the traditional Ingress API and why you would wan’t to migrate away from using Ingress.

In this article, I will focus on the other possibilities that the Gateway API provides. Note that some of the instructions in this article only work for Google Cloud and GKE as they have adopted the standard with custom resource definitions (CRD).

Sun is rising on the second day of operating your Gateway resources
Photo by Simon Berger on Unsplash

HTTP to HTTPS

As a platform architect, making sure that all of our external clients access our services and web applications using HTTPS is a given. In the previous article this was resolved by just not exposing the HTTP endpoint at all. But considering a web site where user are likely to just enter the address, we should help them transfer to HTTPS to provide them with a secure experience.

kind: Gateway
apiVersion: gateway.networking.k8s.io/v1beta1
metadata:
name: gw-ingress
namespace: ingress-gw-api
annotations:
networking.gke.io/certmap: gw-ingress-demo
spec:
gatewayClassName: gke-l7-global-external-managed
listeners:
- name: https
protocol: HTTPS
port: 443
allowedRoutes:
kinds:
- kind: HTTPRoute
namespaces:
from: All
- name: http
protocol: HTTP
port: 80
allowedRoutes:
kinds:
- kind: HTTPRoute
namespaces:
from: Same
addresses:
- type: NamedAddress
value: gateway-ip
---
kind: HTTPRoute
apiVersion: gateway.networking.k8s.io/v1beta1
metadata:
name: http-redirect
namespace: ingress-gw-api
spec:
parentRefs:
- namespace: ingress-gw-api
name: gw-ingress
sectionName: http
rules:
- filters:
- type: RequestRedirect
requestRedirect:
scheme: https

With this configuration we enable a listener on port 80 for HTTP traffic but we restrict the use of it to HTTPRoutes in the same namespace. And provided the HTTPRoute, all calls made using HTTP will be redirected to HTTPS.

curl http://gw-ingress.predictly.se/a?test=true -v
* Trying 34.128.166.39:80...
* Connected to gw-ingress.predictly.se (34.128.166.39) port 80 (#0)
> GET /a?test=true HTTP/1.1
> Host: gw-ingress.predictly.se
> User-Agent: curl/7.88.1
> Accept: */*
>
< HTTP/1.1 302 Found
< Cache-Control: private
< Location: https://gw-ingress.predictly.se:443/a?test=true
< Content-Length: 0
< Date: Mon, 25 Dec 2023 13:50:56 GMT
< Content-Type: text/html; charset=UTF-8
<
* Connection #0 to host gw-ingress.predictly.se left intact

Using RBAC we can make sure that application developers can’t modify this basic constraint and thereby risking exposing an application in an insecure way.

Ensure Encryption Standard using SSL Policy

One issue that must be resolved when creating a Gateway instance (or any type of load balancer) is to replace the default SSL policy as it is too weak.

apiVersion: compute.cnrm.cloud.google.com/v1beta1
kind: ComputeSSLPolicy
metadata:
name: sslpolicy-moderntls12
namespace: ingress-gw-api
annotations:
cnrm.cloud.google.com/project-id: predictly-conf-frontend-lab
spec:
description: An SSL Policy with a MODERN encryption profile, supporting several modern methods of encryption for TLS 1.2 and up.
minTlsVersion: TLS_1_2
profile: MODERN
---
apiVersion: networking.gke.io/v1
kind: GCPGatewayPolicy
metadata:
name: tls12-gateway-policy
namespace: ingress-gw-api
spec:
default:
sslPolicy: sslpolicy-moderntls12
targetRef:
group: gateway.networking.k8s.io
kind: Gateway
name: gw-ingress

We have now restricted our Gateway to only accept connections using TLS 1.2 and above.

Load balancer in Cloud Console using sslpolicy-moderntls12

Protect your workload using Cloud Armor Security Policy

For more advanced protection of your HTTP based workload, Google offers Cloud Armor Security Policy as a tool to monitor and protect your services. Note that setting this up and configuring your policies correct is a completely separate topic, do not take this configuration and put in production!

apiVersion: compute.cnrm.cloud.google.com/v1beta1
kind: ComputeSecurityPolicy
metadata:
name: gw-ingress-security-policy
namespace: gw-ingress-api
annotations:
cnrm.cloud.google.com/project-id: predictly-conf-frontend-lab
spec:
description: A policy designed to allow access only to client from Sweden.
adaptiveProtectionConfig:
autoDeployConfig:
confidenceThreshold: 0.5
expirationSec: 7200
impactedBaselineThreshold: 0.01
loadThreshold: 0.8
layer7DdosDefenseConfig:
enable: true
ruleVisibility: STANDARD
rule:
- action: allow
priority: 1000
match:
expr:
expression: 'origin.region_code == "SE"'
description: Allow access to clients from Sweden
- action: deny(403)
priority: 2147483647
match:
versionedExpr: SRC_IPS_V1
config:
srcIpRanges:
- "*"
description: Rule matching all IPs with priority 2147483647, set to deny.
---
apiVersion: networking.gke.io/v1
kind: GCPBackendPolicy
metadata:
name: echoserver-security-policy
namespace: echoserver
spec:
default:
securityPolicy: gw-ingress-security-policy
targetRef:
group: ""
kind: Service
name: echoserver

Note that the final resource in this example is not part of the Gateway API, it’s a custom Google extension. Also note that we are not targeting the Gateway or the HTTPRoute with this configuration, instead we are targeting the Service.

patrik@euw3-admin-host:~$ curl https://gw-ingress.predictly.se -kv
* Trying 34.128.166.39:443...
* Connected to gw-ingress.predictly.se (34.128.166.39) port 443 (#0)
...
> GET / HTTP/2
> Host: gw-ingress.predictly.se
> user-agent: curl/7.88.1
> accept: */*
>
...
< HTTP/2 403
< content-type: text/html; charset=UTF-8
< content-length: 134
< via: 1.1 google
< date: Mon, 25 Dec 2023 13:55:54 GMT
< alt-svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000
<
* Connection #0 to host gw-ingress.predictly.se left intact
<!doctype html><meta charset="utf-8"><meta name=viewport content="width=device-width, initial-scale=1"><title>403</title>403 Forbidden

Access is denied (HTTP 403) when originating from a VM in europe-west3.

Session Affinity

Some workloads require that the client once connected stays on the same instance for the duration of their session. This can be achieved by configuring session affinity on the Service.

apiVersion: networking.gke.io/v1
kind: GCPBackendPolicy
metadata:
name: gw-ingress-security-policy
namespace: echoserver
spec:
default:
sessionAffinity:
type: GENERATED_COOKIE
cookieTtlSec: 0
targetRef:
group: ""
kind: Service
name: echoserver

This configuration will set the GCLB cookie in the response of the client which will last for the duration of the session.

patrik@euw3-admin-host:~$ curl https://gw-ingress.predictly.se -kv
* Trying 34.128.166.39:443...
* Connected to gw-ingress.predictly.se (34.128.166.39) port 443 (#0)
...
> GET / HTTP/2
> Host: gw-ingress.predictly.se
> user-agent: curl/7.88.1
> accept: */*
>
...
< HTTP/2 200
< date: Mon, 25 Dec 2023 15:10:37 GMT
< content-type: text/plain
< server: echoserver
< set-cookie: GCLB="835602333cf872db"; Path=/; HttpOnly

This cookie will be shared between all applications that are hosted on the same domain since it at this stage is not possible to specify path in the spec.

--

--