K8s安装Cert Manager
cert-manager 为 Kubernetes 或 OpenShift 集群中的工作负载创建 TLS 证书,并在证书过期之前续订证书。
cert-manager 可以从各种证书颁发机构获取证书,包括: Let’s Encrypt、HashiCorp Vault、 Venafi和私有 PKI。
使用 cert-manager 的证书资源,私钥和证书存储在 Kubernetes Secret 中,该 Secret 由应用程序 Pod 挂载或由 Ingress 控制器使用。使用csi-driver、csi-driver-spiffe或istio-csr,私钥是在应用程序启动之前按需生成的;私钥永远不会离开节点,并且不会存储在 Kubernetes Secret 中。
安装
参考官方文档:https://cert-manager.io/docs/installation/
使用kubectl安装
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.14.5/cert-manager.yaml查看:
kubectl get pods --namespace cert-manager使用helm安装
添加 repo:
helm repo add jetstack https://charts.jetstack.io --force-updatehelm repo update安装 cert-manager:
helm install cert-manager jetstack/cert-manager \ --namespace cert-manager \ --create-namespace \ --version v1.14.5 \ --set installCRDs=true更多配置参数,参考:https://artifacthub.io/packages/helm/cert-manager/cert-manager
查看状态
$ kubectl -n cert-manager rollout status deploy/cert-managerdeployment "cert-manager" successfully rolled out
$ kubectl get pods -n cert-managerNAME READY STATUS RESTARTS AGEpod/cert-manager-5c47f46f57-k78l6 1/1 Running 0 91spod/cert-manager-cainjector-6659d6844d-tr8rf 1/1 Running 0 91spod/cert-manager-webhook-547567b88f-8lthd 1/1 Running 0 91s使用helm3查看:
$ helm list -n cert-managerNAME NAMESPACE REVISION UPDATED STATUS CHART cert-manager cert-manager 1 2024-05-09 17:35:59.976722226 +0800 CST deployed cert-manager-v1.14.5 v1.14.5验证
创建自签名证书进行验证:
$ cat <<EOF > test-resources.yamlapiVersion: v1kind: Namespacemetadata: name: cert-manager-test---apiVersion: cert-manager.io/v1kind: Issuermetadata: name: test-selfsigned namespace: cert-manager-testspec: selfSigned: {}---apiVersion: cert-manager.io/v1kind: Certificatemetadata: name: selfsigned-cert namespace: cert-manager-testspec: dnsNames: - example.com secretName: selfsigned-cert-tls issuerRef: name: test-selfsignedEOF创建 test-resources:
kubectl apply -f test-resources.yaml查看证书状态:
$ kubectl describe certificate -n cert-manager-testName: selfsigned-certNamespace: cert-manager-testLabels: <none>Annotations: <none>API Version: cert-manager.io/v1Kind: CertificateMetadata: Creation Timestamp: 2024-05-09T23:25:16Z Generation: 1 Resource Version: 302521 UID: 4a691ab3-4a7a-476d-9cd6-028285bca5baSpec: Dns Names: example.com Issuer Ref: Name: test-selfsigned Secret Name: selfsigned-cert-tlsStatus: Conditions: Last Transition Time: 2024-05-09T23:25:17Z Message: Certificate is up to date and has not expired Observed Generation: 1 Reason: Ready Status: True Type: Ready Not After: 2024-08-07T23:25:17Z Not Before: 2024-05-09T23:25:17Z Renewal Time: 2024-07-08T23:25:17Z Revision: 1Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Issuing 8s cert-manager-certificates-trigger Issuing certificate as Secret does not exist Normal Generated 7s cert-manager-certificates-key-manager Stored new private key in temporary Secret resource "selfsigned-cert-f66n5" Normal Requested 7s cert-manager-certificates-request-manager Created new CertificateRequest resource "selfsigned-cert-1" Normal Issuing 7s cert-manager-certificates-issuing The certificate has been successfully issued删除 test-resources:
kubectl delete -f test-resources.yaml卸载
#通过kubectl删除kubectl delete -f https://github.com/cert-manager/cert-manager/releases/download/v1.14.5/cert-manager.crds.yaml
#通过helm3删除helm --namespace cert-manager delete cert-managerkubectl delete namespace cert-manager生成证书
概念介绍
Issuer
安装 cert-manager 后,您需要配置的第一件事是Issuer或ClusterIssuer。Issuers 和 ClusterIssuers 是 Kubernetes 资源,表示能够通过接受证书签名请求来生成签名证书的证书颁发机构 (CA)。所有 cert-manager 证书都需要一个处于就绪状态的引用颁发者来尝试接受请求。
一个简单的 CA Issuer 如下:
apiVersion: cert-manager.io/v1kind: Issuermetadata: name: ca-issuer namespace: mesh-systemspec: ca: secretName: ca-key-pair这是一个基于私钥对证书进行签名的简单 Issuer 方法。然后,存储在密钥 ca-key-pair 中的证书可用于 Issuer 在公钥基础结构 (PKI) 系统中信任新签名的证书。
Issuers 和 ClusterIssuer 区别:
- Issuers 是基于命名空间的
- ClusterIssuer 是基于集群的
ACME Orders 和 Challenges
cert-manager 支持使用ACME Issuer从 ACME 服务器请求证书,包括从Let’s Encrypt请求证书。这些证书通常在公共 Internet 上受到大多数计算机的信任。要成功请求证书,证书管理器必须解决已完成的 ACME 挑战,以证明客户端拥有所请求的 DNS 地址。
为了完成这些挑战,cert-manager引入了两种 CustomResource类型;Orders和Challenges。
ACME 支持两种验证方式:
- DNS 验证:通过 DNS01 质询,您可以通过证明您控制域名的 DNS 记录来证明其所有权。这是通过创建具有特定内容的 TXT 记录来完成的,该记录证明您拥有对域 DNS 记录的控制权
- HTTP 验证:通过 HTTP01 质询,您可以通过确保域中存在特定文件来证明域的所有权。
Let’s Encrypt 的 ACME 服务器分为两种:
- 暂存环境:
https://acme-staging-v02.api.letsencrypt.org/directory - 生产环境:
https://acme-v02.api.letsencrypt.org/directory
生产环境施加了更严格的速率限制,因此为了减少您达到这些限制的机会,建议测试过程中使用暂存环境。
Let’s Encrypt 利用 ACME 协议来校验域名是否真的属于你,校验成功后就可以自动颁发免费证书,证书有效期只有 90 天,在到期前需要再校验一次来实现续期,幸运的是 cert-manager 可以自动续期,这样就可以使用永久免费的证书了。如何校验这个域名是否属于你呢?主流的两种校验方式是 HTTP-01 和 DNS-01,详细校验原理可参考 Let’s Encrypt 的运作方式,下面将简单描述下。
Let’s Encrypt生成证书
ACME 颁发证书并使用 HTTP 验证
HTTP-01 的校验原理是给你域名指向的 HTTP 服务增加一个临时 location ,Let’s Encrypt 会发送 http 请求到 http:///.well-known/acme-challenge/,YOUR_DOMAIN 就是被校验的域名,TOKEN 是 ACME 协议的客户端负责放置的文件,在这里 ACME 客户端就是 cert-manager,它通过修改或创建 Ingress 规则来增加这个临时校验路径并指向提供 TOKEN 的服务。Let’s Encrypt 会对比 TOKEN 是否符合预期,校验成功后就会颁发证书。此方法仅适用于给使用 Ingress 暴露流量的服务颁发证书,并且不支持泛域名证书。
先创建一个颁发者,因为测试,使用暂存环境的 ACME 服务器。
cat <<EOF > letsencrypt-staging.yamlapiVersion: cert-manager.io/v1kind: Issuermetadata: name: letsencrypt-stagingspec: acme: # The ACME server URL server: https://acme-staging-v02.api.letsencrypt.org/directory # Email address used for ACME registration email: ichensoul@gmail.com # Name of a secret used to store the ACME account private key privateKeySecretRef: name: letsencrypt-staging # Enable the HTTP-01 challenge provider solvers: # An empty 'selector' means that this solver matches all domains - selector: {} http01: ingress: ingressClassName: nginxEOF创建颁发者:
kubectl apply -f letsencrypt-staging.yaml创建证书:
cat <<EOF > chensoul-cc-tls.yamlapiVersion: cert-manager.io/v1kind: Certificatemetadata: name: chensoul-cc-tlsspec: secretName: chensoul-cc-tls issuerRef: name: letsencrypt-staging commonName: test.chensoul.cc dnsNames: - test.chensoul.ccEOF创建证书:
$ kubectl apply -f chensoul-cc-tls.yamlcertificate.cert-manager.io/chensoul-cc-tls created查看状态:
kubectl get secret,certificate,Issuer,ClusterIssuer
kubectl describe Issuer letsencrypt-stagingkubectl describe Secret cloudflare-api-token-secret
kubectl describe certificate chensoul-cc-tlskubectl describe CertificateRequest chensoul-cc-tlskubectl describe order chensoul-cc-tlskubectl describe Challenge chensoul-cc-tls等待一段时间,直到证书状态变为True:
$ kubectl get secret,certificate,Issuer,ClusterIssuerNAME TYPE DATA AGEsecret/chensoul-cc-tls kubernetes.io/tls 2 47ssecret/cloudflare-api-token-secret Opaque 1 2m39ssecret/letsencrypt-staging Opaque 1 5m34s
NAME READY SECRET AGEcertificate.cert-manager.io/chensoul-cc-tls True chensoul-cc-tls 2m31s
NAME READY AGEissuer.cert-manager.io/letsencrypt-staging True 2m39s还可以查看证书的 TLS Base64 键值对:
kubectl get secret chensoul-cc-tls -o yaml删除相关资源:
kubectl delete Secret cloudflare-api-token-secret letsencrypt-staging chensoul-cc-tlskubectl delete Issuers letsencrypt-stagingkubectl delete certificate chensoul-cc-tlsACME 颁发证书并使用 DNS 验证
DNS-01 的校验原理是利用 DNS 提供商的 API Key 拿到你的 DNS 控制权限, 在 Let’s Encrypt 为 ACME 客户端提供令牌后,ACME 客户端 (cert-manager) 将创建从该令牌和您的帐户密钥派生的 TXT 记录,并将该记录放在 _acme-challenge.。 然后 Let’s Encrypt 将向 DNS 系统查询该记录,如果找到匹配项,就可以颁发证书。此方法不需要你的服务使用 Ingress,并且支持泛域名证书。
参考:https://medium.com/@sms-astanley/custom-issuers-with-letsencrypt-and-rancher-ingress-2c89ab1b0a91
先创建一个颁发者,然后根据域名解析选择 DNS01 提供商,支持的提供商参考:https://cert-manager.io/docs/configuration/acme/dns01/
我的 DNS 提供商为 Cloudflare,参考 https://cert-manager.io/docs/configuration/acme/dns01/cloudflare/ 在 Cloudflare 创建一个 API token 或者 API KEY。
cat <<EOF > letsencrypt-staging.yamlapiVersion: v1kind: Secretmetadata: name: cloudflare-api-token-secrettype: OpaquestringData: api-token: SSQ0XP71lyfFDjIMPuwtti7v-LhOQlpPe5ruK-9Z
---apiVersion: cert-manager.io/v1kind: Issuermetadata: name: letsencrypt-stagingspec: acme: email: ichensoul@gmail.com server: https://acme-staging-v02.api.letsencrypt.org/directory # Name of a secret used to store the ACME account private key privateKeySecretRef: name: letsencrypt-staging solvers: - dns01: cloudflare: email: ichensoul@gmail.com apiTokenSecretRef: name: cloudflare-api-token-secret key: api-tokenEOF创建颁发者:
$ kubectl apply -f letsencrypt-staging.yamlsecret/cloudflare-api-token-secret createdissuer.cert-manager.io/letsencrypt-staging created如果想将这个 Issuer 设置为默认使用,可以用如下命令升级 cert-manager
helm upgrade cert-manager jetstack/cert-manager --set 'extraArgs={--default-issuer-name=letsencrypt-prod,--default-issuer-kind=ClusterIssuer}' -n cert-manager
创建一个证书:
cat <<EOF > chensoul-cc-tls.yamlapiVersion: cert-manager.io/v1kind: Certificatemetadata: name: chensoul-cc-tlsspec: secretName: chensoul-cc-tls issuerRef: name: letsencrypt-staging kind: Issuer commonName: test.chensoul.cc dnsNames: - test.chensoul.ccEOF创建证书:
$ kubectl apply -f chensoul-cc-tls.yamlcertificate.cert-manager.io/chensoul-cc-tls created查看状态:
kubectl get secret,certificate,Issuer,ClusterIssuer
kubectl describe Issuer letsencrypt-stagingkubectl describe Secret cloudflare-api-token-secret
kubectl describe certificate chensoul-cc-tlskubectl describe CertificateRequest chensoul-cc-tlskubectl describe order chensoul-cc-tlskubectl describe Challenge chensoul-cc-tls等待一段时间,直到证书状态变为True:
$ kubectl get secret,certificate,Issuer,ClusterIssuerNAME TYPE DATA AGEsecret/chensoul-cc-tls kubernetes.io/tls 2 47ssecret/cloudflare-api-token-secret Opaque 1 2m39ssecret/letsencrypt-staging Opaque 1 5m34s
NAME READY SECRET AGEcertificate.cert-manager.io/chensoul-cc-tls True chensoul-cc-tls 2m31s
NAME READY AGEissuer.cert-manager.io/letsencrypt-staging True 2m39s还可以查看证书的 TLS Base64 键值对:
kubectl get secret chensoul-cc-tls -o yaml删除相关资源:
kubectl delete Secret cloudflare-api-token-secret letsencrypt-staging chensoul-cc-tlskubectl delete Issuers letsencrypt-stagingkubectl delete certificate chensoul-cc-tls校验方式对比
HTTP-01 的校验方式的优点是: 配置简单通用,不管使用哪个 DNS 提供商都可以使用相同的配置方法;缺点是:需要依赖 Ingress,如果你的服务不是用 Ingress 暴露流量的就不适用,而且不支持泛域名证书。
DNS-01 的校验方式的优点是没有 HTTP-01 校验方式缺点,不依赖 Ingress,也支持泛域名;缺点就是不同 DNS 提供商的配置方式不一样,而且 DNS 提供商有很多,cert-manager 的 Issuer 不可能每个都去支持,不过有一些可以通过部署实现了 cert-manager 的 Webhook 的服务来扩展 Issuer 进行支持,比如 DNSPod 和 阿里 DNS,详细 Webhook 列表请参考: https://cert-manager.io/docs/configuration/acme/dns01/#webhook
选择哪种方式呢?条件允许的话,建议是尽量用 DNS-01 的方式,限制更少,功能更全。
参考文章
- Make SSL certs easy with k3s
- https://www.thebookofjoel.com/k3s-cert-manager-letsencrypt
- 使用 LetsEncrypt配置kubernetes ingress-nginx免费HTTPS证书
- cert-manager管理k8s集群证书
- https://blog.csdn.net/xichenguan/article/details/100709830
- https://medium.com/@sms-astanley/custom-issuers-with-letsencrypt-and-rancher-ingress-2c89ab1b0a91