【问题标题】:Basic Auth doesn't work in kubernetes ingress基本身份验证在 kubernetes 入口中不起作用
【发布时间】:2020-05-08 21:29:03
【问题描述】:

我在 kubernetes 集群中创建了 pypiserver,我使用了https://hub.docker.com/r/pypiserver/pypiserver docker 镜像。我需要为我创建的服务器创建基本身份验证。我用这个方法https://kubernetes.github.io/ingress-nginx/examples/auth/basic/

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: pypiserver
  labels:
    app: pypiserver
  annotations:
    kubernetes.io/ingress.class: nginx
    kubernetes.io/tls-acme: 'true'
    ingress.kubernetes.io/auth-type: basic
    ingress.kubernetes.io/auth-secret: secret
    ingress.kubernetes.io/auth-realm: "Authentication Required - ok"
spec:
  rules:
  - host: example.com
    http:
      paths:
      - path: /
        backend:
          serviceName: pypiservice
          servicePort: 8080
  tls:
  - hosts:
    - example.com
    secretName: secret-tls

但是我的主机名是“www.example.com/8080”,我没有看到 ingress 在 kubernetes 集群中有任何 pod。 Ingress 运行良好,但我没有获得此主机的身份验证。 (而且我还有 http://IP adress:8080 我通过 cloudflare 转换为域)

请让我知道我做错了什么?

【问题讨论】:

  • 我已经复制了您的案例,看起来 nginx 入口控制器中的 basic auth 确实存在一些问题(至少在某些版本中)。我在 github github.com/kubernetes/ingress-nginx/issues/3480 上发现了一些类似的问题,如果我设法让它工作(我目前正在我的 GKE 集群上测试它),我会告诉你并分享我的解决方案。

标签: kubernetes-ingress pypiserver


【解决方案1】:

我不确切知道您的 nginx 入口控制器 版本是什么,但我可以分享什么对我有用。我已经在我的 GKE 集群上复制了它。

我按照this 指南安装了我的 nginx 入口控制器。基本上它归结为运行以下命令:

如果您使用 GKE,则需要将您的用户初始化为 cluster-admin 使用以下命令:

kubectl create clusterrolebinding cluster-admin-binding \
  --clusterrole cluster-admin \
  --user $(gcloud config get-value account)

所有部署都需要以下强制命令。

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.27.1/deploy/static/mandatory.yaml

我在我的 GKE 上使用 1.13 版本,所以这个技巧也适用于我的案例:

提示

如果您使用的是 1.14 之前的 Kubernetes 版本,则需要 在第 217 行将 kubernetes.io/os 更改为 beta.kubernetes.io/os mandatory.yaml,请参阅标签详细信息。

但我的处理方式完全不同。基本上你需要你的Nodeskubernetes.io/os=linux 标签,这样你就可以简单地给它们贴上标签。以下命令将完成这项工作:

kubectl label node --all kubernetes.io/os=linux

然后我们前往Provider Specific Steps,如果是GKE,则归结为应用以下yaml

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.27.1/deploy/static/provider/cloud-generic.yaml

那么你可能想verify你的安装:

要检查入口控制器 pod 是否已启动,请运行 以下命令:

kubectl get pods --all-namespaces -l app.kubernetes.io/name=ingress-nginx --watch

或者直接运行:

kubectl get all -n ingress-nginx

它还会告诉您是否正确部署了所有必需的资源。

接下来我们需要编写包含basic-auth相关annotations的入口(入口对象/资源)。如您的问题所述,我正在关注same tutorial

首先我们需要创建包含username 和散列passwordauth 文件:

$ htpasswd -c auth foo
New password: <bar>
New password:
Re-type new password:
Adding password for user foo

一旦我们有了它,我们需要创建一个Secret 对象,然后我们将在我们的入口中使用它:

$ kubectl create secret generic basic-auth --from-file=auth
secret "basic-auth" created

创建后,我们可以检查一切是否顺利:

$ kubectl get secret basic-auth -o yaml
apiVersion: v1
data:
  auth: Zm9vOiRhcHIxJE9GRzNYeWJwJGNrTDBGSERBa29YWUlsSDkuY3lzVDAK
kind: Secret
metadata:
  name: basic-auth
  namespace: default
type: Opaque

好的,到目前为止一切顺利......

然后我们需要创建我们的ingress resource/object

我的ingress-with-auth.yaml 文件看起来与the instruction 中的文件略有不同,即我刚刚添加了kubernetes.io/ingress.class: nginx 以确保使用我的nginx 入口控制器 而不是内置的GKE 解决方案:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: ingress-with-auth
  annotations:
    kubernetes.io/ingress.class: nginx
    # type of authentication
    nginx.ingress.kubernetes.io/auth-type: basic
    # name of the secret that contains the user/password definitions
    nginx.ingress.kubernetes.io/auth-secret: basic-auth
    # message to display with an appropriate context why the authentication is required
    nginx.ingress.kubernetes.io/auth-realm: 'Authentication Required - foo'
spec:
  rules:
  - host: foo.bar.com
    http:
      paths:
      - path: /
        backend:
          serviceName: pypiserver
          servicePort: 80

在您的示例中,您可能需要在 basic-auth 相关注释中添加 nginx 前缀:

ingress.kubernetes.io/auth-type: basic
ingress.kubernetes.io/auth-secret: secret
ingress.kubernetes.io/auth-realm: "Authentication Required - ok"

所以它看起来像这样:

nginx.ingress.kubernetes.io/auth-type: basic
nginx.ingress.kubernetes.io/auth-secret: secret
nginx.ingress.kubernetes.io/auth-realm: "Authentication Required - ok"

首先我使用了我的入口资源中列出的地址(在我的ingress 定义中添加kubernetes.io/ingress.class: nginx 注释后,它就不再出现在那里:

$ kubectl get ingress 
NAME                HOSTS         ADDRESS   PORTS   AGE
ingress-with-auth   foo.bar.com             80      117m

当我尝试使用此 IP 访问 pypi-server 时,它直接将我带到该页面,无需任何身份验证。但看起来如果您没有定义正确的入口类,则使用默认值,因此在实践中您的 ingress 定义与 auth-basic 细节没有被考虑在内,也不会传递给 nginx 入口控制器我们在前面的步骤之一中安装。

那么应该使用什么 IP 地址来访问您的应用程序?运行以下命令,这将显示您的 nginx 入口控制器CLUSTER-IP(可以在您的集群中从任何PodNode 访问)和EXTERNAL-IP

$ kubectl get service --namespace ingress-nginx 
NAME            TYPE           CLUSTER-IP   EXTERNAL-IP     PORT(S)                      AGE
ingress-nginx   LoadBalancer   10.0.3.220   35.111.112.113   80:30452/TCP,443:30006/TCP   18h

您基本上可以在集群中托管许多不同的网站,并且所有这些网站都可以通过此 IP 访问。所有这些都可以在默认的http 80 端口(或https 443 在您的情况下)上可用。它们之间的唯一区别是您在http requesthttp 标头中传递的hostname

由于我没有指向此外部 IP 地址的域,并且无法通过转到 http://foo.bar.com 来简单地访问我的网站,因此我需要以某种方式传递 hostname 我从 35.111.112.113 地址请求的地址。可以通过以下几种方式完成:

我在我的 Google Chrome 浏览器中安装了 ModHeader 扩展程序,它允许我修改我的 http 请求标头并将 hostname I'm requestig 设置为我想要的任何值。

您也可以使用curl 执行此操作,如下所示:

curl -v http://35.111.112.113 -H 'Host: foo.bar.com' -u 'foo:bar'

系统会提示您进行身份验证。

如果你不提供-u username:password 标志,你应该得到401 Authorization Required

基本上就是这样。

如果对你有帮助,请告诉我。如果不完全清楚,请随时提出其他问题。

还有一件事。如果仍然无法正常工作,您可以从附加到您的 nginx 入口控制器 Pod 开始(首先通过运行kubectl get pods -n ingress-nginx 检查您的Pod 名称):

kubectl exec -ti -n ingress-nginx nginx-ingress-controller-pod /bin/bash

并检查您的/etc/nginx/nginx.conf 文件的内容。寻找foo.bar.com(或者在你的情况下example.com)。它应该包含类似的行:

auth_basic "Authentication Required - foo";
            auth_basic_user_file /etc/ingress-controller/auth/default-ingress-with-auth.passwd;

然后检查文件是否存在于指定位置/etc/ingress-controller/auth/default-ingress-with-auth.passwd

对您的 Service 定义的注释。 pypiserver 容器专门暴露了 8080 端口这一事实并不意味着您在通过入口访问它时需要使用该端口。在Service 定义中,Container 暴露的端口称为targetPort。您需要在定义 Service 时指定它,但 Service 本身可以公开完全不同的端口。我使用以下命令定义了我的Service

kubectl expose deployment pypiserver --type=LoadBalancer --port=80 --target-port=8080

请注意,type 应设置为 NodePortLoadBalancer。然后在您的入口定义中,您不必使用8080,而是使用80,这是您的pypiserverService 公开的端口。请注意,我的ingress object/resource 定义中有servicePort: 80。您在 cloudflare 中的 example.com 域应该使用它的 A record 指向您的 nginx ingress controller LoadBalancer Service IP (kubectl get svc -n ingress-nginx),而不指定任何端口。

【讨论】:

  • 在我的/etc/nginx/nginx.conf 中,我的服务器定义中没有基本的身份验证相关配置。但是当使用kubectl describe ingress -A 进行验证时,所有注释都是正确的(nginx.ingress.kubernetes.io/*)。这是否与相同的问题(没有基本身份验证但会产生 503 错误)或其他一些配置错误有关?谢谢。
  • 我发现了我的错误,我创建了一个名为“basic-auth”而不是“auth”的文件来从中创建秘密。谢谢。
  • 另一个提示:确保 secret 和 ingress-ngnix 在同一个命名空间中
猜你喜欢
  • 2018-01-11
  • 2020-10-22
  • 1970-01-01
  • 2014-09-06
  • 2014-01-22
  • 2016-01-11
  • 2020-12-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多