Ingress-nginx: Feature Request: multi-origin support for cors-allow-origin

Created on 4 May 2020  路  8Comments  路  Source: kubernetes/ingress-nginx

Feature Request

_In a world_ of a single API used by multiple SPAs .... 馃審
It would be really helpful to be able to specify a list of origins/domains/subdomains in the nginx.ingress.kubernetes.io/cors-allow-origin annotation. Especially for subdomains serving media: media1.site.com, media2.site.com, media3.site.com

Intriguingly, this case was put forward in the initial feature request, but looks like it got reduced to an MVP of a single domain? But since the initial merge the thread has continued with many code blocks of how-to config snippet hacks to enable the support of multiple domain handling. This of course gets very messy - especially when having to apply to each microservice's ingress definition.

Linked Issues

Initial Feature Request: https://github.com/kubernetes/ingress-nginx/issues/1171

Prior Art?

/kind feature

kinfeature

Most helpful comment

This would be really good!
Currently blocked and having to look into writing a snippet 馃憥

Support for wildcard subdomains would be really nice:

nginx.ingress.kubernetes.io/cors-allow-origin: "https://*.domain.com"

because "https://app1.domain.com", "https://app2.domain.com", "https://app3.domain.com" all needing to call "https://api.domain.com" is a common need.

All 8 comments

As it currently stands, if you attempt to specify a comma-separated list of allowed origins in the nginx.ingress.kubernetes.io/cors-allow-origin annotation, it won't validate and will therefore fall back to the default of *.

This may give the false impression that the list is actually being obeyed, since all listed origins will work... but so will all other origins, since it's ending up as Access-Control-Allow-Origin: *.

Having this feature would be great, we are also struggling to do it. As a workaround, we are using configuration snippet with custom nginx config which is working but still an ugly solution.

Here's my ugly configuration snippet to work around:

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: foo
  annotations:
    kubernetes.io/ingress.class: "nginx"
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
    nginx.ingress.kubernetes.io/configuration-snippet: |
      if ($http_origin ~* "^https?://((?:www\.exactmatch\.com)|(?:.*\.regexmatch\.com))$") {
        set $cors "true";
      }
      if ($request_method = 'OPTIONS') {
        set $cors "${cors}options";
      }

      if ($cors = "true") {
        add_header 'Access-Control-Allow-Origin' "$http_origin" always;
        add_header 'Access-Control-Allow-Methods' 'GET, PUT, POST, DELETE, PATCH, OPTIONS' always;
        add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization' always;
        add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always;
      }

      if ($cors = "trueoptions") {
        add_header 'Access-Control-Allow-Origin' "$http_origin";
        add_header 'Access-Control-Allow-Methods' 'GET, PUT, POST, DELETE, PATCH, OPTIONS';
        add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
        add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
        add_header 'Access-Control-Max-Age' 1728000;
        add_header 'Content-Type' 'text/plain charset=UTF-8';
        add_header 'Content-Length' 0;
        return 204;
      }

Here's my ugly configuration snippet to work around:

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: foo
  annotations:
    kubernetes.io/ingress.class: "nginx"
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
    nginx.ingress.kubernetes.io/configuration-snippet: |
      if ($http_origin ~* "^https?://((?:www\.exactmatch\.com)|(?:.*\.regexmatch\.com))$") {
        set $cors "true";
      }
      if ($request_method = 'OPTIONS') {
        set $cors "${cors}options";
      }

      if ($cors = "true") {
        add_header 'Access-Control-Allow-Origin' "$http_origin" always;
        add_header 'Access-Control-Allow-Methods' 'GET, PUT, POST, DELETE, PATCH, OPTIONS' always;
        add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization' always;
        add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always;
      }

      if ($cors = "trueoptions") {
        add_header 'Access-Control-Allow-Origin' "$http_origin";
        add_header 'Access-Control-Allow-Methods' 'GET, PUT, POST, DELETE, PATCH, OPTIONS';
        add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
        add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
        add_header 'Access-Control-Max-Age' 1728000;
        add_header 'Content-Type' 'text/plain charset=UTF-8';
        add_header 'Content-Length' 0;
        return 204;
      }

What is the expected behavior in this case if the $http_origin is not on whitelist ?

No headers added, which means no CORS policy so all CORS requests blocked by the browser.

Hi all
Here's my configuration snippet to don't work, where is the problem?

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/rewrite-target: /
    nginx.ingress.kubernetes.io/cors-allow-credentials: "true"
    nginx.ingress.kubernetes.io/enable-access-log: "true"
    nginx.ingress.kubernetes.io/enable-rewrite-log: "true"
    nginx.ingress.kubernetes.io/proxy-body-size: 100m
    ingress.kubernetes.io/force-ssl-redirect: "true"
    nginx.ingress.kubernetes.io/configuration-snippet: |
      if ($http_origin ~* "^https?://((?:ui|uia)\.stand01\.example\.com)$") {
        set $cors "true";
      }
      if ($cors = "true") {
        add_header 'Access-Control-Allow-Origin' "$http_origin";
        add_header 'Access-Control-Allow-Methods' 'GET, PUT, POST, DELETE, PATCH, OPTIONS';
        add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
        add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
      }
  name: ui-https-cors-ing
spec:
  tls:
  - hosts: 
    - ui.stand01.example.com
    secretName: stand01-06-example-com-crt-fullchain
  rules:
  - host: ui.stand01.example.com
    http:
      paths:
      - backend:
          serviceName: ui-svc
          servicePort: 8080
        path: /

This would be really good!
Currently blocked and having to look into writing a snippet 馃憥

Support for wildcard subdomains would be really nice:

nginx.ingress.kubernetes.io/cors-allow-origin: "https://*.domain.com"

because "https://app1.domain.com", "https://app2.domain.com", "https://app3.domain.com" all needing to call "https://api.domain.com" is a common need.

Hello Guys,
I am facing Multiple "Access control allow origin" issue while I am using the below mentioned configuration snippet in k8s annotations: -

annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/configuration-snippet: |
if ($http_origin ~* ((https?:\/\/(.+.)*(domain1|domain2).(?:net|com)$)) {
set $cors "true";
}

  # Determine the HTTP request method used
  if ($request_method = 'OPTIONS') {
      set $cors "${cors}options";
  }

  if ($request_method = 'GET') {
      set $cors "${cors}get";
  }

  if ($request_method = 'POST') {
      set $cors "${cors}post";
  }

  if ($cors = "true") {
      # Catch all incase there's a request method we're not dealing with properly
      add_header 'Access-Control-Allow-Origin' "$http_origin";
  }
  if ($cors = "trueget") {
      add_header 'Access-Control-Allow-Origin' "$http_origin";
      add_header 'Access-Control-Allow-Credentials' 'true';
      add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
      add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
  }
  if ($cors = "trueoptions") {
      add_header 'Access-Control-Allow-Origin' "$http_origin";
      #
      # Om nom nom cookies
      #
      add_header 'Access-Control-Allow-Credentials' 'true';
      add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
      #
      # Custom headers and headers various browsers *should* be OK with but aren't
      #
      add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
      #
      # Tell client that this pre-flight info is valid for 20 days
      #
      add_header 'Access-Control-Max-Age' 1728000;
      add_header 'Content-Type' 'text/plain charset=UTF-8';
      add_header 'Content-Length' 0;
      return 204;
  }
  if ($cors = "truepost") {
      add_header 'Access-Control-Allow-Origin' "$http_origin";
      add_header 'Access-Control-Allow-Credentials' 'true';
      add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
      add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
  }

Please find the attached error: -
image

Please suggest where am I doing wrong.

Was this page helpful?
0 / 5 - 0 ratings