In many cases, a public api is desired with the ability to run commands with public credentials, but the default cors allow-origin is set to '*' which will not allow a request with credentials to be exposed by the browser.
Failed to load xxxx: Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. Origin 'xxxx' is therefore not allowed access. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
A knob in the annotations to allow this and copy the origin into the outgoing request would be super nice!
@dgregoire please check https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/#enable-cors
@aledbf yes - that
nginx.ingress.kubernetes.io/cors-allow-origin controls what's the accepted Origin for CORS and defaults to '*'. This is a single field value, with the following format: http(s)://origin-site.com or http(s)://origin-site.com:port Example: nginx.ingress.kubernetes.io/cors-allow-origin: "https://origin-site.com:4443"
if you send a fetch() request with credentials to an ingress rule setup with the default "*", the browser wont expose it to the running script because wildcards are not allowed on access-control-allow-credentials: true. It would be super nice to have a knob that copies the incoming Origin: host.com header to the outgoing allow-origin header.
@dgregoire
Did u solve the problem in another way?
upd:
Found the solution
nginx.ingress.kubernetes.io/configuration-snippet: |
add_header Access-Control-Allow-Origin $http_origin;
add_header Access-Control-Allow-Methods "POST, GET, OPTIONS";
add_header Access-Control-Allow-Credentials true;
@odinsy
Thanks, good idea!
@aledbf
How do you feel about having the controller handle that case?
@claudiuchis provided a workaround at https://github.com/kubernetes/ingress-nginx/issues/1171#issuecomment-391988766
Issues go stale after 90d of inactivity.
Mark the issue as fresh with /remove-lifecycle stale.
Stale issues rot after an additional 30d of inactivity and eventually close.
If this issue is safe to close now please do so with /close.
Send feedback to sig-testing, kubernetes/test-infra and/or fejta.
/lifecycle stale
Stale issues rot after 30d of inactivity.
Mark the issue as fresh with /remove-lifecycle rotten.
Rotten issues close after an additional 30d of inactivity.
If this issue is safe to close now please do so with /close.
Send feedback to sig-testing, kubernetes/test-infra and/or fejta.
/lifecycle rotten
Rotten issues close after 30d of inactivity.
Reopen the issue with /reopen.
Mark the issue as fresh with /remove-lifecycle rotten.
Send feedback to sig-testing, kubernetes/test-infra and/or fejta.
/close
@fejta-bot: Closing this issue.
In response to this:
Rotten issues close after 30d of inactivity.
Reopen the issue with/reopen.
Mark the issue as fresh with/remove-lifecycle rotten.Send feedback to sig-testing, kubernetes/test-infra and/or fejta.
/close
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository.
Would be nice for the ingress to handle *.domain.com out of the box. It's very ugly to add all these custom large snippets
@dgregoire
Did u solve the problem in another way?upd:
Found the solutionnginx.ingress.kubernetes.io/configuration-snippet: | add_header Access-Control-Allow-Origin $http_origin; add_header Access-Control-Allow-Methods "POST, GET, OPTIONS"; add_header Access-Control-Allow-Credentials true;
If backend return page with error code, this headers missing, I think, this is better solution:
nginx.ingress.kubernetes.io/enable-cors: "true"
nginx.ingress.kubernetes.io/cors-allow-methods: "PUT, GET, POST, OPTIONS"
nginx.ingress.kubernetes.io/cors-allow-credentials: "true"
nginx.ingress.kubernetes.io/configuration-snippet: |
more_set_headers "Access-Control-Allow-Origin: $http_origin";
I didn't want to open a separate ticket, but I would welcome a solution where I could whitelist what Origin values are Allowed to be reflected back in ACAO.
Eg. I have An API that two web frontends are accessing, but I only want to allow that API to be accessed from those two frontends and nowhere else:
Eg. api.myapp.example.com should reflect the Origin header value only if Origin equals web1.myapp.example.com, or web2.myapp.example.com.
I would even go so far as to allow reflecting all subdomains of a given domain (seconding the request of @ahoulgrave)
Eg.:
nginx-ingress.kubernetes.io/cors-reflect-subdomains: myapp.example.com
Could simply reflect all Origins in ACAO if they are subdomains of myapp.example.com.
I can prepare a PR for this if its something more people would want.
@dgregoire
Did u solve the problem in another way?
upd:
Found the solutionnginx.ingress.kubernetes.io/configuration-snippet: | add_header Access-Control-Allow-Origin $http_origin; add_header Access-Control-Allow-Methods "POST, GET, OPTIONS"; add_header Access-Control-Allow-Credentials true;If backend return page with error code, this headers missing, I think, this is better solution:
nginx.ingress.kubernetes.io/enable-cors: "true" nginx.ingress.kubernetes.io/cors-allow-methods: "PUT, GET, POST, OPTIONS" nginx.ingress.kubernetes.io/cors-allow-credentials: "true" nginx.ingress.kubernetes.io/configuration-snippet: | more_set_headers "Access-Control-Allow-Origin: $http_origin";
I tried a similar configuration, but observed the following with nginx-ingress 0.25.0:
➜ curl -I -X OPTIONS -H "Origin: https://frontend.domain" https://backend.domain
HTTP/2 204
server: openresty/1.15.8.1
date: Tue, 24 Sep 2019 00:04:37 GMT
content-type: text/html
content-length: 0
access-control-allow-origin: *
It seems as though when the nginx.ingress.kubernetes.io/enable-cors: "true" annotation is present, you cannot more_set_headers Access-Control-Allow-Origin on OPTIONS requests. For me it was always overridden to *
@aledbf can we get a response and a possible reopen of this ticket as an improvement based on @reegnz suggestion?
@jeffreybrowning I am sorry, but I am not actively working on this project since the last release (0.26.1). Please check https://github.com/kubernetes/ingress-nginx/issues/4404
Pull requests are always welcome
/reopen
@aledbf: Reopened this issue.
In response to this:
/reopen
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository.
@btsuhako Hi!
You can do like that:
ingress.kubernetes.io/cors-allow-origin: "$http_origin"
@avchu thanks! adding only that annotation seems to get the response we're expecting. the problem is when we add the nginx.ingress.kubernetes.io/enable-cors: "true" annotation, which seems to override every OPTIONS request, and sets the access-control-allow-origin: * header to every response, instead of using the $http_origin
@btsuhako Yes, I know, I had this situation today. But there is no other solution because default of '*' value overrides by cors-allow-origin, and then configuration-snippet became redundant
Issues go stale after 90d of inactivity.
Mark the issue as fresh with /remove-lifecycle stale.
Stale issues rot after an additional 30d of inactivity and eventually close.
If this issue is safe to close now please do so with /close.
Send feedback to sig-testing, kubernetes/test-infra and/or fejta.
/lifecycle stale
@avchu my biggest issue with cors-allow-origin is that it is limited to a single origin. I usually put multiple domains behind ingress-nginx, and I'd prefer a way to provide a list of domains that are allowed. That is only possible if you provide a way to reflect back the Host header of a request, and then whitelist what domains are allowed to be reflected back to the caller.
Right now I have a workaround with http-snippet and location-snippet in the ingress configmap:
http-snippet: |
# CORS start
map $http_origin $allow_origin {
hostnames;
default "";
*.example.com "$http_origin";
*.docker "$http_origin";
*.invalid "$http_origin";
*.localhost "$http_origin";
}
map $allow_origin $cors_allow_credentials {
default "true";
"" "";
}
map $request_method $cors_method {
default "allowed";
"OPTIONS" "preflight";
}
map $cors_method $cors_max_age {
default "";
"preflight" 900;
}
map $cors_method $cors_allow_methods {
default "";
"preflight" "GET, PUT, POST, DELETE, PATCH, OPTIONS";
}
map $cors_method $cors_allow_headers {
default "";
"preflight" "DNT,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization";
}
# CORS end
location-snippet: |
# CORS start
more_set_headers 'Access-Control-Allow-Origin: $allow_origin';
more_set_headers 'Access-Control-Allow-Credentials: $cors_allow_credentials';
more_set_headers 'Access-Control-Allow-Methods: $cors_allow_methods';
more_set_headers 'Access-Control-Allow-Headers: $cors_allow_headers';
more_set_headers 'Access-Control-Max-Age: $cors_max_age';
more_set_headers 'Vary: Origin';
if ($request_method = 'OPTIONS') {
more_set_headers 'Content-Length: 0';
more_set_headers 'Content-Type: text/plain';
return 204;
}
# CORS end
It's based on various solutions for CORS that I've found, but mainly these two:
https://gist.github.com/sbuzonas/6e2dbc1218a0be0d7ae2
https://gist.github.com/huandu/aa8de89ba12a8139f518eedfd07fb1a5
@reegnz Thanks for your example config. Why did you include the '.docker' and '.localhost' in the origin list?
@bastoker that's just in my case the domains I use locally on my dev machine.
On production you'd only include the domains you whitelist for cross-origin requests.
Stale issues rot after 30d of inactivity.
Mark the issue as fresh with /remove-lifecycle rotten.
Rotten issues close after an additional 30d of inactivity.
If this issue is safe to close now please do so with /close.
Send feedback to sig-testing, kubernetes/test-infra and/or fejta.
/lifecycle rotten
Rotten issues close after 30d of inactivity.
Reopen the issue with /reopen.
Mark the issue as fresh with /remove-lifecycle rotten.
Send feedback to sig-testing, kubernetes/test-infra and/or fejta.
/close
@fejta-bot: Closing this issue.
In response to this:
Rotten issues close after 30d of inactivity.
Reopen the issue with/reopen.
Mark the issue as fresh with/remove-lifecycle rotten.Send feedback to sig-testing, kubernetes/test-infra and/or fejta.
/close
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository.
Most helpful comment
I didn't want to open a separate ticket, but I would welcome a solution where I could whitelist what Origin values are Allowed to be reflected back in ACAO.
Eg. I have An API that two web frontends are accessing, but I only want to allow that API to be accessed from those two frontends and nowhere else:
Eg. api.myapp.example.com should reflect the Origin header value only if Origin equals web1.myapp.example.com, or web2.myapp.example.com.
I would even go so far as to allow reflecting all subdomains of a given domain (seconding the request of @ahoulgrave)
Eg.:
Could simply reflect all Origins in ACAO if they are subdomains of myapp.example.com.
I can prepare a PR for this if its something more people would want.