使用客户端证书验证保护特定的nginx-ingress位置

5

我正在设置一个ghost实例,试图使用客户端证书验证来保护/ghost路径。

我已经有了一个初始的ingress,并且它以指定为 / 的路径很好地提供了服务。

我正在尝试添加第二个(大部分相同)的ingress用于/ghost路径。如果我这样做并添加基本身份验证的注释,一切似乎都很正常。即,如果我浏览到/ghost,我会在basic-auth秘密中提示凭据,如果我浏览其他任何URL,则会无需进行身份验证就可以访问。

然后,我根据此示例切换到基于客户端证书验证:https://github.com/kubernetes/ingress-nginx/tree/master/docs/examples/auth/client-certs

当我尝试这样做时,整个站点或站点的所有内容都被保护,而不是像基本身份验证那样进行基于路径的分离。查看运行pod的nginx.conf时,proxy_set_header ssl-client-verifyproxy_set_header ssl-client-subject-dnproxy_set_header ssl-client-issuer-dn元素被添加到根路径和/ghost路径下。我尝试将其从根路径中删除,并将配置直接复制回pod,但也没有运气。

我通过Helm将nginx-ingress(Chart版本0.23.0)作为依赖项引入。

/位置的Ingress定义 - 这个可以工作

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    certmanager.k8s.io/cluster-issuer: letsencrypt-staging
    kubernetes.io/ingress.class: nginx
    kubernetes.io/tls-acme: "true"
  labels:
    app: my-app
    chart: my-app-0.1.1
    heritage: Tiller
    release: my-app
  name: my-app
  namespace: default
spec:
  rules:
  - host: example.com
    http:
      paths:
      - backend:
          serviceName: my-app
          servicePort: http
        path: /
  tls:
  - hosts:
    - example.com
    secretName: mysite-tls
< p>对于/ghost位置的Ingress定义 - 这个没有起作用。

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/auth-tls-verify-client: "on"
    nginx.ingress.kubernetes.io/auth-tls-secret: "default/auth-tls-chain"
    nginx.ingress.kubernetes.io/auth-tls-verify-depth: "1"
    nginx.ingress.kubernetes.io/auth-tls-error-page: "http://www.example.com/error-cert.html"
    nginx.ingress.kubernetes.io/auth-tls-pass-certificate-to-upstream: "false"
    kubernetes.io/ingress.class: "nginx"
  labels:
    app: my-app
    chart: my-app-0.1.1
    heritage: Tiller
    release: my-app
  name: my-app-secure
  namespace: default
spec:
  rules:
  - host: example.com
    http:
      paths:
      - backend:
          serviceName: my-app
          servicePort: http
        path: /ghost
  tls:
  - hosts:
    - example.com
    secretName: mysite-tls

你能发布你的Ingress定义吗? - Rico
现在已经添加了入口定义。 - rh072005
2个回答

2
如果您想在第二个入口安全地为所有页面提供服务,请在路径上添加'*',如果只需要/ghost,则需要另一条规则。类似这样的东西:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/auth-tls-verify-client: "on"
    nginx.ingress.kubernetes.io/auth-tls-secret: "default/auth-tls-chain"
    nginx.ingress.kubernetes.io/auth-tls-verify-depth: "1"
    nginx.ingress.kubernetes.io/auth-tls-error-page: "http://www.example.com/error-cert.html"
    nginx.ingress.kubernetes.io/auth-tls-pass-certificate-to-upstream: "false"
    kubernetes.io/ingress.class: "nginx"
  labels:
    app: my-app
    chart: my-app-0.1.1
    heritage: Tiller
    release: my-app
  name: my-app-secure
  namespace: default
spec:
  rules:
  - host: example.com
    http:
      paths:
      - backend:
          serviceName: my-app
          servicePort: http
        path: /ghost
      - backend:
          serviceName: my-app
          servicePort: http
        path: /ghost/*
  tls:
  - hosts:
    - example.com
    secretName: mysite-tls

然而,如果你想要像/未加密和/ghost加密这样的设置,我相信你将无法做到。例如,如果你使用nginx,这是nginx本身的限制,当你在nginx中配置一个带有TLS的server {}块时,它看起来像这样:
server {
    listen              443 ssl;
    server_name         example.com;
    ssl_certificate     example.com.crt;
    ssl_certificate_key example.com.key;
    ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers         HIGH:!aNULL:!MD5;
    ...
}

负载均衡器创建的路径如下:

server {
    listen              443 ssl;
    server_name         example.com;
    ssl_certificate     example.com.crt;
    ssl_certificate_key example.com.key;
    ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers         HIGH:!aNULL:!MD5;
    ...

    location / {
       ...
    }

    location /ghost {
       ...
    }

}

当您配置另一个具有相同主机名且没有SSL的server {}块时,它将覆盖第一个。

您可以通过不同的- host:规则在入口中执行此操作,例如使用TLS的ghost.example.com和不使用TLS的main.example.com。因此,在您的nginx.conf中,您将拥有不同的server {}块。

您始终可以进入入口控制器pod来检查配置,例如:

$ kubectl exec -it nginx-ingress-controller-xxxxxxxxx-xxxxx bash
www-data@nginx-ingress-controller-6bd7c597cb-8kzjh:/etc/nginx$ cat nginx.conf

问题不在于 Ghost 下的多个页面(虽然这会在后面派上用场)。我的问题是除了 Ghost 下的页面之外,网站的所有部分都是公开的。我需要使用双向身份验证来保护 /ghost/*,但不包括其他任何页面。目前,认证应用于所有页面。 - rh072005
所以您想要“/”不安全,而“/ghost”安全? - Rico
是的,就是那样。 - rh072005
添加了更多细节...希望有所帮助。 - Rico
谢谢Rico,这真是太有帮助了。我想我会设置第二个入口和域,针对/ghost路径进行阻止,并在原来的一个中使用服务器片段来完成。 - rh072005

0

你可以添加一个位置片段

  annotations:
    nginx.ingress.kubernetes.io/location-snippet: |
       if ($location ^~ ghost) {
          set $ban_info = "location";
       }

       if ($ssl_client_s_dn !~ "CN=ok_client") {
          set $ban_info = "${ban_info}+no_client";
       }

       if ($ban_info = "location+no_client") {
         return 403;
       }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接