Kubernetes
Contour Ingress
CORS
API Management
Cloud Native

Dealing with CORS using the Contour Kubernetes Ingress

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

When browser clients call an API through Contour, CORS must usually be handled at the HTTP layer before the request reaches your application. In practice, that often means configuring CORS on Contour's HTTPProxy routes so Envoy can answer preflight requests and attach the correct response headers consistently.

What Problem CORS Is Solving

Browsers restrict cross-origin requests unless the server explicitly allows them. That is why a frontend on one origin and an API on another may fail even though the network route itself is fine.

Typical headers involved are:

  • 'Access-Control-Allow-Origin'
  • 'Access-Control-Allow-Methods'
  • 'Access-Control-Allow-Headers'
  • 'Access-Control-Allow-Credentials'

If these are missing or wrong, the browser blocks the request even if the backend would otherwise respond normally.

Why Configure CORS at Contour

Contour sits in front of your services using Envoy, so it is a good place to centralize cross-origin rules. That gives you a few advantages:

  • one place to manage policy
  • consistent preflight handling
  • less duplicated CORS code across many services

This is especially useful when several backends share the same frontend clients and should expose similar cross-origin rules.

A Typical HTTPProxy Example

Contour's HTTPProxy resource supports route-level CORS configuration. A representative example looks like this:

yaml
1apiVersion: projectcontour.io/v1
2kind: HTTPProxy
3metadata:
4  name: api-proxy
5  namespace: default
6spec:
7  virtualhost:
8    fqdn: api.example.com
9  routes:
10    - conditions:
11        - prefix: /
12      corsPolicy:
13        allowOrigin:
14          - https://app.example.com
15        allowMethods:
16          - GET
17          - POST
18          - OPTIONS
19        allowHeaders:
20          - Content-Type
21          - Authorization
22        exposeHeaders:
23          - X-Request-Id
24        allowCredentials: true
25        maxAge: "10m"
26      services:
27        - name: api-service
28          port: 8080

The key part is corsPolicy. That tells Contour and Envoy how to answer browser CORS checks before the request reaches the service.

Preflight Requests Matter

A lot of CORS confusion comes from preflight requests. Before sending certain cross-origin requests, the browser sends an OPTIONS request asking whether the real request is allowed.

If your ingress does not answer that preflight correctly, the browser never sends the actual API request.

That is why CORS often feels like a backend bug even when your application logs show nothing: the browser blocked the call before the main request happened.

Be Specific About Origins

The most important design choice is what to allow in allowOrigin.

For example:

  • good for production: https://app.example.com
  • risky if used broadly: *

A wildcard is convenient for quick testing but often too permissive for real deployments, especially when credentials are involved. If you need cookies or authenticated browser requests, be deliberate about exactly which frontend origins are allowed.

Debugging the Effective Behavior

When CORS still fails, inspect the live response headers rather than only the YAML. A browser developer console or a direct curl request can help.

For example, you can simulate a preflight request:

bash
curl -i -X OPTIONS https://api.example.com/endpoint \
  -H "Origin: https://app.example.com" \
  -H "Access-Control-Request-Method: POST"

Check whether the response contains the expected Access-Control-Allow-* headers. If not, either the HTTPProxy is wrong, the request is not matching the route you think it is, or Contour has not applied the configuration as expected.

Common Pitfalls

The biggest mistake is enabling CORS only in the backend service while assuming Contour will automatically handle preflight traffic the same way. If the ingress intercepts the request path, it may need explicit configuration.

Another mistake is allowing * and allowCredentials: true together conceptually. Credentialed browser requests need more deliberate origin rules than an unrestricted wildcard setup.

People also forget that route matching matters. A corsPolicy on one route does not help a request that is actually landing on a different route or proxy resource.

Finally, do not debug CORS only from server logs. A browser can block the request based on response headers even when the backend itself looks healthy.

Summary

  • With Contour, CORS is often best handled on HTTPProxy routes.
  • Correct preflight handling is just as important as the main request response.
  • 'corsPolicy lets Envoy return the required Access-Control-Allow-* headers.'
  • Be specific about allowed origins, especially when credentials are involved.
  • Verify actual response headers with browser tools or curl, not just the YAML definition.

Course illustration
Course illustration

All Rights Reserved.