Kubernetes Ingress HTTPS自动化:Cert-Manager与Let's Encrypt实践指南
你好,SRE同行!
我理解你刚接手一个Kubernetes集群,发现大量服务Ingress缺乏HTTPS配置,老板又要求所有对外服务必须走HTTPS,这确实是个常见的挑战。手工管理证书不仅效率低下,而且极易出错,特别是证书的存储、分发和自动续期。
别担心,在Kubernetes生态中,我们有非常成熟的工具来自动化这一过程。今天,我将带你通过一个实用的方法,利用 Cert-Manager 结合 Let's Encrypt 实现Kubernetes Ingress HTTPS证书的自动化管理,彻底解决你的困扰。
为什么选择 Cert-Manager 和 Let's Encrypt?
- Cert-Manager:Kubernetes原生证书管理工具,能够自动化地从各种CA(如Let's Encrypt、Vault等)获取、续订和管理TLS证书。它将证书以Secret的形式存储在Kubernetes集群中,供Ingress Controller或其他应用使用。
- Let's Encrypt:一个免费、开放、自动化的证书颁发机构(CA),提供被所有主流浏览器信任的TLS证书。它的ACME协议非常适合自动化集成。
前提条件
- 一个运行中的Kubernetes集群。
- 已安装并配置好Ingress Controller,例如Nginx Ingress Controller或Traefik。确保你的Ingress Controller能够正确处理流量并路由到后端服务。
- 一个或多个可解析到Ingress Controller外部IP/域名的域名(例如:
your-service.example.com)。
实践步骤:自动化部署与管理HTTPS证书
步骤 1:安装 Cert-Manager
Cert-Manager 的安装非常简单,推荐使用 Helm。
# 1. 添加 cert-manager Helm 仓库
helm repo add jetstack https://charts.jetstack.io
helm repo update
# 2. 安装 cert-manager CRDs(Custom Resource Definitions)
# 注意:v1.7.0+ 版本需要手动安装CRDs,或者使用 helm install --set installCRDs=true
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.2/cert-manager.crds.yaml
# 3. 安装 cert-manager 到 cert-manager 命名空间
# 请根据你的集群版本选择合适的 cert-manager 版本
helm install cert-manager jetstack/cert-manager \
--namespace cert-manager \
--create-namespace \
--version v1.13.2 # 替换为你想要安装的版本
安装完成后,你可以通过以下命令检查 cert-manager Pods 是否正常运行:
kubectl get pods -n cert-manager
# 应该看到 cert-manager, cert-manager-webhook, cert-manager-cainjector 三个 Pod 处于 Running 状态
步骤 2:配置 ClusterIssuer 或 Issuer
Issuer 和 ClusterIssuer 是 Cert-Manager 用来表示证书颁发机构的资源。Issuer 作用于特定命名空间,而 ClusterIssuer 作用于整个集群。对于需要跨多个命名空间共享证书的场景,ClusterIssuer 是更好的选择。
这里我们使用 Let's Encrypt 的 HTTP-01 挑战类型,因为它最常用且易于配置,只要你的 Ingress Controller 能正常访问外部网络。
2.1 创建 Let's Encrypt Staging ClusterIssuer(用于测试)
建议先使用 Let's Encrypt Staging 环境进行测试,以免触及生产环境的速率限制。
# cert-manager-staging-clusterissuer.yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-staging
spec:
acme:
# 邮箱用于接收证书相关的通知,非常重要
email: your-email@example.com
server: https://acme-staging-v02.api.letsencrypt.org/directory
privateKeySecretRef:
# 用于存储 ACME 账户密钥的 Secret
name: letsencrypt-staging-private-key
solvers:
- http01:
ingress:
class: nginx # 替换为你的 Ingress Controller 名称,例如:nginx, traefik, gce
保存为 cert-manager-staging-clusterissuer.yaml 并应用:
kubectl apply -f cert-manager-staging-clusterissuer.yaml
2.2 创建 Let's Encrypt Production ClusterIssuer(用于生产)
当测试通过后,你可以创建生产环境的 ClusterIssuer。
# cert-manager-production-clusterissuer.yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
email: your-email@example.com
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: letsencrypt-prod-private-key
solvers:
- http01:
ingress:
class: nginx # 替换为你的 Ingress Controller 名称
保存为 cert-manager-production-clusterissuer.yaml 并应用:
kubectl apply -f cert-manager-production-clusterissuer.yaml
检查 ClusterIssuer 状态:
kubectl get clusterissuer letsencrypt-staging -o yaml
# 确保 Status.Conditions 中 Type: Ready 的状态为 True
步骤 3:更新 Ingress 资源以请求 HTTPS 证书
现在,你可以修改现有的 Ingress 资源,或创建新的 Ingress,让 Cert-Manager 为其自动签发证书。
# my-service-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-service-ingress
annotations:
# 指定使用哪个 ClusterIssuer 来签发证书
cert-manager.io/cluster-issuer: letsencrypt-staging # 测试阶段用 staging,生产阶段改为 letsencrypt-prod
# 强制将 HTTP 请求重定向到 HTTPS (Nginx Ingress Controller 特有)
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
spec:
ingressClassName: nginx # 确保指定了你的 Ingress Class
tls:
- hosts:
- your-service.example.com # 你的域名
secretName: your-service-tls # Cert-Manager 会将证书存储到这个 Secret
rules:
- host: your-service.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-backend-service # 你的后端服务名称
port:
number: 80 # 你的后端服务监听的端口
关键点解释:
cert-manager.io/cluster-issuer: letsencrypt-staging:这个 annotation 告诉 Cert-Manager 哪个ClusterIssuer负责为这个 Ingress 签发证书。tls部分:hosts:指定需要 HTTPS 保护的域名。secretName:Cert-Manager 会把签发到的证书(包括私钥和公钥)以kubernetes.io/tls类型的 Secret 存储在这个名称下。Ingress Controller 会自动加载这个 Secret 来启用 HTTPS。
保存为 my-service-ingress.yaml 并应用:
kubectl apply -f my-service-ingress.yaml
步骤 4:验证证书签发状态
应用 Ingress 后,Cert-Manager 会自动为你创建 Certificate 和 Order 资源来管理证书签发流程。
# 查看 Certificate 资源
kubectl get certificate
# 查看 Order 资源(会显示证书签发过程中的挑战状态)
kubectl get order
# 查看 Challenge 资源(会显示 ACME 挑战的具体信息)
kubectl get challenge
当 Certificate 资源的状态显示 Ready 为 True 时,表示证书已成功签发并存储在 your-service-tls 这个 Secret 中。
kubectl get secret your-service-tls -o yaml
# 你会看到 base64 编码的 tls.crt 和 tls.key
步骤 5:访问服务验证 HTTPS
现在,通过浏览器访问 https://your-service.example.com,你应该能看到浏览器地址栏显示安全连接(小绿锁),并且证书信息应该是由 Let's Encrypt 签发的。
证书存储、分发与自动续期
- 证书存储:Cert-Manager 成功获取证书后,会将其存储在一个 Kubernetes Secret 中(例如上面的
your-service-tls)。这个 Secret 类型为kubernetes.io/tls,包含tls.crt和tls.key两个数据字段。 - 证书分发:当 Ingress Controller 检测到 Ingress 资源中指定了
tls部分以及对应的secretName后,它会自动从这个 Secret 中读取证书数据,并将其配置到其代理服务器(如Nginx或Envoy)中,从而启用 HTTPS。这个过程对你来说是透明的。 - 自动续期:这是 Cert-Manager 最强大的功能之一。默认情况下,Cert-Manager 会在证书到期前约30天自动尝试续订。它会重新执行 ACME 挑战流程,获取新的证书,并更新对应的 Secret。由于 Ingress Controller 通常会监听这些 Secret 的变化,所以证书更新后,服务通常不需要手动干预就能无缝切换到新证书,实现了真正的自动化。
最佳实践与注意事项
- 先用 Staging,后用 Production:始终先在
letsencrypt-staging环境测试你的配置,确保一切正常后再切换到letsencrypt-prod。生产环境的 Let's Encrypt 有严格的速率限制,频繁失败可能导致暂时无法签发证书。 - DNS-01 挑战:如果你的 Ingress Controller 无法直接暴露 HTTP-01 挑战所需的
.well-known/acme-challenge路径,或者你需要签发泛域名证书(例如*.example.com),你就需要使用 DNS-01 挑战。这通常需要 Cert-Manager 能够与你的DNS服务提供商(如阿里云DNS、腾讯云DNS、AWS Route 53等)集成,通过API修改DNS记录来验证域名所有权。 - 监控证书状态:虽然 Cert-Manager 会自动续期,但作为 SRE,监控其健康状况仍是必要的。你可以设置告警,例如当
Certificate资源的Ready状态长时间不是True,或者其notAfter字段显示证书即将过期时。 - Secret 安全:存储证书的 Secret 是敏感信息,确保对这些 Secret 设置适当的 RBAC 权限,限制只有必要的服务账户才能访问。
- Ingress Controller 配置:确认你的 Ingress Controller 支持
networking.k8s.io/v1版本的 Ingress 资源,并正确配置了ingressClassName。
通过上述步骤,你不仅能满足老板对HTTPS的要求,还能建立一套健壮、自动化的证书管理流程,大大提升运维效率和系统安全性。祝你顺利!