cert-manager
# 安装
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.14.3/cert-manager.yaml
# 配置 Issuer
以
acme-issuer
的Cloudflare
为例
cert-manager 可配置:
Issuer
:作用域仅限某一命名空间ClusterIssuer
:作用域全局(推荐)
# 创建 Secret - DNS Api Token
创建一个 Secret,用来存储 DNS Api Token,cloudflare 有两种 token,这里我简单粗暴点使用的 Global API Key
。
需要准备 cloudflare 的 注册邮箱
、 Global API Key
。
在 cert-manager
命名空间下,创建用来存储 cloudflare 的 API token,将被下面引用
apiVersion: v1
kind: Secret
metadata:
name: cloudflare-api-key-secret
type: Opaque
stringData:
api-key: <Global API Key>
笔记
- 由于我使用了 kubesphere,这里我是在页面上手动创建的。
- 检查好配置是否准确,cloudflare 两种 token 对应不同的 key 名!!!
小节参考:
# 配置 测试 ClusterIssuer
由于 Let's Encrypt 正式证书有速率限制,因此在正式颁发前先使用 staging 证书打通整个链路先。
example-com-staging-cluster-issuer.yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: example-com-staging-cluster-issuer
spec:
acme:
email: [email protected] # 在证书过期的时候,会发邮件通知【测试的用默认就行】
server: https://acme-staging-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: example-com-letsencrypt-staging-key # 用于存储ACME帐户私钥的密钥名称
# 配置HTTP01或DNS01
solvers:
- dns01:
cloudflare:
email: my-cloudflare-[email protected]
apiKeySecretRef:
name: cloudflare-api-key-secret
key: api-key
kubectl apply -f example-com-staging-cluster-issuer.yaml
# 检查(Cluster)Issuers是否就绪
kubectl get clusterissuer
kubectl describe clusterissuer example-com-staging-cluster-issuer
# 配置 生产 ClusterIssuer
与测试的类似,建议在链路走通后再回来配置
example-com-prod-cluster-issuer.yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: example-com-prod-cluster-issuer
spec:
acme:
email: [email protected] # 在证书过期的时候,会发邮件通知
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: example-com-letsencrypt-prod-key # 用于存储ACME帐户私钥的密钥名称
# 配置HTTP01或DNS01
solvers:
- dns01:
cloudflare:
email: my-cloudflare-[email protected]
apiKeySecretRef:
name: cloudflare-api-key-secret
key: api-key
kubectl apply -f example-com-prod-cluster-issuer.yaml
# 检查(Cluster)Issuers是否就绪
kubectl get clusterissuer
kubectl describe clusterissuer example-com-prod-cluster-issuer
# 扩展:DNSPod(腾讯云)
笔记
说是 DNSPod,实际上用的是腾讯云的 api
参考:imroc/cert-manager-webhook-dnspod: cert-manager webhook resolver for DNSPod (opens new window)
安装
kubectl apply -f https://raw.githubusercontent.com/imroc/cert-manager-webhook-dnspod/master/bundle.yaml
创建 Secret - dnspod-secret
apiVersion: v1
stringData:
secret-key: ******
kind: Secret
metadata:
name: dnspod-secret
namespace: cert-manager
type: Opaque
配置 ClusterIssuer
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: example-com-prod-cluster-issuer
spec:
acme:
email: [email protected] # 在证书过期的时候,会发邮件通知
server: https://acme-v02.api.letsencrypt.org/directory # 生产
preferredChain: ""
privateKeySecretRef:
name: example-com-letsencrypt-prod-key # 用于存储ACME帐户私钥的密钥名称
solvers:
- dns01:
webhook:
config:
secretId: ************************************
secretKeyRef:
key: secret-key
name: dnspod-secret
ttl: 600
groupName: acme.imroc.cc
solverName: dnspod
注意
groupName
、 solverName
为 WEBHOOK 的标识,不可修改
kubectl apply -f example-com-prod-cluster-issuer.yaml
# 检查(Cluster)Issuers是否就绪
kubectl get clusterissuer
kubectl describe clusterissuer example-com-prod-cluster-issuer
# 部署 TLS Ingress
整体流程与正常部署 TLS Ingress 资源类似,区别在于:
需要添加注解
cert-manager.io/cluster-issuer
,值为上面配置的 Issuer 名称。- 如果是 issuer 则为
cert-manager.io/issuer
- 如果是 issuer 则为
secretName
原本为提前配好的证书 secret 名称,现在无需提前配置,填一个不存在的名称即可。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: kuard
annotations:
cert-manager.io/cluster-issuer: "example-com-prod-cluster-issuer"
spec:
ingressClassName: nginx
tls:
- hosts:
- example.example.com # 泛域名使用 "*.example.com"
secretName: example-com-staging-tls
rules:
- host: example.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: kuard
port:
number: 80
访问 Ingress https 端口会证书为 (STAGING) Artificial Apricot R3
即为成功,如为 Kubernetes Ingress Controller Fake Certificate
则未成功。
# 踩过的坑
部署了 TLS Ingress 并未成功,secret 里的 example-com-staging-tls 有后缀
最后发现是 issuer 没配好,把 Cloudflare 的两种 token 搞混了。
排除思路官方文档 Troubleshooting (故障排除) (opens new window)
证书没有颁发
# 检查证书资源,显示False说明有问题
kubectl get certificate
# 查看证书资源False的原因
kubectl describe certificate <certificate-name>
# 如果最后一个状态是 Created new CertificateRequest resource
# 则继续检查 certificaterequest资源,显示False说明有问题
kubectl get certificaterequest --all-namespaces
# 查看certificaterequest资源False的原因
kubectl describe certificaterequest <CertificateRequest name> -n 命名空间
# 至此通常就能知道问题出现在哪
# ACME 继续排除 order,从certificaterequest可知
kubectl get order
kubectl describe order example-com-2745722290-439160286
kubectl describe challenge example-com-2745722290-439160286-0
# 找到问题并解决后,可删除order重试
kubectl delete order example-com-2745722290-439160286
又或者可以在工作负载中找到 cert-manager/cert-manager
查看日志,如果你和我一样遇到上面的排除无果,可以尝试重新部署 cert-manager
来解决。
Referenced "Issuer" not found: issuer.cert-manager.io "nip-cool-prod-issuer" not found
检查是不是 issuer
和 cluster-issuer
搞混了
Waiting for DNS-01 challenge propagation: Could not determine authoritative nameservers for "_acme-challenge.nip.cool."
参考:DNS01 - cert-manager Documentation (opens new window)
- 不知道为什么一直自检不过,但同样的环境,dns 使用 cloudflare 的域名则正常通过。
- 解决办法是给 cert-manager 指定 DNS:
- 我使用的
kubectl apply
安装,我是通过编辑deployment
的 yaml 添加下述两行命令参数解决。 - 又或者把安装的
cert-manager.yaml
下载到本地,修改后apply
- 如果是通过 helm 方式安装的,则参考官方文档操作。
- 我使用的
spec:
containers:
- name: cert-manager-controller
image: 'quay.io/jetstack/cert-manager-controller:v1.14.3'
args:
- '--v=2'
- '--cluster-resource-namespace=$(POD_NAMESPACE)'
- '--leader-election-namespace=kube-system'
- '--dns01-recursive-nameservers-only'
- '--dns01-recursive-nameservers=119.29.29.29:53,8.8.8.8:53'
- 然后删除 order 重试
kubectl delete order example-com-2745722290-439160286
试了两个 k8s 集群使用 imroc/cert-manager-webhook-dnspod
+ cool域名
都会出现这个问题,不知道是域名问题还是 webhook 的问题。
# 参考
- Installation - cert-manager Documentation (opens new window)
- Securing NGINX-ingress - cert-manager Documentation (opens new window):官方全流程教程
- Troubleshooting (故障排除) - cert-manager Documentation (opens new window)
- Troubleshooting Problems with ACME (ACME 故障排除) / Let's Encrypt Certificates - cert-manager Documentation (opens new window)