引言:证书缩期的技术必然性
CA/B Forum 的 Ballot SC-081 确定了证书有效期缩减路线:398 天 → 200 天(2026.3)→ 100 天(2027.3)→ 47 天(2029.3)。背后的逻辑很清楚——缩短有效期能降低私钥泄露的风险窗口,但代价是运维复杂度指数级上升。
我管理着十几台 EC2 实例上的证书,去年手动续期还能应付,现在已经开始全面切自动化了。这篇文章把我的方案、配置和踩坑经验完整记录下来。
一、方案全景:ACM 托管 vs ACME 自管
ACM 托管:零运维方案
如果你的架构是 客户端 → ALB/CloudFront → EC2,TLS 终止在 ALB 上,那用 ACM 就够了:
aws acm request-certificate \--domain-name "*.example.com" \--validation-method DNS \--region us-east-1
ACM 证书免费、自动续期、跟 ALB/CloudFront 无缝集成。限制是不能导出私钥,没法直接装到 Nginx 上。
ACME 自管:EC2 直接终止 TLS 的场景
当 EC2 直接暴露给用户(没有 LB),或者有特殊的证书需求(OV/EV、自定义 CA),就得用 ACME 协议手动管理了。
ACME(Automatic Certificate Management Environment)是 Let's Encrypt 推动的标准协议(RFC 8555),核心流程:
- 客户端向 CA 发起证书申请
- CA 下发验证挑战(HTTP-01 或 DNS-01)
- 客户端完成挑战,证明域名所有权
- CA 签发证书
- 到期前重复上述流程完成续期
二、Certbot 三种验证模式的技术对比
Standalone 模式
sudo certbot certonly --standalone \-d example.com -d www.example.com \--email admin@example.com --agree-tos --no-eff-email
原理:Certbot 在 80 端口起临时 HTTP 服务器。CA 访问 http://example.com/.well-known/acme-challenge/<token> 完成验证。
适用场景:初始部署、还没装 Web 服务器。
致命缺点:续期时也需要停服占端口。
Webroot 模式
sudo certbot certonly --webroot \-w /var/www/certbot \-d example.com \--email admin@example.com --agree-tos
原理:Certbot 把挑战文件写到指定目录,由已运行的 Nginx 提供访问。需要在 Nginx 配置中加:
server {listen 80;server_name example.com;location /.well-known/acme-challenge/ {root /var/www/certbot;}location / {return 301 https://$host$request_uri;}
}
适用场景:不想让 Certbot 碰 Nginx 配置的洁癖选手。
Nginx 插件模式
sudo certbot certonly --nginx \-d example.com -d www.example.com \--email admin@example.com --agree-tos
原理:Certbot 通过 Nginx 插件直接修改 server block,临时插入验证 location,验证完删掉。
适用场景:大多数 EC2 + Nginx 的标准部署。推荐首选。
三种模式对比
| 维度 | Standalone | Webroot | Nginx 插件 |
|---|---|---|---|
| 是否中断服务 | 是 | 否 | 否 |
| 是否修改 Nginx 配置 | 否 | 需手动加 location | 自动处理 |
| 续期友好度 | 差 | 好 | 好 |
| 生产环境推荐 | ✗ | ✓ | ✓(首选) |
三、自动续期的完整配置
基础 cron 配置
# 验证续期流程
sudo certbot renew --dry-run# 生产 cron
echo "30 2 * * * root certbot renew --quiet --deploy-hook 'systemctl reload nginx'" \| sudo tee /etc/cron.d/certbot-renew
sudo chmod 644 /etc/cron.d/certbot-renew
deploy-hook vs post-hook 的区别
这是一个我踩过的坑:
--deploy-hook:只在证书实际被续期时执行--post-hook:不管有没有续期,每次 renew 命令结束都执行--pre-hook:每次 renew 命令开始前执行
多证书场景下,用 --post-hook 会导致每次 cron 触发都 reload Nginx。虽然不会出问题,但日志很吵。
续期失败告警
# /etc/cron.d/certbot-renew
30 2 * * * root certbot renew --quiet --deploy-hook 'systemctl reload nginx' || curl -X POST https://hooks.slack.com/xxx -d '{"text":"证书续期失败,请检查"}'
四、DigiCert ACME:企业级证书自动化
Let's Encrypt 只签发 DV 证书。如果合规要求 OV/EV,可以用 DigiCert ACME:
# 注册账户(EAB 凭据从 DigiCert CertCentral 获取)
sudo certbot register \--server https://acme.digicert.com/v2/acme/directory \--eab-kid "YOUR_KEY_ID" \--eab-hmac-key "YOUR_HMAC_KEY" \--agree-tos --email admin@example.com# 申请证书(后续续期跟 LE 一样走 cron)
sudo certbot certonly --nginx \--server https://acme.digicert.com/v2/acme/directory \-d example.com
五、多台 EC2 的规模化管理
SSM 批量推送
aws ssm send-command \--targets "Key=tag:Role,Values=webserver" \--document-name "AWS-RunShellScript" \--parameters 'commands=["snap install certbot --classic","certbot certonly --nginx -d $(hostname -f) --agree-tos -m admin@example.com -n","echo \"30 2 * * * root certbot renew --quiet --deploy-hook systemctl reload nginx\" > /etc/cron.d/certbot-renew"]'
架构升级:收拢到 ALB
如果团队规模允许,最好的方案还是把 TLS 终止收拢到 ALB + ACM。EC2 只处理 HTTP,彻底不碰证书。
六、监控层:Lambda 证书探测
import ssl, socket, datetime, boto3def lambda_handler(event, context):domains = ['example.com', 'api.example.com']for domain in domains:ctx = ssl.create_default_context()with ctx.wrap_socket(socket.socket(), server_hostname=domain) as s:s.settimeout(5)s.connect((domain, 443))cert = s.getpeercert()expiry = datetime.datetime.strptime(cert['notAfter'], '%b %d %H:%M:%S %Y %Z')days_left = (expiry - datetime.datetime.utcnow()).daysif days_left < 14:boto3.client('sns').publish(TopicArn='arn:aws:sns:us-east-1:123456789012:cert-alerts',Message=f'{domain} 证书还剩 {days_left} 天过期')
用 EventBridge 每天触发一次,14 天阈值告警。
总结
| 场景 | 推荐方案 |
|---|---|
| ALB/CloudFront 后面 | ACM 托管 |
| EC2 自管 DV 证书 | Certbot + Nginx 插件 + cron |
| 企业 OV/EV 需求 | DigiCert ACME + Certbot |
| EKS 容器环境 | cert-manager + ClusterIssuer |
| 多台 EC2 批量管理 | SSM Run Command 或架构升级到 ALB |
证书有效期缩短到 47 天不是 if 而是 when。现在花半小时配好自动化,比以后每个月手动续期省心得多。
参考资料:
- 使用 ACME 协议实现 TLS/SSL 证书自动化 - 亚马逊云科技
- AWS Certificate Manager 用户指南
- RFC 8555 - Automatic Certificate Management Environment (ACME)
