DEV Community

Cover image for Native CORS support on GKE Gateway: Offloading cross-origin policy management to infrastructure
Olivier Bourgeois for Google Cloud

Posted on

Native CORS support on GKE Gateway: Offloading cross-origin policy management to infrastructure

Web browsers enforce the Same-Origin Policy by default to protect users from malicious scripts trying to read data across distinct origins. However, modern application architectures almost always require cross-origin communication. Single-page applications, mobile clients, and embedded web components regularly fetch data and stream AI model inferences across separate domains, subdomains, and ports.

To allow these interactions safely, applications must implement Cross-Origin Resource Sharing (CORS). For years, teams running Kubernetes workloads on Ingress-Nginx handled this using annotations like nginx.ingress.kubernetes.io/enable-cors. When migrating to the Kubernetes Gateway API and GKE Gateway, the lack of native CORS support was a frequent operational pain point, making it one of the most requested missing capabilities.

The GKE team addressed this gap with the Preview release of native CORS support for GKE Gateway and Inference Gateway. In this article, I will break down how the new CORS filter works, why moving cross-origin policy management to the load balancer matters, and the operational nuances you need to consider.

Why manage CORS at the ingress layer?

Implementing CORS inside individual backend applications introduces architectural friction across three main areas:

  • Redundant application logic: Every backend service or framework (Node.js, FastAPI, Spring, or inference engines like vLLM) must include middleware to evaluate incoming headers and generate preflight responses.
  • Preflight resource consumption: Complex web requests trigger preflight OPTIONS calls. Routing these preflight requests to backend containers wastes application memory, CPU cycles, and network bandwidth on pure protocol negotiation.
  • Configuration sprawl and drift: When dozens of microservices manage their own CORS policies, subtle discrepancies in allowed headers, exposed headers, or origin validation create security vulnerabilities and broken client integrations.

By shifting CORS processing to GKE Gateway, Google Cloud Load Balancing terminates OPTIONS preflight requests directly at the network edge and injects required response headers (Access-Control-Allow-Origin, Access-Control-Allow-Methods, and Access-Control-Allow-Headers). Your backend applications only receive validated application requests, removing boilerplate code and reducing compute overhead.

Configuring the CORS filter in HTTPRoute

GKE Gateway implements CORS support directly through the open-source Gateway API specification. You define policies declaratively using a CORS filter within the rules section of an HTTPRoute manifest.

Here is an example configuring a CORS policy on an API route:

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: api-cors-route
  namespace: production
spec:
  parentRefs:
  - name: external-gateway
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /api
    backendRefs:
    - name: api-service
      port: 8080
    filters:
    - type: CORS
      cors:
        allowOrigins:
        - "https://app.example.com"
        - "https://*.partner-domain.com"
        allowMethods:
        - GET
        - POST
        - PUT
        - DELETE
        allowHeaders:
        - Authorization
        - Content-Type
        - X-Requested-With
        exposeHeaders:
        - X-Request-ID
        allowCredentials: true
        maxAge: 3600
Enter fullscreen mode Exit fullscreen mode

The cors configuration block gives you granular control over the negotiation parameters:

  • allowOrigins: Specifies the allowed origins via explicit URLs (https://app.example.com), wildcard patterns (https://*.partner-domain.com), or a catch-all wildcard (*).
  • allowMethods: Lists the permitted HTTP methods. You can also specify * to allow all methods.
  • allowHeaders: Defines the HTTP request headers that clients can send in their requests.
  • exposeHeaders: Lists response headers that the browser makes accessible to client scripts beyond simple response headers.
  • allowCredentials: Sets the Access-Control-Allow-Credentials header to true or false, dictating whether browsers can share responses with requests carrying cookies or authentication headers.
  • maxAge: Defines the number of seconds the browser can cache the preflight response (defaulting to 5 seconds), significantly cutting down subsequent OPTIONS traffic.

Security considerations with credentials and wildcards

When designing your CORS policies on GKE Gateway, pay careful attention to the interaction between allowOrigins and allowCredentials.

Under standard browser security rules, browsers block responses to credentialed requests if Access-Control-Allow-Origin is set to a literal wildcard (*). However, when you configure wildcard patterns or a wildcard in allowOrigins in GKE Gateway, the controller dynamically matches and reflects the incoming request origin rather than returning a literal asterisk.

Because the browser sees an explicit origin returned alongside allowCredentials: true, it permits the response. If you configure allowOrigins: ["*"] with allowCredentials: true, any arbitrary website can potentially read authenticated user responses. For authenticated APIs, always define explicit domain lists rather than catch-all wildcards.

Supported GatewayClasses and architectural constraints

This Preview release supports single-cluster GKE Gateway deployments across three primary GatewayClasses:

  • gke-l7-rilb: Regional internal Application Load Balancer.
  • gke-l7-regional-external-managed: Regional external Application Load Balancer.
  • gke-l7-global-external-managed: Global external Application Load Balancer.

It also supports AI inference workloads exposed via Inference Gateway, allowing frontend chat interfaces or client SDKs to query served models directly across origins.

Before implementing this in production, keep the following technical limits in mind:

  • Single-cluster only: Multi-cluster gateways (gke-l7-gmc-*) do not currently support the CORS filter.
  • Filter conflicts: You cannot combine a CORS filter and a RequestRedirect filter within the same route rule.
  • URL map regular expression limits: The GKE Gateway controller translates wildcard origin patterns into regular expressions on the underlying Cloud Load Balancing URL maps. For gke-l7-global-external-managed, there is a limit of one regular expression per Gateway listener, and combining wildcard origins with PathPrefix matches is not supported. For regional external and regional internal GatewayClasses, you can use up to five regular expressions per hostname. Note that exact origins and catch-all * entries do not count against these regex quotas.

Next steps

Native CORS support in GKE Gateway eliminates one of the biggest functional gaps for organizations migrating workloads from legacy Ingress controllers to the Kubernetes Gateway API. By managing cross-origin policies declaratively at the routing layer, platform teams can simplify application code and centralize security posture across all services.

To learn more and begin testing CORS in your clusters, check out the official GKE Gateway CORS documentation and the upstream Gateway API CORS User Guide.

Top comments (0)