如何通过证书管理器在 Kubernetes 中正确设置 TLS?

How to setup TLS correctly in Kubernetes via cert-manager?

我正在尝试为 Kubernetes 集群 (AWS EKS) 外部可用的服务设置 TLS。使用 cert-manager,我已经成功颁发了证书并配置了入口,但我仍然收到错误 NET::ERR_CERT_AUTHORITY_INVALID。这是我拥有的:

  1. namespace tests and hello-kubernetes in it (deployment and service have name hello-kubernetes-first, serivce 是 ClusterIP with port 80 and targetPort 8080, deployment is based on paulbouwer/hello-kubernetes:1.8, see details in my )

  2. DNS 和入口 配置为显示服务:

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: hello-kubernetes-ingress
      namespace: tests
    spec:
      ingressClassName: nginx
      rules:
      - host: test3.projectname.org
        http:
          paths:
          - path: "/"
            pathType: Prefix
            backend:
              service:
                name: hello-kubernetes-first
                port:
                  number: 80
    

    在不配置 TLS 的情况下,我可以通过 http 访问 test3.projectname.org 并查看服务(好吧,它试图将我重定向到 https,我看到 NET::ERR_CERT_AUTHORITY_INVALID,无论如何我都会进入不安全状态并查看你好 kubernetes 页面)。

    • 注意:我有 nginx-ingress ingress controller;它是通过下表安装在我面前的:

      apiVersion: v2
      name: nginx
      description: A Helm chart for Kubernetes
      type: application
      version: 4.0.6
      appVersion: "1.0.4"
      dependencies:
      - name: ingress-nginx
        version: 4.0.6
        repository: https://kubernetes.github.io/ingress-nginx
      

      并且图表应用的值覆盖与 original ones 主要在 extraArgs 中不同:default-ssl-certificate: "nginx-ingress/dragon-family-com" 未提交

  3. cert-manager 通过 kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.5.4/cert-manager.yaml

    安装
  4. ClusterIssuer 使用以下配置创建:

    apiVersion: cert-manager.io/v1
    kind: ClusterIssuer
    metadata:
      name: letsencrypt-backoffice
    spec:
      acme:
        server: https://acme-staging-v02.api.letsencrypt.org/directory
        # use https://acme-v02.api.letsencrypt.org/directory after everything is fixed and works
        privateKeySecretRef: # this secret is created in the namespace of cert-manager
          name: letsencrypt-backoffice-private-key
        # email: <will be used for urgent alerts about expiration etc>
    
        solvers:
        # TODO: add for each domain/second-level domain/*.projectname.org
        - selector:
            dnsZones:
              - test.projectname.org
              - test2.projectname.org
              - test3.projectname.org
          http01:
            ingress:
              class: nginx
    
  5. 证书tests 命名空间中。它的配置是

    apiVersion: cert-manager.io/v1
    kind: Certificate
    metadata:
      name: letsencrypt-certificate-31
      namespace: tests
    spec:
      secretName: tls-secret-31
      issuerRef:
        kind: ClusterIssuer
        name: letsencrypt-backoffice
      commonName: test3.projectname.org
      dnsNames:
      - test3.projectname.org
    

现在,证书已准备就绪(kubectl get certificates -n tests 说明)并应用它,我将其添加到入口规范中:

  tls:
    - hosts:
      - test3.projectname.org
      secretName: tls-secret-31

但是,当我尝试通过 https 打开 test3.projectname.org 时,它仍然显示 NET::ERR_CERT_AUTHORITY_INVALID 错误。 我做错了什么?如何调试? 我检查了 openssl s_client -connect test3.projectname.org:443 -prexit*,它显示了以下链:

 0 s:CN = test3.projectname.org
   i:C = US, O = (STAGING) Let's Encrypt, CN = (STAGING) Artificial Apricot R3
 1 s:C = US, O = (STAGING) Let's Encrypt, CN = (STAGING) Artificial Apricot R3
   i:C = US, O = (STAGING) Internet Security Research Group, CN = (STAGING) Pretend Pear X1
 2 s:C = US, O = (STAGING) Internet Security Research Group, CN = (STAGING) Pretend Pear X1
   i:C = US, O = (STAGING) Internet Security Research Group, CN = (STAGING) Doctored Durian Root CA X3

并告诉其他输出

Verification error: unable to get local issuer certificate

不幸的是,我还没有找到任何有用的东西来进一步尝试,所以非常感谢您的帮助。

您的 ClusterIssuer 指的是 LetsEncrypt 暂存颁发者。删除该设置/默认应该使用他们的生产设置。正如评论中指出的那样:https://acme-v02.api.letsencrypt.org/directory

删除之前生成的机密或切换到新的机密应确保使用正确的颁发者重新生成您的证书。

暂存颁发者可能有助于测试 LetsEncrypt 集成,否则不应使用它。

根据 SYN 的建议,我已经通过

解决了这个问题
  1. 正在将 ClusterIssuer 配置中的 ACME 服务器从 https://acme-staging-v02.api.letsencrypt.org/directory 切换到 https://acme-v02.api.letsencrypt.org/directory。登台服务器的想法似乎是:允许调试证书颁发(以便 kubectl get certificate [-n <namespace>] 显示 READY = true)而不提供实际的可信证书;发证成功后,切换到主服务器获取生产证书。

  2. 正在更新证书、tls 机密和入口配置。好吧,我不确定是否有办法实际更新证书;相反,我创建了新的,它创建了新的秘密,然后更新了入口配置(只是秘密的名称)

您的证书不起作用的原因,不是因为您使用了登台服务器,而是因为您没有在 Ingress 规则中指定 tls 对象。 Certbot 的暂存仅用于测试目的,如果您请求超过 5 certificates/hour,则不会在您测试时“禁止”您。 当您验证一切都按预期工作时,您可以使用普通的非暂存服务器。

应该这样做:

集群颁发者对象:

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: user@example.com
    privateKeySecretRef:
      name: letsencrypt-prod
    solvers:
    - http01:
        ingress:
          class: nginx

入口对象:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: hello-kubernetes-ingress
  namespace: tests
  labels:
    app: hello-kubernetes-ingress
  annotations:
    kubernetes.io/ingress.class: "nginx"
    cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  tls:
  - hosts:
    - test3.projectname.org
    secretName: hello-tls
  rules:
  - host: test3.projectname.org
    http:
      paths:
      - pathType: ImplementationSpecific
        path: "/"
        backend:
          service:
            name: hello-kubernetes-ingress
            port: 
              number: 80

证书和密钥存储在一个名为“hello-tls”的秘密中,您在初始示例中也没有指定,因此您收到了失败。