cert-manager是什么?
cert-manager 是一个在 k8s 上管理证书和证书签发的应用, 可以在自动在过期前更新证书。
cert-manager 可以从各种证书颁发机构获取证书,包括:Let’s Encrypt、HashiCorp Vault、Venafi 和私有 PKI。
安装
cert-manager支持helm和kubectl两种方式的安装,任选其中一种即可。
kubectl
执行安装操作
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.14.3/cert-manager.yaml
验证是否安装成功
kubectl get pods --namespace cert-manager
helm
执行安装操作
helm repo add jetstack https://charts.jetstack.io --force-update
helm repo update
helm install \
cert-manager jetstack/cert-manager \
--namespace cert-manager \
--create-namespace \
--version v1.14.3
验证是否安装成功
kubectl get pods --namespace cert-manager
选择证书颁发者
cert-manager 支持以下几种证书颁发者
- SelfSigned
- CA
- Vault
- Venafi
- ACME
由于ACME签发的比较好,这里我们选择它
选择证书校验方式
ACME支持 dns01, http01两种形式的验证
dns01
dns01是通过dns服务商提供的api key操作dns添加txt解析记录,然后颁发机构,将向dns系统查询该记录,如果找到匹配项,就可以颁发证书。此方法支持泛域名证书,无需公网站点。
配置示例
1.选择dns服务商
我这里用的是阿里云的,所以我选择了cert-manager-alidns-webhook
2.安装webhook
helm repo add cert-manager-alidns-webhook https://devmachine-fr.github.io/cert-manager-alidns-webhook
helm repo update
helm install cert-manager-alidns-webhook/alidns-webhook
3.创建secerts
登录阿里云打开【ram访问控制->身份管理->用户】
创建用户会得到AccessKey ID和AccessKey Secret
授予这个用户AliyunOSSFullAccess权限,如下图所示
执行下面命令
kubectl create secret generic alidns-secrets --from-literal="access-token=替换为你的AccessKey ID" --from-literal="secret-key=替换成你的AccessKey Secret" -n cert-manager
4.创建ClusterIssuer
创建ClusterIssuer.yaml,内容如下
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt
spec:
acme:
email: xxxx@gmail.com #替换成你的邮箱
server: https://acme-v02.api.letsencrypt.org/directory #readme给的是测试的地址,这边已经调整为正式地址,不然会报证书不信任
privateKeySecretRef:
name: letsencrypt
solvers:
- dns01:
webhook:
config:
accessTokenSecretRef:
key: access-token
name: alidns-secrets
regionId: cn-beijing
secretKeySecretRef:
key: secret-key
name: alidns-secrets
groupName: example.com
solverName: alidns-solver
执行下面命令
kubectl apply -f ClusterIssuer.yaml
5.签发证书
创建ClusterIssuerCertificate.yaml,内容如下
我的域名是codeme.cn
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: codeme-wildcard #名称随便定义
namespace: cert-manager
spec:
secretName: codeme-wildcard
commonName: codeme.cn #替换成自己的
dnsNames:
- codeme.cn #替换成自己的
- "*.codeme.cn" #替换成自己的
issuerRef:
name: letsencrypt
kind: ClusterIssuer
执行命令
kubectl apply -f ClusterIssuerCertificate.yaml
6.验证证书是否创建成功
kubectl get Certificate -A
NAMESPACE NAME READY SECRET AGE
cert-manager alidns-webhook-1709742037-ca True alidns-webhook-1709742037-ca 46h
cert-manager alidns-webhook-1709742037-webhook-tls True alidns-webhook-1709742037-webhook-tls 46h
cert-manager codeme-wildcard True codeme-wildcard 32h
以上可以看出 codeme-wildcard 已经创建成功, READY状态也是 True
复制证书到目标命名空间(namespace)
上面的证书是签发在cert-manager空间下的,其他的namespace要想使用证书,必须要把证书复制到自己的namespace下面。
解决方案参考 配置证书复制到其他 namespace下的内容
使用证书
ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/proxy-body-size: 20M
name: bee88
namespace: bee88
spec:
ingressClassName: nginx
rules:
- host: bee88.codeme.cn #替换成自己的
http:
paths:
- backend:
service:
name: mk #替换成自己的
port:
number: 80
path: /
pathType: ImplementationSpecific
tls:
- hosts:
- bee88.codeme.cn #替换成自己的
secretName: codeme-wildcard #替换成自己的
执行命令
kubectl apply -f ingress.yaml -n 目标空间
http01
http01方式需要在你的公网站点根目录下放置一个文件, 来验证你的域名所有权,完成验证,然后就可以生成证书了。此方法仅适用于给使用 Ingress 暴露流量的服务颁发证书,不支持泛域名证书。
配置示例
1.创建ClusterIssuer
#ClusterIssuer.yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt #名称随便定义,后面会用到
spec:
acme:
email: xxxx@gmail.com #替换成你的邮箱
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: issuer-account-key
solvers:
- http01:
ingress:
class: nginx
使用证书
ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
cert-manager.io/cluster-issuer: letsencrypt # 和上面定义的名称一致
nginx.ingress.kubernetes.io/proxy-body-size: 20M
name: saas
namespace: saas
spec:
ingressClassName: nginx
rules:
- host: saas.codeme.cn #替换成自己的
http:
paths:
- backend:
service:
name: mk #替换成自己的
port:
number: 80
path: /
pathType: ImplementationSpecific
tls:
- hosts:
- saas.codeme.cn #替换成自己的
secretName: saas.codeme.cn #替换成自己的
执行命令
kubectl apply -f ingress.yaml -n 目标空间
只要加上注解 cert-manager.io/cluster-issuer: letsencrypt ,那cert-manager会帮我们签发证书到secretName中
常见错误
证书不可信
主要是由于 安装的cert-manager-alidns-webhook 项目的readme给出了错误示范例子
需要把ACME的测试地址
https://acme-staging-v02.api.letsencrypt.org/directory
更改为
https://acme-v02.api.letsencrypt.org/directory
签发证书报错
1.报错User not authorized to operate on the specified resource, or this API doesn’t support RAM
阿里云的ram访问控制,创建用户的时候,没有进行AliyunOSSFullAccess授权,进cert-manger空间下pod中的日志可以看到错误信息
kubectl logs cert-manager-696746686c-62d7f -n cert-manager
解决方法参考Issuing certificate as Secret does not exist
2.证书卡在pending
证书的READY为false
kubectl get Certificate -A
NAMESPACE NAME READY SECRET AGE
cert-manager alidns-webhook-1709742037-ca True alidns-webhook-1709742037-ca 47h
cert-manager alidns-webhook-1709742037-webhook-tls True alidns-webhook-1709742037-webhook-tls 47h
cert-manager codeme-wildcard False codeme-wildcard 33h
kubectl get challenge -A
NAMESPACE NAME STATE DOMAIN AGE
cert-manager icodeme-wildcard-f9k16-382344 pending xxx.xxx 24s
查看原因是:
Waiting for DNS-01 challenge propagation: DNS record for “xxx.xxx” not yet
解决办法参考DNS01 配置示例下的内容
我本想参考这个方案,第一天做了部署不行,过了第二天发现pending消失了,自动成功了