背景与痛点

在云原生和微服务架构中,服务之间的通信安全至关重要。mTLS(双向TLS)通过双向认证机制,确保通信双方的身份合法性,是零信任架构的核心组件之一。然而,传统的证书管理方式(如使用OpenSSL手动签发)存在诸多痛点:

  • 手动操作繁琐:从生成私钥、创建CSR到提交CA签名,每一步都需要人工干预。
  • 续期管理困难:证书过期后需手动替换,容易因疏忽导致服务中断。
  • 缺乏标准化流程:不同团队可能采用不同的工具链,难以统一管理。

mTLS示意图

技术选型:为什么选择acme.sh?

在自动化证书管理工具中,Certbot和acme.sh是最流行的两个选择。以下是它们的对比:

  • Certbot:功能全面,但依赖Python环境,配置复杂。
  • acme.sh:纯Shell实现,轻量级,支持所有ACME v2协议,API设计简洁。

acme.sh的核心优势:

  1. 零依赖:仅需Bash环境,适合容器化部署。
  2. 多CA支持:除了Let's Encrypt,还支持Buypass、ZeroSSL等。
  3. 自动化程度高:内置证书续期和部署钩子。

实现细节

安装acme.sh

# 一键安装(默认使用Let's Encrypt)
curl https://get.acme.sh | sh -s email=your@email.com

申请客户端证书

mTLS需要服务端和客户端双证书。以下是关键命令:

# 生成服务端证书
acme.sh --issue -d api.yourdomain.com --dns dns_cf \
  --server letsencrypt --keylength ec-256

# 生成客户端证书(需额外指定客户端标识)
acme.sh --issue -d client.device1.yourdomain.com \
  --dns dns_cf --server letsencrypt --keylength ec-256

完整Bash脚本示例

#!/bin/bash
# 错误时退出并记录日志
set -eo pipefail
LOG_FILE="/var/log/acme_mtls.log"

echo "[$(date)] Starting mTLS cert renewal" >> $LOG_FILE

# 使用Cloudflare DNS验证(需提前设置API密钥)
export CF_Key="your_cloudflare_api_key"
export CF_Email="admin@yourdomain.com"

DOMAINS=(
  "api.yourdomain.com"
  "client.device1.yourdomain.com"
)

for domain in "${DOMAINS[@]}"; do
  acme.sh --issue -d "$domain" --dns dns_cf \
    --server letsencrypt --keylength ec-256 2>&1 | tee -a $LOG_FILE

  # 将证书复制到Nginx目录(示例)
  acme.sh --install-cert -d "$domain" \
    --key-file /etc/nginx/ssl/${domain}.key \
    --fullchain-file /etc/nginx/ssl/${domain}.pem \
    --reloadcmd "systemctl reload nginx"
done

echo "[$(date)] Renewal completed" >> $LOG_FILE

生产实践

自动更新方案

推荐使用systemd timer(比crontab更可靠):

# /etc/systemd/system/acme-renew.timer
[Unit]
Description=Daily ACME cert renewal

[Timer]
OnCalendar=daily
Persistent=true

[Install]
WantedBy=timers.target

Kubernetes证书热加载

通过ConfigMap和Sidecar实现:

  1. 将acme.sh部署为Sidecar容器
  2. 使用emptyDir共享证书文件
  3. 主容器通过inotify-tools监控证书变化

K8s架构图

避坑指南

ACME协议限流

Let's Encrypt有以下限制(测试时容易触发):

  • 每个域名每周最多签发50张证书
  • 同一IP每小时最多5次新订单

解决方案:

  1. 开发环境使用--staging测试模式
  2. 错误时添加等待重试逻辑

证书链验证

常见错误:unable to get local issuer certificate

解决方法:

# 下载并附加中间证书
wget -O - https://letsencrypt.org/certs/lets-encrypt-r3.pem >> fullchain.pem

安全加固

短期证书最佳实践

  • 证书有效期不超过30天(acme.sh默认90天)
  • 通过--days参数调整:
    acme.sh --issue ... --days 30

私钥存储方案

  • 使用HSM(硬件安全模块)存储根密钥
  • 或通过Vault动态生成临时证书

延伸阅读

  1. RFC8555 - ACME协议规范
  2. acme.sh官方文档

动手挑战

尝试将acme.sh与HashiCorp Vault集成:

  1. 使用Vault的PKI引擎作为内部CA
  2. 通过Vault API自动签发mTLS证书
  3. 实现证书的自动轮换和吊销检查
Logo

音视频技术社区,一个全球开发者共同探讨、分享、学习音视频技术的平台,加入我们,与全球开发者一起创造更加优秀的音视频产品!

更多推荐