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:
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:
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
HTTPProxyroutes. - Correct preflight handling is just as important as the main request response.
- '
corsPolicylets Envoy return the requiredAccess-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.

