Ingress 默认后端是基本身份验证返回 401 而不是 404

时间:2021-04-19 07:27:32

标签: kubernetes kubernetes-ingress

我已将 ingress-nginx helm chart ( 3.20.1 , https://github.com/kubernetes/ingress-nginx/tree/master/charts/ingress-nginx ) 部署到 k8s 集群中。

为应用程序配置的一些 Ingress 使用基本身份验证 - 它按预期工作。 IE。我可以在没有基本身份验证的情况下访问集群中的一些应用程序(如配置) 并且某些应用程序需要专用的基本身份验证凭据(如配置)。

但是尝试一个未知/不受支持的 URL/路径在默认后端处理很尴尬。 不知何故,默认后端现在也需要基本身份验证(作为 basic-auth 的入口之一)?

我如何才能找出为什么/在不应该进行此基本身份验证的地方? 我确实希望默认后端在没有基本身份验证的情况下为 404 提供错误页面!

$ kubectl -n ingress get svc
NAME                                 TYPE           CLUSTER-IP     EXTERNAL-IP     PORT(S)                      AGE
ingress-nginx-controller             LoadBalancer   10.0.235.5     xx.yy.zzz.zzz   80:31294/TCP,443:31732/TCP   39d
ingress-nginx-controller-admission   ClusterIP      10.0.190.204   <none>          443/TCP                      39d
ingress-nginx-controller-metrics     ClusterIP      10.0.21.184    <none>          9913/TCP                     12d
ingress-nginx-defaultbackend         ClusterIP      10.0.109.195   <none>          80/TCP                       39d

当前部署的 Ingress:

$ kubectl get ingress -A
Warning: extensions/v1beta1 Ingress is deprecated in v1.14+, unavailable in v1.22+; use networking.k8s.io/v1 Ingress
NAMESPACE       NAME                                      CLASS    HOSTS                ADDRESS         PORTS     AGE
dev-app-a       app-a                                     <none>   my-host.com          xx.yy.zzz.zzz   80, 443   46d
dev-jaeger      jaeger                                    <none>   my-host.com          xx.yy.zzz.zzz   80, 443   47d
dev-app-b       app-b                                     <none>   my-host.com          xx.yy.zzz.zzz   80, 443   17d
dev-app-c       app-c                                     <none>   my-host.com          xx.yy.zzz.zzz   80, 443   12d
dev-app-d       app-d                                     <none>   my-host.com          xx.yy.zzz.zzz   80, 443   4d22h
prom            prometheus-grafana                        <none>   my-other-host.com    xx.yy.zzz.zzz   80, 443   20d
prom            prometheus-kube-prometheus-alertmanager   <none>   my-other-host.com    xx.yy.zzz.zzz   80, 443   20d
prom            prometheus-kube-prometheus-prometheus     <none>   my-other-host.com    xx.yy.zzz.zzz   80, 443   20d
stage-app-a     app-a                                     <none>   my-third-host.com    xx.yy.zzz.zzz   80, 443   39d
stage-jaeger    jaeger                                    <none>   my-third-host.com    xx.yy.zzz.zzz   80, 443   39d

入口详细信息:

apiVersion: v1
items:
- apiVersion: extensions/v1beta1
  kind: Ingress
  metadata:
    annotations:
      cert-manager.io/cluster-issuer: letsencrypt-prod
      kubernetes.io/ingress.class: nginx
      nginx.ingress.kubernetes.io/enable-cors: "false"
      nginx.ingress.kubernetes.io/proxy-buffering: "off"
    labels:
      app.kubernetes.io/name: app-a
    name: app-a
    namespace: foo-app-a
  spec:
    rules:
    - host: my-host.com
      http:
        paths:
        - backend:
            serviceName: app-a-http
            servicePort: http
          path: /abc/
          pathType: ImplementationSpecific
    tls:
    - hosts:
      - my-host.com
      secretName: app-a-tls
  status:
    loadBalancer:
      ingress:
      - ip: xx.xx.xx.xx
- apiVersion: extensions/v1beta1
  kind: Ingress
  metadata:
    annotations:
      cert-manager.io/cluster-issuer: letsencrypt-prod
      kubernetes.io/ingress.class: nginx
      nginx.ingress.kubernetes.io/add-base-url: "true"
      nginx.ingress.kubernetes.io/auth-realm: Authentication Required - Jaeger UI
      nginx.ingress.kubernetes.io/auth-secret: jaeger-basic-auth
      nginx.ingress.kubernetes.io/auth-type: basic
      nginx.ingress.kubernetes.io/enable-cors: "false"
      nginx.ingress.kubernetes.io/from-to-www-redirect: "true"
      nginx.ingress.kubernetes.io/proxy-buffering: "off"
    labels:
      app.kubernetes.io/name: jaeger
    name: jaeger
    namespace: dev-jaeger
  spec:
    rules:
    - host: my-host.com
      http:
        paths:
        - backend:
            serviceName: jaeger
            servicePort: http-ui
          path: /jaeger/
          pathType: ImplementationSpecific
    tls:
    - hosts:
      - my-host.com
      secretName: jaeger-tls
  status:
    loadBalancer:
      ingress:
      - ip: xx.xx.xx.xx
- apiVersion: extensions/v1beta1
  kind: Ingress
  metadata:
    annotations:
      cert-manager.io/cluster-issuer: letsencrypt-prod
      kubernetes.io/ingress.class: nginx
      nginx.ingress.kubernetes.io/enable-cors: "false"
      nginx.ingress.kubernetes.io/proxy-buffering: "off"
      nginx.ingress.kubernetes.io/rewrite-target: /$1
    labels:
      app.kubernetes.io/name: app-b
    name: app-b
    namespace: dev-app-b
  spec:
    rules:
    - host: my-host.com
      http:
        paths:
        - backend:
            serviceName: app-b
            servicePort: http
          path: /app-b/(.*)
          pathType: ImplementationSpecific
    tls:
    - hosts:
      - my-host.com
      secretName: app-b-tls
  status:
    loadBalancer:
      ingress:
      - ip: xx.xx.xx.xx
- apiVersion: extensions/v1beta1
  kind: Ingress
  metadata:
    annotations:
      cert-manager.io/cluster-issuer: letsencrypt-prod
      kubernetes.io/ingress.class: nginx
      nginx.ingress.kubernetes.io/enable-cors: "false"
      nginx.ingress.kubernetes.io/proxy-buffering: "off"
      nginx.ingress.kubernetes.io/rewrite-target: /$1
    labels:
      app.kubernetes.io/name: app-c
    name: app-c
    namespace: dev-app-c
  spec:
    rules:
    - host: my-host.com
      http:
        paths:
        - backend:
            serviceName: app-c
            servicePort: http
          path: /app-c/(.*)
          pathType: ImplementationSpecific
    tls:
    - hosts:
      - my-host.com
      secretName: app-c-tls
  status:
    loadBalancer:
      ingress:
      - ip: xx.xx.xx.xx
- apiVersion: extensions/v1beta1
  kind: Ingress
  metadata:
    annotations:
      kubernetes.io/ingress.class: nginx
      meta.helm.sh/release-name: prometheus
      meta.helm.sh/release-namespace: prom
      nginx.ingress.kubernetes.io/add-base-url: "true"
      nginx.ingress.kubernetes.io/auth-realm: Authentication Required - Grafana UI
      nginx.ingress.kubernetes.io/auth-secret: monitoring-basic-auth
      nginx.ingress.kubernetes.io/auth-type: basic
      nginx.ingress.kubernetes.io/enable-cors: "false"
      nginx.ingress.kubernetes.io/from-to-www-redirect: "true"
      nginx.ingress.kubernetes.io/proxy-buffering: "off"
    labels:
      app.kubernetes.io/instance: prometheus
      app.kubernetes.io/managed-by: Helm
      app.kubernetes.io/name: grafana
      app.kubernetes.io/version: 7.4.2
      helm.sh/chart: grafana-6.4.8
    name: prometheus-grafana
    namespace: prom
  spec:
    rules:
    - host: my-other-host.com
      http:
        paths:
        - backend:
            serviceName: prometheus-grafana
            servicePort: 80
          path: /monitoring/grafana/
          pathType: ImplementationSpecific
    tls:
    - hosts:
      - my-other-host.com
      secretName: prometheus-general-tls
  status:
    loadBalancer:
      ingress:
      - ip: xx.xx.xx.xx
- apiVersion: extensions/v1beta1
  kind: Ingress
  metadata:
    annotations:
      kubernetes.io/ingress.class: nginx
      meta.helm.sh/release-name: prometheus
      meta.helm.sh/release-namespace: prom
      nginx.ingress.kubernetes.io/auth-realm: Authentication Required - AlertManager UI
      nginx.ingress.kubernetes.io/auth-secret: monitoring-basic-auth
      nginx.ingress.kubernetes.io/auth-type: basic
    labels:
      app: kube-prometheus-stack-alertmanager
      app.kubernetes.io/managed-by: Helm
      chart: kube-prometheus-stack-14.0.1
      heritage: Helm
      release: prometheus
    name: prometheus-kube-prometheus-alertmanager
    namespace: prom
  spec:
    rules:
    - host: my-other-host.com
      http:
        paths:
        - backend:
            serviceName: prometheus-kube-prometheus-alertmanager
            servicePort: 9093
          path: /monitoring/alertmanager/
          pathType: ImplementationSpecific
    tls:
    - hosts:
      - my-other-host.com
      secretName: prometheus-general-tls
  status:
    loadBalancer:
      ingress:
      - ip: xx.xx.xx.xx
- apiVersion: extensions/v1beta1
  kind: Ingress
  metadata:
    annotations:
      cert-manager.io/cluster-issuer: letsencrypt-prod
      kubernetes.io/ingress.class: nginx
      meta.helm.sh/release-name: prometheus
      meta.helm.sh/release-namespace: prom
      nginx.ingress.kubernetes.io/auth-realm: Authentication Required - Prometheus UI
      nginx.ingress.kubernetes.io/auth-secret: monitoring-basic-auth
      nginx.ingress.kubernetes.io/auth-type: basic
    labels:
      app: kube-prometheus-stack-prometheus
      app.kubernetes.io/managed-by: Helm
      chart: kube-prometheus-stack-14.0.1
      heritage: Helm
      release: prometheus
    name: prometheus-kube-prometheus-prometheus
    namespace: prom
  spec:
    rules:
    - host: my-other-host.com
      http:
        paths:
        - backend:
            serviceName: prometheus-kube-prometheus-prometheus
            servicePort: 9090
          path: /monitoring/prometheus/
          pathType: ImplementationSpecific
    tls:
    - hosts:
      - my-other-host.com
      secretName: prometheus-general-tls
  status:
    loadBalancer:
      ingress:
      - ip: xx.xx.xx.xx
- apiVersion: extensions/v1beta1
  kind: Ingress
  metadata:
    annotations:
      cert-manager.io/cluster-issuer: letsencrypt-prod
      kubernetes.io/ingress.class: nginx
      nginx.ingress.kubernetes.io/enable-cors: "false"
      nginx.ingress.kubernetes.io/proxy-buffering: "off"
    labels:
      app.kubernetes.io/managed-by: terraform
      app.kubernetes.io/name: app-a
    name: app-a
    namespace: stage-app-a
  spec:
    rules:
    - host: my-third-host.com
      http:
        paths:
        - backend:
            serviceName: app-a-http
            servicePort: http
          path: /controller/
          pathType: ImplementationSpecific
    tls:
    - hosts:
      - my-third-host.com
      secretName: app-a-tls
  status:
    loadBalancer:
      ingress:
      - ip: xx.xx.xx.xx
- apiVersion: extensions/v1beta1
  kind: Ingress
  metadata:
    annotations:
      cert-manager.io/cluster-issuer: letsencrypt-prod
      kubernetes.io/ingress.class: nginx
      nginx.ingress.kubernetes.io/add-base-url: "true"
      nginx.ingress.kubernetes.io/auth-realm: Authentication Required - Jaeger UI
      nginx.ingress.kubernetes.io/auth-secret: jaeger-basic-auth
      nginx.ingress.kubernetes.io/auth-type: basic
      nginx.ingress.kubernetes.io/enable-cors: "false"
      nginx.ingress.kubernetes.io/from-to-www-redirect: "true"
      nginx.ingress.kubernetes.io/proxy-buffering: "off"
    labels:
      app.kubernetes.io/name: jaeger
    name: jaeger
    namespace: stage-jaeger
  spec:
    rules:
    - host: my-third-host.com
      http:
        paths:
        - backend:
            serviceName: jaeger
            servicePort: http-ui
          path: /jaeger/
          pathType: ImplementationSpecific
    tls:
    - hosts:
      - my-third-host.com
      secretName: jaeger-tls
  status:
    loadBalancer:
      ingress:
      - ip: xx.xx.xx.xx

例如在未知路径上尝试一个简单的 curl(我希望默认后端给出 404 响应)返回来自我的 Prometheus 端点的数据,这些数据受基本身份验证保护:

(真实的主机名/ip 已经被我混淆了!)

$ curl -v "https://my-other-host.com/bar"
*   Trying xx.xx.xx.xx...
* TCP_NODELAY set
* Connected to my-other-host.com (xx.xx.xx.xx) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/cert.pem
  CApath: none
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
* ALPN, server accepted to use h2
* Server certificate:
*  subject: CN=my-other-host.com
*  start date: Apr  6 14:28:20 2021 GMT
*  expire date: Jul  5 14:28:20 2021 GMT
*  subjectAltName: host "my-other-host.com" matched cert's "my-other-host.com"
*  issuer: C=US; O=Let's Encrypt; CN=R3
*  SSL certificate verify ok.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x7fec1300d600)
> GET /bar HTTP/2
> Host: my-other-host.com
> User-Agent: curl/7.64.1
> Accept: */*
>
* Connection state changed (MAX_CONCURRENT_STREAMS == 128)!
< HTTP/2 401
< date: Wed, 21 Apr 2021 15:37:24 GMT
< content-type: text/html
< content-length: 172
< www-authenticate: Basic realm="Authentication Required - Prometheus UI"
< strict-transport-security: max-age=15724800; includeSubDomains
<
<html>
<head><title>401 Authorization Required</title></head>
<body>
<center><h1>401 Authorization Required</h1></center>
<hr><center>nginx</center>
</body>
</html>
* Connection #0 to host my-other-host.com left intact
* Closing connection 0

或类似的,当在另一台主机上尝试时,我会从看起来像我的 Jaeger 端点而不是默认后端 404 的东西中得到 401:

$ curl -v "https://my-host.com/foo"
*   Trying xx.xx.xx.xx...
* TCP_NODELAY set
* Connected to my-host.com (xx.xx.xx.xx) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/cert.pem
  CApath: none
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
* ALPN, server accepted to use h2
* Server certificate:
*  subject: CN=my-host.com
*  start date: Mar 18 06:37:40 2021 GMT
*  expire date: Jun 16 06:37:40 2021 GMT
*  subjectAltName: host "my-host.com" matched cert's "my-host.com"
*  issuer: C=US; O=Let's Encrypt; CN=R3
*  SSL certificate verify ok.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x7f968480d600)
> GET /foo HTTP/2
> Host: my-host.com
> User-Agent: curl/7.64.1
> Accept: */*
> 
* Connection state changed (MAX_CONCURRENT_STREAMS == 128)!
< HTTP/2 401 
< date: Wed, 21 Apr 2021 15:59:21 GMT
< content-type: text/html
< content-length: 172
< www-authenticate: Basic realm="Authentication Required - Jaeger UI"
< strict-transport-security: max-age=15724800; includeSubDomains
< 
<html>
<head><title>401 Authorization Required</title></head>
<body>
<center><h1>401 Authorization Required</h1></center>
<hr><center>nginx</center>
</body>
</html>
* Connection #0 to host my-host.com left intact
* Closing connection 0

1 个答案:

答案 0 :(得分:1)

通过为集群中提供服务的每个主机显式添加 Ingress 路由来修复(或解决该问题):

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: nginx
  name: default-route-per-host
  namespace: ingress
spec:
  rules:
  - host: my-host.com
    http:
      paths:
      - backend:
          service:
            name: ingress-nginx-defaultbackend
            port:
              name: http
        path: /
        pathType: Prefix
  - host: my-other-host.com
    http:
      paths:
      - backend:
          service:
            name: ingress-nginx-defaultbackend
            port:
              name: http
        path: /
        pathType: Prefix
  - host: my-third-host.com
    http:
      paths:
      - backend:
          service:
            name: ingress-nginx-defaultbackend
            port:
              name: http
        path: /
        pathType: Prefix