证书 47 天就过期,还在手动续?聊聊我在 AWS 上的自动化方案

证书 47 天就过期,还在手动续?聊聊我在 AWS 上的自动化方案

上周帮朋友排查一个线上故障,折腾两小时最后发现------证书过期了。就这么简单又离谱的原因。客户打不开页面,浏览器直接甩一个 NET::ERR_CERT_DATE_INVALID,朋友还以为是 DNS 出了问题,查了半天。

更离谱的是,这种事以后会越来越频繁。CA/B Forum 去年通过了 Ballot SC-081,证书有效期会一路缩:398 天 → 200 天(2026.3)→ 100 天(2027.3)→ 47 天(2029.3)。到 2029 年,一个半月不续就挂。你管 5 台机器可能还能记住,管 20 台呢?靠人肉置巡?不现实。

今天分享一下我在亮马逊云科技上搞证书自动化的实践,踩过的坑一并说了。

先选路线:你的证书该谁管

在亚马逊云科技上搞 TLS,第一步是想清楚你属于哪种架构:

架构 方案 操心程度
ALB/CloudFront/API Gateway ACM 托管 完全不操心
EC2 上跑 Nginx/Apache Certbot + ACME 需要配一次
EKS Ingress cert-manager K8s 声明式

如果你的流量经过 ALB 或 CloudFront,直接用 AWS Certificate Manager(ACM),证书免费、自动续期、零配置。申请的时候加个 DNS 验证的 CNAME 记录,后面再也不用管了:

bash 复制代码
aws acm request-certificate \
  --domain-name "*.example.com" \
  --validation-method DNS \
  --region us-east-1

但现实是很多团队的服务直接跑在 EC2 上,TLS 终止在 Nginx。ACM 的证书没法导出私钥,装不到 Nginx 里。这种情况就得靠 ACME 协议 + Certbot 了。

Certbot 实战:三种模式怎么选

Nginx 插件模式(日常推荐)

Certbot 的 Nginx 插件会自动在你的 server block 里插入验证 location,验证完删掉,整个过程不中断服务:

bash 复制代码
# 安装
sudo snap install certbot --classic

# 一条命令搞定申请
sudo certbot certonly --nginx \
  -d example.com \
  -d www.example.com \
  --email admin@example.com \
  --agree-tos

装完看一眼证书状态:

bash 复制代码
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

Webroot 模式(不碠 Nginx 配置)

有些同事的 Nginx 配置比较复杂(比如用了大量 include 和自定义 map),不想让 Certbot 自动改配置文件。这时候用 Webroot 模式,自己加一段 location 就行:

nginx 复制代码
server {
    listen 80;
    server_name example.com;
    location /.well-known/acme-challenge/ {
        root /var/www/certbot;
    }
}

然后跑:

bash 复制代码
sudo certbot certonly --webroot \
  -w /var/www/certbot \
  -d example.com \
  -d www.example.com \
  --email admin@example.com \
  --agree-tos

Standalone 模式(临时用用)

Certbot 自己起一个 Web 服务器来验证,但它得占 80 端口,意味着你得先停掉 Nginx。生产环境别用这个做续期,适合新机器初次部署还没装 Web 服务器的场景。

bash 复制代码
sudo systemctl stop nginx
sudo certbot certonly --standalone \
  -d example.com \
  --email admin@example.com \
  --agree-tos
sudo systemctl start nginx

自动续期的正确姿势

证书拿到了,怎么自动续?Certbot 的 renew 命令会扫描所有本地证书,距离过期 30 天内的自动续。

bash 复制代码
# 先跑一遍 dry-run,确认流程没问题
sudo certbot renew --dry-run

# 写 cron,每天凌晨 2:30 跑一次
echo "30 2 * * * root certbot renew --quiet --deploy-hook 'systemctl reload nginx'" \
  | sudo tee /etc/cron.d/certbot-renew

踩坑重点--deploy-hook--post-hook 的区别。

  • --deploy-hook:只在续期成功时执行
  • --post-hook:不管有没有续期都执行

我之前用的 --post-hook,结果每天凌晨 cron 触发都会 reload Nginx,日志里全是无意义的 reload 记录。多张证书的时候更烦,一次 renew 跑完会 reload 好几次。改成 --deploy-hook 后世界清净了。

DigiCert ACME:企业级 OV/EV 也能自动化

Let's Encrypt 发的是 DV(域名验证)证书,免费好用。但有些企业内部合规要求 OV 或 EV 证书,显示公司名。好消息是 DigiCert 现在也支持 ACME 协议了,意味着付费证书也能走同样的自动化流程。

bash 复制代码
# 注册 DigiCert ACME 账户(EAB 凭据从 DigiCert 管理后台获取)
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

# 申请证书
sudo certbot certonly --nginx \
  --server https://acme.digicert.com/v2/acme/directory \
  -d example.com

配好后续期流程跟 Let's Encrypt 完全一样,同一条 cron 通吃,不用额外改任何东西。

多台机器怎么管

单机 Certbot 配一次就好,但如果你有十几台 EC2 呢?一台台 SSH 过去配置不现实。三种思路:

思路一:流量收拢到 ALB。TLS 终止在负载均衡器,后端 EC2 只跑 HTTP。新服务强烈推荐这么干。

思路二:SSM 批量推送。用 AWS Systems Manager Run Command 一次搞定所有机器:

bash 复制代码
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"]'

思路三:EKS 用 cert-manager。K8s 环境下声明一个 ClusterIssuer,证书申请和续期全自动:

yaml 复制代码
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

监控兜底:别光靠自动化

自动化做好了不代表可以完全放手。万一哪天 Let's Encrypt 服务端抽风、DNS 解析出了问题、安全组把 80 端口关了,续期就会失败。加一层监控兜底:

python 复制代码
import ssl, socket, datetime, boto3

def check_cert(domain):
    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')
        return (expiry - datetime.datetime.utcnow()).days

def lambda_handler(event, context):
    for domain in ['example.com', 'api.example.com']:
        days = check_cert(domain)
        if days < 14:
            boto3.client('sns').publish(
                TopicArn='arn:aws:sns:us-east-1:123456789012:cert-alerts',
                Message=f'{domain} 证书还剩 {days} 天,请检查续期是否正常'
            )

用 EventBridge 每天触发一次这个 Lambda 就行。14 天阈值给了你两周的缓冲来人工干预。

我的建议

  1. 能上 ALB + ACM 的优先上,省心到不需要解释
  2. EC2 场景 Certbot + Nginx 插件 + deploy-hook,一次配好长期不管
  3. 企业证书走 DigiCert ACME,同一套自动化流程
  4. 不管哪种方案,都加上监控,14 天阈值告警
  5. 配完立刻跑 --dry-run,别等到真正续期那天才发现配错了

证书有效期缩短已经是定局,趁现在还有 200 天的缓冲期起紧把自动化做了。别等凌晨 2 点被告警叫醒才后悔。


参考: 使用 ACME 协议实现 TLS/SSL 证书自动化 - 亚马逊云科技

相关推荐
云天AI实战派3 天前
Agentic AI 全流程实战:用 OpenAI on AWS 搭一个餐饮补货智能体,从 API 调用到容器化上线
人工智能·云计算·aws
yunson_Liu3 天前
aws EKS集群pvc存储扩容
k8s·aws
卷卷说风控3 天前
【卷卷观察】OpenAI扑进AWS怀里:AI平台战争进入贴身肉搏期
人工智能·云计算·aws
SNOWPIAOP5 天前
Claude Code + CCR + AWS Bedrock 踩坑复盘:上下文超限、模型路由、Mantle 端点与 Qwen3 Coder Next
云计算·claude·aws·上下文·ccr
Flynt7 天前
AWS WorkMail + App Runner:服务退役时的迁移检查清单
app·aws
zhojiew8 天前
AWS云上ECS托管控制器场景服务部署策略实践和原理
云计算·aws
yunson_Liu8 天前
AWS EKS创建EFS存储类
云计算·aws
TG_yunshuguoji8 天前
亚马逊云代理商:如何在AWS上部署Hermes Agent?
人工智能·云计算·aws·hermes agent·hermes
TokenByte-AI导航小贴士9 天前
Claude 4.5 Sonnet / Opus / Haiku:新手选型指南
人工智能·ai·云计算·aigc·claude·aws