Configure CORS policy
Configure Cross-Origin Resource Sharing (CORS) headers at the ingress level so external browser-based clients can make API requests to vCluster Platform.
Prerequisites
- A deployed vCluster Platform instance with external access configured.
- An ingress controller (such as ingress-nginx) deployed on the host cluster.
helmv3.10+ andkubectlwith admin access to the cluster.
Overview
If you build browser-based tools, such as a custom operations dashboard, a monitoring UI, or a CI interface, that call the Platform API from a different domain, browsers block those requests by default. This is the same-origin policy. CORS headers tell the browser which external origins are allowed.
For example, a dashboard at https://dashboard.example.com that fetches data from the Platform API at https://platform.example.com fails unless the Platform ingress returns the correct CORS headers.
The Platform UI and API share the same origin. Normal Platform access, kubectl commands, and in-cluster service-to-service traffic don't require CORS. Configure CORS only when a browser-based application at a different origin calls the Platform API.
The Platform doesn't set CORS headers by default. Add them through your ingress controller.
Configure ingress-level CORS
ingress-nginx
Create or update your
vcluster-platform.yamlwith CORS annotations on the Platform ingress:Modify the following with your specific values to generate a copyable command:vcluster-platform.yamlingress:
enabled: true
host: "platform.example.com"
annotations:
# CORS
nginx.ingress.kubernetes.io/enable-cors: "true"
nginx.ingress.kubernetes.io/cors-allow-origin: "https://dashboard.example.com"
nginx.ingress.kubernetes.io/cors-allow-methods: "GET, POST, PUT, DELETE, PATCH, OPTIONS"
nginx.ingress.kubernetes.io/cors-allow-headers: "Authorization, Content-Type"
nginx.ingress.kubernetes.io/cors-allow-credentials: "true"
nginx.ingress.kubernetes.io/cors-max-age: "3600"
tls:
enabled: true
secret: tls-vcluster-platformApply the configuration:
Modify the following with your specific values to generate a copyable command:Upgrade the Platform with CORS annotationshelm upgrade vcluster-platform vcluster-platform \
--repo https://charts.loft.sh/ \
--namespace vcluster-platform \
--reuse-values \
-f vcluster-platform.yamlVerify the ingress returns CORS headers by sending a preflight request:
Modify the following with your specific values to generate a copyable command:Test CORS preflightcurl -v -X OPTIONS \
-H "Origin: https://dashboard.example.com" \
-H "Access-Control-Request-Method: GET" \
https://platform.example.com/kubernetes/management/apisA correct response includes these headers:
Access-Control-Allow-Origin: https://dashboard.example.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, PATCH, OPTIONS
Access-Control-Allow-Headers: Authorization, Content-TypeIf these headers are missing, check the ingress annotations and confirm the ingress controller processes them.
Annotation reference
All annotations use the nginx.ingress.kubernetes.io/ prefix.
| Annotation | Description | Default |
|---|---|---|
enable-cors | Enable CORS headers | "false" |
cors-allow-origin | Allowed origins (comma-separated) | "*" |
cors-allow-methods | Allowed HTTP methods | "GET, PUT, POST, DELETE, PATCH, OPTIONS" |
cors-allow-headers | Allowed request headers | Standard browser headers and Authorization |
cors-allow-credentials | Allow credentials (cookies, auth) | "false" |
cors-expose-headers | Response headers exposed to browser | (none) |
cors-max-age | Preflight cache duration in seconds | "1728000" |
Don't set cors-allow-origin to "*" when cors-allow-credentials is "true". Browsers reject this combination per the CORS specification. List explicit origins instead.
Other ingress controllers
Traefik, Istio, and Gateway API support CORS through their own configuration:
- Traefik: Use the headers middleware with
accessControlAllowOriginListon an IngressRoute. - Istio: Use the
corsPolicyfield on a VirtualService. See Expose vCluster Platform with Istio for a related setup guide. - Gateway API: The experimental CORS filter (Gateway API v1.3+) supports CORS on HTTPRoute resources. See the Gateway API CORS guide for details.
Security considerations
Restrict allowed origins
Setting cors-allow-origin to "*" disables CORS protection. Any website a user visits can make cross-origin requests to the Platform API.
Never use cors-allow-origin: "*" in production. List only the specific domains that need access.
- Prefer explicit origins (
https://dashboard.example.com) over wildcards. - Separate development and production configurations. Don't include localhost origins in production values.
CORS doesn't replace authentication
CORS headers control which origins a browser permits for cross-origin requests. They don't authenticate or authorize API calls. The Platform's authentication, RBAC, and network policies remain the primary access controls.
Troubleshoot CORS issues
Browser shows "blocked by CORS policy"
The ingress didn't return an Access-Control-Allow-Origin header for the requesting origin. Verify the following:
- The
enable-corsannotation is"true"on the Platform ingress. - The
cors-allow-originvalue matches the exact origin the browser sends. Scheme, host, and port must all match. - The ingress controller terminates TLS. Check the Platform's TLS configuration.
Limitations
- Changes to ingress annotations require a
helm upgradeof the Platform to update the ingress resource.