TLS/SSL 证书有效期缩短到 47 天:用 ACME 协议在亚马逊云科技上实现证书全自动续期
TLS/SSL 证书有效期缩短到 47 天:用 ACME 协议在亚马逊云科技上实现证书全自动续期
CA/B Forum 2025 年 4 月投票通过了证书有效期缩减路线图。2026 年 3 月起 200 天,2027 年 3 月起 100 天,2029 年 3 月起只有 47 天。手动续期?别想了,必须自动化。
背景:证书有效期为什么越来越短
我第一次知道这事是去年底,看到 Apple 在 CA/B Forum 上提的 Ballot SC-081 终于通过了。简单说就是:
| 时间节点 | 证书有效期 | DCV 有效期 |
|---|---|---|
| 2025.4 之前 | 398 天 | 398 天 |
| 2026.3.15 | 200 天 | 200 天 |
| 2027.3.15 | 100 天 | 100 天 |
| 2029.3.15 | 47 天 | 10 天 |
说白了,到 2029 年你的证书一个半月就过期。一台服务器还好,十台二十台呢?手动登上去 renew 一遍?周末忘了续期直接 503?
这不是杞人忧天——我去年就被坑过一次。某个边缘节点的证书过期了,凌晨 2 点告警把我叫醒,排查半天发现是 cron 任务写错了路径。从那以后我就开始认真研究自动化方案。 EC2 上的 Nginx/Apache 里。这就引出了第二条路。
路线二:ACME 协议自动申请+续期(EC2 自管场景)
如果你在 EC2 上跑 Nginx、跑 Apache、跑自建 K8s Ingress,就得用 ACME 协议自己管证书了。好消息是 Certbot 和 acme.sh 都很成熟,配合 cron 可以做到全自动。
Certbot 三种验证模式详解
Certbot 支持三种方式获取证书,适用场景不一样:
模式一:Standalone(独占 80 端口)
Certbot 自己起一个临时 Web 服务器来完成验证。适合还没部署 Web 服务、或者可以短暂停服的场景。
# 先停掉 Nginx
sudo systemctl stop nginx
# 申请证书
sudo certbot certonly --standalone \
-d example.com \
-d www.example.com \
--email admin@example.com \
--agree-tos \
--no-eff-email
# 重新启动 Nginx
sudo systemctl start nginx
缺点明显:续期的时候也得停服。生产环境别用这个。
模式二:Webroot(不中断服务)
让 Certbot 把验证文件写到 Nginx 的 webroot 目录,CA 来访问验证。服务不中断。
# Nginx 配置里加一段
# server {
# listen 80;
# server_name example.com;
# location /.well-known/acme-challenge/ {
# root /var/www/certbot;
# }
# }
sudo certbot certonly --webroot \
-w /var/www/certbot \
-d example.com \
-d www.example.com \
--email admin@example.com \
--agree-tos
模式三:Nginx 插件(一步到位)
Certbot 的 Nginx 插件会自动修改 Nginx 配置、完成验证、安装证书。最省事。
sudo certbot certonly --nginx \
-d example.com \
-d www.example.com \
--email admin@example.com \
--agree-tos
# 或者连安装也一起做(自动改 nginx.conf)
sudo certbot --nginx \
-d example.com \
-d www.example.com
装完之后看一眼证书信息:
sudo certbot certificates
# 输出类似:
# Certificate Name: example.com
# Domains: example.com www.example.com
# Expiry Date: 2026-09-15 (VALID: 89 days)
# Certificate Path: /etc/letsencrypt/live/example.com/fullchain.pem
# Private Key Path: /etc/letsencrypt/live/example.com/privkey.pem
自动续期:一条 cron 搞定
Certbot 续期命令是 certbot renew,它会检查所有证书,距离过期 30 天以内的自动续。
# 测试续期(不会真的续,只是跑一遍流程)
sudo certbot renew --dry-run
# 写进 crontab,每天凌晨 2:30 跑一次
echo "30 2 * * * root certbot renew --quiet --deploy-hook 'systemctl reload nginx'" | sudo tee /etc/cron.d/certbot-renew
--deploy-hook 是关键——续期成功后自动 reload Nginx,让新证书生效。不加这个的话证书续了但 Nginx 还在用旧的,等于白续。
踩坑记录:我之前写成了 --post-hook,这个不管续没续都会跑。如果你有多张证书,每次 cron 触发都会 reload 一次 Nginx,虽然无害但日志会很吵。用 --deploy-hook 只在真正续期成功时才执行。
进阶:DigiCert ACME 支持(企业级 OV/EV 证书)
Let’s Encrypt 发的是 DV 证书,不少企业内部要求 OV 或 EV。好消息是 DigiCert 现在也支持 ACME 协议了,意味着你可以用同样的自动化流程来管理付费证书。
# DigiCert ACME 目录 URL
DIGICERT_ACME_URL="https://acme.digicert.com/v2/acme/directory"
# 用 certbot 注册 DigiCert 账户
sudo certbot register \
--server $DIGICERT_ACME_URL \
--email admin@example.com \
--agree-tos \
--eab-kid "YOUR_KEY_ID" \
--eab-hmac-key "YOUR_HMAC_KEY"
# 申请证书
sudo certbot certonly --nginx \
--server $DIGICERT_ACME_URL \
-d example.com
EAB(External Account Binding)的 Key ID 和 HMAC Key 从 DigiCert 管理后台获取。配置好之后续期流程和 Let’s Encrypt 一模一样。
多台 EC2 的证书管理方案
如果你有十几台 EC2 都需要证书,一台台 SSH 上去配 Certbot 显然不现实。几个方案:
方案一:集中式——用 ELB 卸载 TLS
把所有 EC2 放到 ALB 后面,TLS 终止在 ALB,证书用 ACM 管理。EC2 只处理 HTTP 流量。这是最推荐的架构。
方案二:自动化——Ansible/SSM 批量配置
用 AWS Systems Manager Run Command 批量执行 Certbot 安装和配置:
# 通过 SSM 在所有带 tag 的实例上安装 certbot
aws ssm send-command \
--targets "Key=tag:Role,Values=webserver" \
--document-name "AWS-RunShellScript" \
--parameters 'commands=["sudo snap install certbot --classic","sudo certbot certonly --nginx -d $(hostname -f) --agree-tos --email admin@example.com -n"]'
方案三:容器化——cert-manager
如果跑 EKS,用 cert-manager 配合 Let’s Encrypt 自动管理 Ingress 证书:
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: admin@example.com
privateKeySecretRef:
name: letsencrypt-prod-key
solvers:
- http01:
ingress:
class: nginx
监控证书过期:别等告警了才发现
自动化做好之后,还需要兜底监控。推荐用 CloudWatch + Lambda 做证书过期检查:
import ssl
import socket
import datetime
import boto3
def check_cert_expiry(domain, port=443):
ctx = ssl.create_default_context()
with ctx.wrap_socket(socket.socket(), server_hostname=domain) as s:
s.settimeout(5)
s.connect((domain, port))
cert = s.getpeercert()
expiry = datetime.datetime.strptime(cert['notAfter'], '%b %d %H:%M:%S %Y %Z')
days_left = (expiry - datetime.datetime.utcnow()).days
return days_left
def lambda_handler(event, context):
domains = ['example.com', 'api.example.com', 'admin.example.com']
sns = boto3.client('sns')
for domain in domains:
days = check_cert_expiry(domain)
if days < 14:
sns.publish(
TopicArn='arn:aws:sns:us-east-1:123456789012:cert-alerts',
Subject=f'证书即将过期: {domain}',
Message=f'{domain} 的证书还有 {days} 天过期,请检查自动续期是否正常。'
)
决策树:我该选哪个方案
| 场景 | 推荐方案 | 理由 |
|---|---|---|
| 业务在 ALB/CloudFront 后面 | ACM | 零运维,自动续期 |
| EC2 直接暴露,DV 证书够用 | Certbot + cron | 免费,成熟 |
| 企业要求 OV/EV 证书 | DigiCert ACME + Certbot | 自动化管理付费证书 |
| K8s/EKS 环境 | cert-manager | 云原生方式 |
| 大量 EC2 需要统一管理 | ALB 集中卸载,或 SSM 批量 | 降低运维复杂度 |
总结
证书有效期缩短是大势所趋,从 398 天到 47 天这条路已经定了。与其到 2029 年手忙脚乱,不如现在就把自动化搭好:
- 能用 ACM 就用 ACM,零成本零运维
- EC2 自管场景用 Certbot,
--deploy-hook别忘了 - cron 是续期的核心,写完跑一遍
--dry-run - 加上监控兜底,14 天阈值告警
别等证书过期那天凌晨被叫醒才后悔。
参考资料:
更多推荐
所有评论(0)