在具有大量域的 kubernetes 应用程序上自动化 LetsEncrypt

Had*_*oud 5 kubernetes lets-encrypt caddy

我有一个节点应用程序,它根据域名加载其数据。域配置有 CNAME app.service.com(即节点应用程序)。

Node 应用程序看到请求域并向 API 发送请求以获取应用程序数据。

例如:domain.comCNAME app.service.com -> 然后节点应用程序向 api 请求 domain.com 数据

问题是为所有域设置 HTTPS(使用 LetsEncrypt)。我认为 cert-manager 可以提供帮助,但不知道如何自动执行此操作,而无需手动更改每个新域的配置文件。

或者在 Kubernetes 中是否有更好的方法来实现这一目标?

Mal*_*ata 2

支持多个域名和/或子域名的标准方法是使用一个 SSL 证书并实施 SAN(主题备用名称)。额外的域名一起存储在 SAN 中。所有 SSL 证书都支持 SAN,但并非所有证书颁发机构都会颁发多域证书。Let\'s Encrypt 确实支持SAN,因此他们的证书将满足您的目标。

\n\n

首先,您必须在我们的集群中创建一个作业,使用图像来运行 shell 脚本。该脚本将启动 HTTP 服务、创建证书并将其保存到预定义的机密中。您的域名和电子邮件是环境变量,因此请务必填写:

\n\n
apiVersion: batch/v1\nkind: Job\nmetadata:\n  name: letsencrypt-job\n  labels:\n    app: letsencrypt\nspec:\n  template:\n    metadata:\n      name: letsencrypt\n      labels:\n        app: letsencrypt\n    spec:\n      containers:\n      # Bash script that starts an http server and launches certbot\n      # Fork of github.com/sjenning/kube-nginx-letsencrypt\n      - image: quay.io/hiphipjorge/kube-nginx-letsencrypt:latest\n        name: letsencrypt\n        imagePullPolicy: Always\n        ports:\n        - name: letsencrypt\n          containerPort: 80\n        env:\n        - name: DOMAINS\n          value: kubernetes-letsencrypt.jorge.fail # Domain you want to use. CHANGE ME!\n        - name: EMAIL\n          value: jorge@runnable.com # Your email. CHANGE ME!\n        - name: SECRET\n          value: letsencrypt-certs\n      restartPolicy: Never\n
Run Code Online (Sandbox Code Playgroud)\n\n

您有一个作业正在运行,因此您可以创建一个服务来将流量定向到该作业:

\n\n
apiVersion: v1\nkind: Service\nmetadata:\n  name: letsencrypt\nspec:\n  selector:\n    app: letsencrypt\n  ports:\n  - protocol: "TCP"\n    port: 80\n
Run Code Online (Sandbox Code Playgroud)\n\n

该作业现在可以运行,但在我们的作业真正成功并且我们\xe2\x80\x99能够通过 HTTPs 访问我们的服务之前,您仍然需要做三件事。

\n\n

首先,您需要为作业创建一个秘密,以实际更新和存储我们的证书。由于当我们创建密钥时您没有\xe2\x80\x99t 任何证书,因此密钥将开始为空。

\n\n
apiVersion: v1\nkind: Secret\nmetadata:\n  name: letsencrypt-certs\ntype: Opaque\n\n# Create an empty secret (with no data) in order for the update to work\n
Run Code Online (Sandbox Code Playgroud)\n\n

其次,您\xe2\x80\x99 必须将密钥添加到 Ingress 控制器才能获取证书。请记住,入口控制器了解我们的主机,这就是为什么需要在此处指定我们的证书。将我们的秘密添加到 Ingress 控制器将如下所示:

\n\n
apiVersion: extensions/v1beta1\nkind: Ingress\nmetadata:\n  name: "kubernetes-demo-app-ingress-service"\nspec:\n  tls:\n  - hosts:\n    - kubernetes-letsencrypt.jorge.fail # Your host. CHANGE ME\n    secretName: letsencrypt-certs # Name of the secret\n  rules:\n
Run Code Online (Sandbox Code Playgroud)\n\n

最后,您必须通过我们的 Nginx 部署将流量通过主机重定向到作业。为此,您\xe2\x80\x99 将向我们的 Nginx 配置添加一个新路由和一个上游:这可以通过 Ingress 控制器添加一个/.well-known/*条目并将其重定向到 LetsEncrypt 服务来完成。\xe2\x80\x99s 更复杂,因为您还必须向作业添加运行状况路由,因此您\xe2\x80\x99 只需通过 Nginx 部署重定向流量:

\n\n
apiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: nginx-config\ndata:\n  default.conf: |\n\n
Run Code Online (Sandbox Code Playgroud)\n\n

...

\n\n
    # Add upstream for letsencrypt job\n    upstream letsencrypt {\n      server letsencrypt:80 max_fails=0 fail_timeout=1s;\n    }\n\n    server {\n      listen 80;\n\n
Run Code Online (Sandbox Code Playgroud)\n\n

...

\n\n
      # Redirect all traffic in /.well-known/ to letsencrypt\n      location ^~ /.well-known/acme-challenge/ {\n        proxy_pass http://letsencrypt;\n      }\n    }\n
Run Code Online (Sandbox Code Playgroud)\n\n

应用所有这些更改后,销毁您的 Nginx Pod,以确保 ConfigMap 在新 Pod 中正确更新:

\n\n
$ kubectl get pods | grep ngi | awk \'{print $1}\' | xargs kubectl delete pods\n
Run Code Online (Sandbox Code Playgroud)\n\n

确保它有效。

\n\n

为了验证这是否有效,您应该确保作业确实成功。您可以通过 kubectl 获取作业来完成此操作,也可以检查 Kubernetes 仪表板。

\n\n
$ kubectl get job letsencrypt-job\nNAME              DESIRED   SUCCESSFUL   AGE\nletsencrypt-job   1         1            1d\n
Run Code Online (Sandbox Code Playgroud)\n\n

您还可以检查机密以确保证书已正确填充。您可以通过 kubectl 或通过仪表板执行此操作:

\n\n
$ kubectl describe secret letsencrypt-certs\n\nName:   letsencrypt-certs\nNamespace:  default\nLabels:   <none>\nAnnotations:\nType:   Opaque\nData\n====\ntls.crt:  3493 bytes\ntls.key:  1704 bytes\n
Run Code Online (Sandbox Code Playgroud)\n\n

现在您可以看到证书已成功创建,您可以执行整个过程中的最后一步。为了让 Ingress 控制器获取密钥中的更改(从没有数据到拥有证书),您需要更新它以便重新加载。为此,我们\xe2\x80\x99 只需添加一个时间戳作为 Ingress 控制器的标签:

\n\n
apiVersion: extensions/v1beta1\nkind: Ingress\nmetadata:\n  name: "kubernetes-demo-app-ingress-service"\n  labels:\n    # Timestamp used in order to force reload of the secret\n    last_updated: "1494099933"\n...\n
Run Code Online (Sandbox Code Playgroud)\n\n

请查看:kubernetes-letsencrypt

\n