使用 oauth 代理和 CORS 的 Nginx 入口

Nginx ingress with oauth proxy and CORS

我在 Kubernetes 中有两个服务通过 nginx 控制器公开。服务 a 想要调用域 b 上的内容,但同时两个服务都需要使用 oauth-proxy 服务通过 Google 进行身份验证。

所以我成功启用了 CORS,并且 a 可以毫无问题地调用 b。但问题是当我也包含身份验证时,我不断得到:

Access to manifest at 'https://accounts.google.com/o/oauth2/auth?access_type=offline&approval_prompt=force&client_id=<obscured>.apps.googleusercontent.com&redirect_uri=https%3A%2F%2Fa.example.com%2Foauth2%2Fcallback&response_type=code&scope=profile+email&state=<obscured>manifest.json' (redirected from 'https://a.example.com/manifest.json') from origin 'https://a.example.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

入口如下:

服务一

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: nginx
    kubernetes.io/tls-acme: "true"
    nginx.ingress.kubernetes.io/auth-url: "https://$host/oauth2/auth"
    nginx.ingress.kubernetes.io/auth-signin: "https://$host/oauth2/start?rd=$escaped_request_uri"
    nginx.ingress.kubernetes.io/whitelist-source-range: 0.0.0.0/0
  name: a
spec:
  rules:
  - host: a.example.com
    http:
      paths:
      - backend:
          service:
            name: a-svc
            port:
              number: 8080
        path: /
        pathType: Prefix
  tls:
  - hosts:
    - a.example.com
    secretName: a-tls

---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/whitelist-source-range: 0.0.0.0/0
  labels:
    k8s-app: oauth2-proxy
  name: a-oauth
spec:
  rules:
  - host: a.example.com
    http:
      paths:
      - backend:
          service:
            name: oauth2-proxy
            port:
              number: 4180
        path: /oauth2
        pathType: Prefix
  tls:
  - hosts:
      - a.example.com
    secretName: a-oauth-tls

服务b

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: nginx
    kubernetes.io/tls-acme: "true"
    nginx.ingress.kubernetes.io/auth-url: "https://$host/oauth2/auth"
    nginx.ingress.kubernetes.io/auth-signin: "https://$host/oauth2/start?rd=$escaped_request_uri"
    nginx.ingress.kubernetes.io/enable-cors: "true"
    nginx.ingress.kubernetes.io/whitelist-source-range: 0.0.0.0/0
  name: b
spec:
  rules:
  - host: b.example.com
    http:
      paths:
      - backend:
          service:
            name: b-svc
            port:
              number: 8080
        path: /
        pathType: Prefix
  tls:
  - hosts:
    - b.example.com
    secretName: b-tls

---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/enable-cors: "true"
    nginx.ingress.kubernetes.io/auth-url: "https://$host/oauth2/auth"
    nginx.ingress.kubernetes.io/auth-signin: "https://$host/oauth2/start?rd=$escaped_request_uri"
    nginx.ingress.kubernetes.io/whitelist-source-range: 0.0.0.0/0
  labels:
    k8s-app: oauth2-proxy
  name: b-oauth
spec:
  rules:
  - host: b.example.com
    http:
      paths:
      - backend:
          service:
            name: oauth2-proxy
            port:
              number: 4180
        path: /oauth2
        pathType: Prefix
  tls:
  - hosts:
      - b.example.com
    secretName: b-oauth-tls

显然,这两者之间只有一个区别,那就是服务 b 入口中的 cors 注释 nginx.ingress.kubernetes.io/enable-cors: "true"

我不确定是什么导致了这个问题,但我猜测在服务 a 中针对 Google 完成的身份验证没有传递给 CORS 请求,因此服务 b 也可以使用相同的 token/credentials.

进行身份验证

我做错了什么,我该如何解决?

根据文档,您似乎缺少使用 HTTP 的注释。

尝试在服务配置文件中添加这样的片段:

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";

但这可能是 CORS 的问题。在这种情况下,您应该添加以下行:

--cors-allowed-origins=["http://*"]

/etc/default/kube-apiserver/etc/kubernetes/manifests/kube-apiserver.yaml 文件(取决于你的kube-apiserver配置文件的位置)。

之后重启 kube-apiserver。

另见 this similar question

所以,事实证明整个 Kubernetes 和 Nginx 配置是正确的,所以解决方案是在调用第二个服务的 CORS 请求时在客户端实现保存的 cookie 的使用。

基本上,这里已经回答了这个问题:

答案摘录:

Front-end (client): Set the XMLHttpRequest.withCredentials flag to true, this can be achieved in different ways depending on the request-response library used:

  • jQuery 1.5.1 xhrFields: {withCredentials: true}
  • ES6 fetch() credentials: 'include'
  • axios: withCredentials: true