Starting with NGINX Ingress Controller (NIC) v5.4.0, you can define CORS behavior once in a Policy resource and apply it consistently across both VirtualServer and Ingress traffic paths.
Across this blog, we’re focused on:
- How CORS policy works in NGINX Ingress Controller.
- Where to attach it in
VirtualServerandIngress.
Why Use a Policy For CORS?
Many teams start with per-resource tuning and quickly end up with drift. Using a dedicated Policy for CORS gives you:
- A single source of truth for allowed origins, methods, and headers.
- Reuse across services and namespaces.
- Cleaner reviews because CORS behavior is isolated from route logic.
How CORS Policy Works in NGINX Ingress Controller
At a high level:
- Create a
Policyresource withspec.cors - Attach it where traffic is defined:
VirtualServer.spec.policies(or route/subroute policies)Ingressvia thenginx.org/policiesannotation
- NGINX Ingress Controller renders the corresponding NGINX CORS behavior and returns headers for preflight and actual cross-origin requests.
Example CORS Policy:
apiVersion: k8s.nginx.org/v1
kind: Policy
metadata:
name: cors-policy
spec:
cors:
allowOrigin:
- https://app.example.com
allowMethods:
- GET
- POST
- PUT
- OPTIONS
allowHeaders:
- Content-Type
- Authorization
- X-Requested-With
exposeHeaders:
- X-Total-Count
- X-Page-Size
allowCredentials: true
maxAge: 86400
Example of VirtualServer referencing above CORS Policy:
apiVersion: k8s.nginx.org/v1
kind: VirtualServer
metadata:
name: webapp
spec:
host: webapp.example.com
policies:
- name: cors-policy
upstreams:
- name: webapp
service: webapp-svc
port: 80
routes:
- path: /test
action:
pass: webapp
Example of Ingress referencing above CORS Policy:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: cafe-ingress
annotations:
nginx.org/policies: "cors-policy"
spec:
ingressClassName: nginx
rules:
- host: cafe.example.com
http:
paths:
- path: /tea
pathType: Prefix
backend:
service:
name: tea-svc
port:
number: 80
Important behavior to remember:
- CORS policy can be applied to both
VirtualServerandIngress. - For
VirtualServer, route/subroute policies override same-type policy at spec level. - For credentialed CORS (
allowCredentials: true), explicit origins are required.
Production Checks That Prevent Most Issues
Before rollout, validate these explicitly:
- Non-allowed origins do not receive
Access-Control-Allow-Origin. allowCredentials: trueis only used with explicit origins (not*).
Security Considerations
CORS is a browser enforcement boundary, so keep it tight:
- Use explicit origin allow-lists for production.
- Avoid broad method/header lists unless required.
- Treat
allowCredentialsas high trust; use narrowly scoped origins. - Review CORS policy changes with the same care as auth-related config changes.
You can find complete working examples on github and more documentation in our docs:


