k8s使用cert-manager签发免费SSL证书
介绍如何在Kubernetes集群中使用cert-manager自动签发和管理免费的SSL证书
概述
在Kubernetes环境中部署应用时,为服务配置HTTPS加密访问是一个常见需求。手动管理SSL证书不仅繁琐,而且容易出错和过期。cert-manager是一个Kubernetes原生证书管理工具,可以自动化证书的申请、签发和续期过程,特别是与Let's Encrypt等免费证书颁发机构(CA)集成,为Kubernetes服务提供免费的SSL证书。
本文将介绍cert-manager的基本原理、安装配置方法,以及如何使用它来自动签发和管理SSL证书。
cert-manager介绍
cert-manager是一个开源的Kubernetes证书管理控制器,它可以在Kubernetes集群中自动化证书的颁发和管理过程。主要特性包括:
- 自动化证书管理:自动申请、签发、续期和安装证书
- 多种CA支持:支持Let's Encrypt、HashiCorp Vault、Venafi等多种证书颁发机构
- ACME协议支持:完整实现ACME协议,支持HTTP-01和DNS-01验证方式
- 证书资源抽象:提供Certificate、Issuer、ClusterIssuer等自定义资源定义(CRD)
- 集成Ingress:与常见Ingress控制器无缝集成,自动为Ingress配置证书
- 监控和告警:提供证书过期监控和告警机制
原理
cert-manager的工作原理基于Kubernetes的控制器模式和自定义资源定义(CRD):
核心组件
- 控制器(Controller):监听Certificate资源的变化,处理证书申请和续期
- 自定义资源定义(CRD):
Certificate:定义需要申请的证书Issuer:命名空间级别的证书颁发者配置ClusterIssuer:集群级别的证书颁发者配置
- Webhook:验证和转换自定义资源
工作流程
- 用户创建Certificate资源,定义所需证书的域名、有效期等信息
- cert-manager控制器检测到新的Certificate资源
- 根据Certificate中引用的Issuer/ClusterIssuer配置,选择合适的证书颁发机构
- 使用ACME协议向CA申请证书
- 完成域名所有权验证(HTTP-01或DNS-01)
- 获取证书并存储在Kubernetes Secret中
- 将证书应用到Ingress或其他资源
- 定期检查证书有效期,自动续期即将过期的证书
ACME验证方式
- HTTP-01验证:通过在域名下放置特定文件来验证域名所有权
- DNS-01验证:通过在DNS记录中添加TXT记录来验证域名所有权
操作步骤
1. 安装cert-manager
helm install \
cert-manager oci://quay.io/jetstack/charts/cert-manager \
--version v1.19.0 \
--namespace cert-manager \
--create-namespace \
--set crds.enabled=true \
--set prometheus.enabled=false
2. 配置证书颁发者(ClusterIssuer)
以下配置说明:
- 使用Let's Encrypt生产环境(ClusterIssuer)
- 类型为ClusterIssuer
- 使用DNS-01验证方式
对于需要通配符证书或内网服务的场景,可以使用DNS-01验证方式。首先需要创建DNS提供商的API令牌Secret:
cloudflare-api-token-secret.yaml
apiVersion: v1
kind: Secret
metadata:
namespace: cert-manager # cluster-issuer使用的secret需要在cert-manager命名空间下
name: cloudflare-api-token-secret
type: Opaque
stringData:
api-token: xxx # 请替换为您的实际Cloudflare API令牌
创建支持DNS-01验证的ClusterIssuer:
cluster-issuer.yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod-dns-cluster-issuer
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: example@example.com
privateKeySecretRef:
name: letsencrypt-prod-dns-cluster-issuer-secret
solvers:
- dns01:
cloudflare:
apiTokenSecretRef:
name: cloudflare-api-token-secret
key: api-token
selector:
dnsNames:
- "*.example.com"
- "example.com"
- "app.example.com"
- dns01:
cloudflare:
apiTokenSecretRef:
name: cloudflare-api-token-secret
key: api-token
selector:
dnsZones:
- "example.com"
- dns01:
# 兜底
cloudflare:
apiTokenSecretRef:
name: cloudflare-api-token-secret
key: api-token
3. 创建证书资源
方式一:通过Ingress自动创建特定域名证书
ingress-test1.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: cert-manager-ingress-test1
namespace: default
annotations:
# 通过 cert-manager 自动创建证书
cert-manager.io/cluster-issuer: "letsencrypt-prod-dns-cluster-issuer"
nginx.ingress.kubernetes.io/use-forwarded-headers: "true"
nginx.ingress.kubernetes.io/proxy-real-ip-cidr: "0.0.0.0/0"
nginx.ingress.kubernetes.io/enable-real-ip: "true"
nginx.ingress.kubernetes.io/compute-full-forwarded-for: "true"
nginx.ingress.kubernetes.io/proxy-body-size: "100m"
spec:
ingressClassName: nginx
tls:
- hosts:
- app.example.com # 创建特定的域名的证书
secretName: app.example.com-ingress-tls-secret # 保存ssl证书的secret,cert-manager自动创建的证书将保存到此secret中
rules:
- host: app.example.com
http:
paths:
- pathType: Prefix
backend:
service:
name: example-svc
port:
number: 8080
path: /
方式二:通过Ingress自动创建通配符证书
ingress-test2.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: cert-manager-ingress-test2
namespace: default
annotations:
# 通过 cert-manager 自动创建证书
cert-manager.io/cluster-issuer: "letsencrypt-prod-dns-cluster-issuer"
nginx.ingress.kubernetes.io/use-forwarded-headers: "true"
nginx.ingress.kubernetes.io/proxy-real-ip-cidr: "0.0.0.0/0"
nginx.ingress.kubernetes.io/enable-real-ip: "true"
nginx.ingress.kubernetes.io/compute-full-forwarded-for: "true"
nginx.ingress.kubernetes.io/proxy-body-size: "100m"
spec:
ingressClassName: nginx
tls:
- hosts:
- "*.example.com" # 创建三级域名通配符证书
- "example.com" # 创建二级域名证书
secretName: wildcard-example.com-manager-tls-secret # 保存ssl证书的secret,cert-manager自动创建的证书将保存到此secret中
rules:
- host: app2.example.com
http:
paths:
- pathType: Prefix
backend:
service:
name: example-svc
port:
number: 8080
path: /
方式三:手动创建Certificate,并手动绑定到Ingress
先手动创建通配符证书 manual-create-certificate.yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: wildcard-example.com-certificate
namespace: default
spec:
secretName: wildcard-example.com-tls-secret # 保存ssl证书的secret,cert-manager自动创建的证书将保存到此secret中
issuerRef:
name: letsencrypt-prod-dns-cluster-issuer
kind: ClusterIssuer
dnsNames:
- "*.example.com"
- "example.com"
然后创建Ingress时绑定此证书
ingress-test3.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: cert-manager-ingress-test3
namespace: default
annotations:
# 注意手动创建Certificate时,这里不需要使用注解cert-manager.io/cluster-issuer
nginx.ingress.kubernetes.io/use-forwarded-headers: "true"
nginx.ingress.kubernetes.io/proxy-real-ip-cidr: "0.0.0.0/0"
nginx.ingress.kubernetes.io/enable-real-ip: "true"
nginx.ingress.kubernetes.io/compute-full-forwarded-for: "true"
nginx.ingress.kubernetes.io/proxy-body-size: "100m"
nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
ingressClassName: nginx
tls:
- hosts:
- app3.example.com
secretName: wildcard-example.com-tls-secret # 引用上面manual-create-certificate.yaml预先已创建的通配符证书
rules:
- host: app3.example.com
http:
paths:
- pathType: Prefix
backend:
service:
name: example-svc
port:
number: 8080
path: /
4. 查看资源类型
# 查看核心资源
kubectl get certificate # 查看证书
kubectl get issuer # 查看命名空间级签发者
kubectl get clusterissuer # 查看集群级签发者
kubectl get challenge # 查看 ACME 验证挑战
kubectl get order # 查看 ACME 订单
kubectl get certificaterequest # 查看 ACME 证书请求
kubectl get secret
总结
cert-manager为Kubernetes环境提供了强大的证书自动化管理能力,通过与Let's Encrypt等免费CA集成,可以大大简化HTTPS配置的复杂性。在实际应用中,建议:
- 先使用Let's Encrypt测试环境进行验证
- 根据实际需求选择ClusterIssuer或Issuer
- 根据实际需求选择合适的验证方式(HTTP-01或DNS-01)
- 设置适当的监控和告警机制
- 定期检查证书状态和cert-controller日志