2020 年 2 月,Let’s Encrypt 因为一个合规性 bug 被迫在 5 天内撤销 300 万张证书。2021 年 9 月,Let’s Encrypt 的根证书 DST Root CA X3 过期,导致大量老设备和系统无法验证证书。证书看起来只是一个文件,但它背后的 PKI(Public Key Infrastructure,公钥基础设施)体系是整个 HTTPS 安全的信任根基。
证书过期导致的宕机是最常见也最可避免的生产事故。本文从工程视角,系统性地讲解证书的整个生命周期——从结构、签发、部署到监控和轮换。
一、X.509 证书结构
1.1 证书的组成
X.509 是 ITU-T 定义的公钥证书标准,目前广泛使用的是 v3 版本。一张 X.509 证书包含以下核心字段:
X.509 v3 证书结构:
┌─────────────────────────────────────────┐
│ Version: v3 │
├─────────────────────────────────────────┤
│ Serial Number: 唯一标识(CA 内唯一) │
├─────────────────────────────────────────┤
│ Signature Algorithm: sha256WithRSAEncryption │
├─────────────────────────────────────────┤
│ Issuer: 签发者(CA)的 DN │
│ C=US, O=Let's Encrypt, CN=R3 │
├─────────────────────────────────────────┤
│ Validity: │
│ Not Before: 2025-01-01T00:00:00Z │
│ Not After: 2025-03-31T23:59:59Z │
├─────────────────────────────────────────┤
│ Subject: 证书持有者的 DN │
│ CN=example.com │
├─────────────────────────────────────────┤
│ Subject Public Key Info: │
│ Algorithm: RSA / ECDSA │
│ Public Key: (2048/4096 bit RSA 或 │
│ 256/384 bit ECDSA) │
├─────────────────────────────────────────┤
│ Extensions (v3): │
│ Subject Alternative Name (SAN): │
│ DNS: example.com │
│ DNS: www.example.com │
│ DNS: *.example.com │
│ Key Usage: Digital Signature │
│ Extended Key Usage: serverAuth │
│ Basic Constraints: CA:FALSE │
│ Authority Key Identifier: ... │
│ Subject Key Identifier: ... │
│ CRL Distribution Points: ... │
│ Authority Information Access: │
│ OCSP: http://ocsp.example.com │
│ CA Issuers: http://... │
│ Certificate Policies: ... │
│ SCT (Signed Certificate Timestamp): │
│ log1.ct.example.com, ... │
├─────────────────────────────────────────┤
│ Signature: CA 用私钥对以上内容的签名 │
└─────────────────────────────────────────┘
1.2 用 OpenSSL 查看证书
# 查看远程服务器证书
echo | openssl s_client -connect example.com:443 \
-servername example.com 2>/dev/null | \
openssl x509 -noout -text
# 查看本地证书文件
openssl x509 -in cert.pem -noout -text
# 只看关键信息
openssl x509 -in cert.pem -noout \
-subject -issuer -dates -serial \
-ext subjectAltName
# 输出示例:
# subject=CN = example.com
# issuer=C = US, O = Let's Encrypt, CN = R3
# notBefore=Jan 1 00:00:00 2025 GMT
# notAfter=Mar 31 23:59:59 2025 GMT
# serial=0A:1B:2C:3D:4E:5F:6A:7B:8C:9D
# X509v3 Subject Alternative Name:
# DNS:example.com, DNS:www.example.com
# 查看证书指纹(用于证书固定)
openssl x509 -in cert.pem -noout -fingerprint -sha256
# SHA256 Fingerprint=AB:CD:EF:...
# 验证证书链
openssl verify -CAfile chain.pem cert.pem
# cert.pem: OK1.3 证书编码格式
证书文件格式:
PEM (Privacy Enhanced Mail):
- Base64 编码的文本格式
- 以 -----BEGIN CERTIFICATE----- 开头
- 最常用的格式
- 文件扩展名: .pem, .crt, .cer
DER (Distinguished Encoding Rules):
- 二进制格式
- PEM 是 DER 的 Base64 编码
- Java KeyStore 使用 DER
- 文件扩展名: .der, .cer
PKCS#12 / PFX:
- 包含证书 + 私钥的容器格式
- 通常有密码保护
- Windows / IIS 常用
- 文件扩展名: .p12, .pfx
# 格式转换
# PEM → DER
openssl x509 -in cert.pem -outform DER -out cert.der
# DER → PEM
openssl x509 -in cert.der -inform DER -outform PEM -out cert.pem
# PEM 证书 + 私钥 → PKCS#12
openssl pkcs12 -export -out cert.p12 \
-inkey key.pem -in cert.pem -certfile chain.pem
# PKCS#12 → PEM
openssl pkcs12 -in cert.p12 -out all.pem -nodes二、PKI 信任链
2.1 信任链的结构
PKI 信任链 (Certificate Chain):
┌──────────────┐
│ 根 CA │ ← 自签名,预装在操作系统/浏览器中
│ (Root CA) │ 有效期: 20-30 年
│ 离线存储 │ 全球约 150 个根 CA
└──────┬───────┘
│ 签发
v
┌──────────────┐
│ 中间 CA │ ← 由根 CA 签发
│(Intermediate) │ 有效期: 5-10 年
│ 在线运行 │ 实际签发证书的实体
└──────┬───────┘
│ 签发
v
┌──────────────┐
│ 叶子证书 │ ← 由中间 CA 签发
│ (Leaf/End │ 有效期: 90 天 (Let's Encrypt)
│ Entity) │ 或 398 天 (商业 CA)
│ 你的服务器 │
└──────────────┘
2.2 证书验证流程
客户端验证服务器证书的完整流程:
1. 接收证书链
服务器发送: [叶子证书] + [中间 CA 证书]
(不发送根 CA 证书——客户端本地已有)
2. 构建信任链
叶子证书.Issuer → 中间 CA.Subject ✓
中间 CA.Issuer → 根 CA.Subject ✓ (本地查找)
3. 验证签名链
用中间 CA 的公钥验证叶子证书的签名 ✓
用根 CA 的公钥验证中间 CA 的签名 ✓
4. 检查有效期
每张证书: notBefore ≤ 当前时间 ≤ notAfter ✓
5. 检查域名匹配
请求的域名必须匹配证书的 SAN 或 CN
*.example.com 匹配 www.example.com
但不匹配 example.com 本身
也不匹配 sub.www.example.com
6. 检查吊销状态
CRL (Certificate Revocation List): 下载完整吊销列表
OCSP (Online Certificate Status Protocol): 实时查询
OCSP Stapling: 服务器预取 OCSP 响应
7. 检查证书用途
Key Usage: digitalSignature
Extended Key Usage: serverAuth (TLS 服务器证书)
Basic Constraints: CA:FALSE (叶子证书)
# 验证证书链的完整性
openssl verify -show_chain \
-CAfile /etc/ssl/certs/ca-certificates.crt \
-untrusted intermediate.pem \
server.pem
# 检查服务器返回的证书链
openssl s_client -connect example.com:443 \
-servername example.com -showcerts 2>/dev/null | \
grep -E "s:|i:|depth"
# depth=0: 叶子证书
# depth=1: 中间 CA
# depth=2: 根 CA (有时不包含)
# 常见错误: 服务器没有发送中间 CA 证书
# → 部分客户端(特别是移动端)无法验证证书
# 检查方法:
openssl s_client -connect example.com:443 \
-servername example.com 2>&1 | \
grep "Verify return code"
# 21 (unable to verify the first certificate)
# → 缺少中间 CA 证书2.3 根 CA 信任存储
# 各平台的根 CA 信任存储位置
# Linux (Debian/Ubuntu)
ls /etc/ssl/certs/
# 或
ls /usr/share/ca-certificates/
# Linux (RHEL/CentOS)
ls /etc/pki/tls/certs/
# macOS
# 系统偏好设置 → 钥匙串访问 → 系统根证书
# 查看系统信任的根 CA 数量
awk -v cmd='openssl x509 -noout -subject' \
'/BEGIN/{close(cmd)};{print | cmd}' \
/etc/ssl/certs/ca-certificates.crt 2>/dev/null | \
wc -l
# 约 130-150 个根 CA
# Java 的信任存储 (cacerts)
keytool -list -keystore "$JAVA_HOME/lib/security/cacerts" \
-storepass changeit 2>/dev/null | grep -c "trustedCertEntry"三、证书签发
3.1 CSR(Certificate Signing Request)
# 生成 RSA 密钥对和 CSR
openssl req -new -newkey rsa:2048 -nodes \
-keyout server.key -out server.csr \
-subj "/CN=example.com"
# 生成 ECDSA 密钥对和 CSR(推荐)
openssl ecparam -genkey -name prime256v1 -out server.key
openssl req -new -key server.key -out server.csr \
-subj "/CN=example.com"
# 带 SAN 的 CSR(多域名证书)
openssl req -new -key server.key -out server.csr \
-subj "/CN=example.com" \
-addext "subjectAltName=DNS:example.com,DNS:www.example.com,DNS:api.example.com"
# 查看 CSR 内容
openssl req -in server.csr -noout -text
# CSR 包含:
# - 公钥(从密钥对中提取)
# - 请求的 Subject(域名等)
# - 请求的扩展(SAN 等)
# - 请求者的签名(证明持有私钥)
# CSR 不包含私钥——私钥永远不应离开服务器3.2 证书类型
| 验证级别 | 缩写 | 验证内容 | 签发时间 | 价格 | 适用场景 |
|---|---|---|---|---|---|
| 域名验证 | DV | 域名所有权 | 分钟级 | 免费-$10 | 个人/小型网站 |
| 组织验证 | OV | 域名 + 组织信息 | 1-3 天 | $50-$200 | 企业网站 |
| 扩展验证 | EV | 域名 + 组织 + 法律实体 | 1-2 周 | $200-$1000 | 金融/政务 |
DV 证书的验证方式(三选一):
1. HTTP 验证 (http-01)
CA 要求你在网站放置一个特定文件:
http://example.com/.well-known/acme-challenge/<token>
→ 证明你控制了这个域名的 Web 服务器
2. DNS 验证 (dns-01)
CA 要求你添加一个 DNS TXT 记录:
_acme-challenge.example.com → <验证值>
→ 证明你控制了这个域名的 DNS
→ 支持通配符证书(*.example.com)
3. TLS-ALPN 验证 (tls-alpn-01)
CA 通过 TLS 连接验证:
在 443 端口提供包含验证令牌的自签名证书
→ 证明你控制了这个域名的 TLS 端口
四、ACME 协议与 Let’s Encrypt
4.1 ACME 协议概述
ACME(Automatic Certificate Management Environment,RFC 8555)是 Let’s Encrypt 设计的证书自动化管理协议。
ACME 协议流程:
客户端 (certbot) ACME 服务器 (Let's Encrypt)
│ │
├── POST /acme/new-account ───────────→│ 1. 注册账号
│←── 201 Created (account URL) ────────┤
│ │
├── POST /acme/new-order ─────────────→│ 2. 创建订单
│ { identifiers: [{type:"dns", │ (指定要签发的域名)
│ value:"example.com"}] } │
│←── 201 Created (order URL + │
│ authorizations URLs) ────────────┤
│ │
├── POST /acme/authz/xxx ─────────────→│ 3. 获取验证要求
│←── 200 (challenges: http-01, │
│ dns-01, tls-alpn-01) ────────────┤
│ │
│ [放置验证文件或 DNS 记录] │
│ │
├── POST /acme/challenge/xxx ─────────→│ 4. 请求验证
│←── 200 (status: processing) ─────────┤
│ │
│ [CA 访问验证 URL / DNS] │
│ │
├── POST /acme/authz/xxx ─────────────→│ 5. 检查验证状态
│←── 200 (status: valid) ──────────────┤
│ │
├── POST /acme/order/xxx/finalize ────→│ 6. 提交 CSR
│ { csr: <Base64URL-encoded CSR> } │
│←── 200 (status: valid, │
│ certificate URL) ────────────────┤
│ │
├── POST /acme/cert/xxx ──────────────→│ 7. 下载证书
│←── 200 (证书链 PEM) ────────────────┤
4.2 Certbot 部署实战
# 安装 Certbot
# Debian/Ubuntu
apt-get install certbot
# 方式一: Standalone 模式(临时启动 Web 服务器)
# 需要 80 端口空闲
certbot certonly --standalone \
-d example.com -d www.example.com \
--email admin@example.com --agree-tos
# 方式二: Webroot 模式(使用已有 Web 服务器)
certbot certonly --webroot \
-w /var/www/html \
-d example.com -d www.example.com
# 方式三: Nginx 插件(自动配置 Nginx)
certbot --nginx -d example.com
# 方式四: DNS 验证(通配符证书)
certbot certonly --manual \
--preferred-challenges dns \
-d "*.example.com" -d example.com
# 证书文件位置
ls /etc/letsencrypt/live/example.com/
# cert.pem ← 服务器证书
# chain.pem ← 中间 CA 证书
# fullchain.pem ← cert.pem + chain.pem(Nginx 使用这个)
# privkey.pem ← 私钥
# 查看证书信息
certbot certificates
# Certificate Name: example.com
# Domains: example.com www.example.com
# Expiry Date: 2025-04-01 (VALID: 89 days)
# Certificate Path: /etc/letsencrypt/live/example.com/fullchain.pem
# 手动续期
certbot renew --dry-run # 测试续期
certbot renew # 实际续期
# 自动续期(systemd timer 或 cron)
# certbot 安装时通常已配置自动续期
systemctl list-timers | grep certbot
# 或
cat /etc/cron.d/certbot4.3 DNS 自动化验证
手动 DNS 验证不适合自动化。对于通配符证书或大规模部署,需要 DNS API 集成:
# 使用 Cloudflare DNS 插件自动验证
pip install certbot-dns-cloudflare
# 配置 Cloudflare API 凭证
cat > /etc/letsencrypt/cloudflare.ini << 'EOF'
dns_cloudflare_api_token = your-api-token-here
EOF
chmod 600 /etc/letsencrypt/cloudflare.ini
# 签发通配符证书
certbot certonly \
--dns-cloudflare \
--dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini \
-d "*.example.com" -d example.com
# 支持的 DNS 提供商插件:
# certbot-dns-cloudflare
# certbot-dns-route53 (AWS)
# certbot-dns-google (GCP)
# certbot-dns-digitalocean
# certbot-dns-dnspod (腾讯云)
# certbot-dns-aliyun (阿里云, 第三方)五、私有 CA
5.1 为什么需要私有 CA
使用私有 CA 的场景:
1. 内部服务间通信(mTLS)
- 微服务之间的双向认证
- 不需要(也不应该)用公共 CA
2. 开发/测试环境
- 本地开发需要 HTTPS
- 不想为内部域名购买证书
3. IoT 设备
- 设备出厂预装私有 CA 根证书
- 设备连接使用私有 CA 签发的证书
4. 合规要求
- 某些行业要求自建 PKI
- 完全控制证书的签发和吊销
5.2 使用 OpenSSL 搭建私有 CA
# 创建 CA 目录结构
mkdir -p /opt/ca/{root,intermediate}/{certs,crl,newcerts,private,csr}
touch /opt/ca/root/index.txt /opt/ca/intermediate/index.txt
echo 1000 > /opt/ca/root/serial
echo 1000 > /opt/ca/intermediate/serial
# 1. 生成根 CA 密钥和证书
openssl genrsa -aes256 -out /opt/ca/root/private/ca.key 4096
# 输入密码保护私钥
openssl req -new -x509 -days 7300 \
-key /opt/ca/root/private/ca.key \
-out /opt/ca/root/certs/ca.crt \
-subj "/C=CN/O=MyOrg/CN=MyOrg Root CA"
# 2. 生成中间 CA 密钥和 CSR
openssl genrsa -aes256 -out /opt/ca/intermediate/private/intermediate.key 4096
openssl req -new \
-key /opt/ca/intermediate/private/intermediate.key \
-out /opt/ca/intermediate/csr/intermediate.csr \
-subj "/C=CN/O=MyOrg/CN=MyOrg Intermediate CA"
# 3. 用根 CA 签发中间 CA 证书
openssl x509 -req -days 3650 \
-in /opt/ca/intermediate/csr/intermediate.csr \
-CA /opt/ca/root/certs/ca.crt \
-CAkey /opt/ca/root/private/ca.key \
-CAcreateserial \
-out /opt/ca/intermediate/certs/intermediate.crt \
-extfile <(echo -e "basicConstraints=critical,CA:TRUE,pathlen:0\nkeyUsage=critical,digitalSignature,keyCertSign,cRLSign")
# 4. 签发服务器证书
openssl genrsa -out /opt/ca/intermediate/private/server.key 2048
openssl req -new \
-key /opt/ca/intermediate/private/server.key \
-out /opt/ca/intermediate/csr/server.csr \
-subj "/CN=myapp.internal"
openssl x509 -req -days 365 \
-in /opt/ca/intermediate/csr/server.csr \
-CA /opt/ca/intermediate/certs/intermediate.crt \
-CAkey /opt/ca/intermediate/private/intermediate.key \
-CAcreateserial \
-out /opt/ca/intermediate/certs/server.crt \
-extfile <(echo -e "subjectAltName=DNS:myapp.internal,DNS:*.myapp.internal\nextendedKeyUsage=serverAuth\nbasicConstraints=CA:FALSE")
# 5. 构建完整证书链
cat /opt/ca/intermediate/certs/server.crt \
/opt/ca/intermediate/certs/intermediate.crt \
> /opt/ca/intermediate/certs/server-fullchain.crt
# 验证
openssl verify -CAfile /opt/ca/root/certs/ca.crt \
-untrusted /opt/ca/intermediate/certs/intermediate.crt \
/opt/ca/intermediate/certs/server.crt
# server.crt: OK5.3 使用 step-ca 搭建生产级私有 CA
OpenSSL 手动管理 CA 适合学习,但生产环境推荐使用 step-ca(Smallstep)——它提供 ACME 服务器、自动续期、短期证书等现代特性。
# 安装 step CLI 和 step-ca
# https://smallstep.com/docs/step-ca/installation
# 初始化 CA
step ca init --name "MyOrg CA" \
--dns ca.myorg.internal \
--address :8443 \
--provisioner admin
# 启动 CA 服务器
step-ca $(step path)/config/ca.json
# 签发证书
step ca certificate myapp.internal \
server.crt server.key \
--ca-url https://ca.myorg.internal:8443
# step-ca 支持 ACME 协议
# 内部服务可以用 certbot 对接私有 CA
certbot certonly --standalone \
--server https://ca.myorg.internal:8443/acme/acme/directory \
-d myapp.internal六、Kubernetes 中的证书管理
6.1 cert-manager 架构
cert-manager 架构:
┌────────────────────────────────────────────────────┐
│ Kubernetes Cluster │
│ │
│ ┌─────────────┐ ┌──────────────┐ │
│ │ Certificate │────→│ cert-manager │ │
│ │ (CR) │ │ controller │ │
│ └─────────────┘ └──────┬───────┘ │
│ │ │
│ ┌────────┼────────┐ │
│ ↓ ↓ ↓ │
│ ┌──────────┐ ┌──────┐ ┌──────┐ │
│ │ Issuer │ │ ACME │ │ Self │ │
│ │ (CA/Vault)│ │ │ │Signed│ │
│ └──────────┘ └──┬───┘ └──────┘ │
│ │ │
│ │ ACME 协议 │
└───────────────────────────────┼─────────────────────┘
│
↓
┌──────────────┐
│Let's Encrypt │
│ ACME Server │
└──────────────┘
6.2 cert-manager 部署
# 安装 cert-manager
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.14.0/cert-manager.yaml
# 等待 Pod 就绪
kubectl -n cert-manager get pods -w# ClusterIssuer 配置 (Let's Encrypt)
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# Certificate 资源
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: example-com-tls
namespace: default
spec:
secretName: example-com-tls-secret
issuerRef:
name: letsencrypt-prod
kind: ClusterIssuer
dnsNames:
- example.com
- www.example.com
duration: 2160h # 90 天
renewBefore: 720h # 到期前 30 天自动续期# Ingress 中使用证书
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-ingress
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
tls:
- hosts:
- example.com
- www.example.com
secretName: example-com-tls-secret
rules:
- host: example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web
port:
number: 80# 查看证书状态
kubectl get certificates
# NAME READY SECRET AGE
# example-com-tls True example-com-tls-secret 5m
# 查看证书详情
kubectl describe certificate example-com-tls
# 查看 CertificateRequest
kubectl get certificaterequest
# 手动触发续期
kubectl cert-manager renew example-com-tls七、证书监控与告警
7.1 证书过期监控脚本
#!/bin/bash
# cert_monitor.sh — 批量检查证书过期时间
# 用法: ./cert_monitor.sh domains.txt
WARN_DAYS=30
CRIT_DAYS=7
DOMAINS_FILE="${1:?Usage: $0 domains.txt}"
echo "=== 证书过期检查 $(date '+%Y-%m-%d %H:%M') ==="
while IFS= read -r domain; do
[[ -z "$domain" || "$domain" == \#* ]] && continue
# 获取证书过期时间
expiry=$(echo | timeout 5 openssl s_client \
-connect "$domain:443" -servername "$domain" \
2>/dev/null | \
openssl x509 -noout -enddate 2>/dev/null | \
cut -d= -f2)
if [[ -z "$expiry" ]]; then
echo "ERROR $domain — 无法获取证书"
continue
fi
# 计算剩余天数
expiry_epoch=$(date -d "$expiry" +%s 2>/dev/null)
now_epoch=$(date +%s)
days_left=$(( (expiry_epoch - now_epoch) / 86400 ))
# 状态判断
if [[ $days_left -lt 0 ]]; then
echo "EXPIRED $domain — 已过期 $((-days_left)) 天"
elif [[ $days_left -lt $CRIT_DAYS ]]; then
echo "CRITICAL $domain — 还剩 ${days_left} 天 (到期: $expiry)"
elif [[ $days_left -lt $WARN_DAYS ]]; then
echo "WARNING $domain — 还剩 ${days_left} 天 (到期: $expiry)"
else
echo "OK $domain — 还剩 ${days_left} 天"
fi
done < "$DOMAINS_FILE"7.2 Prometheus 证书监控
# Blackbox Exporter 配置
# /etc/blackbox_exporter/config.yml
modules:
tls_check:
prober: tcp
timeout: 5s
tcp:
tls: true
tls_config:
insecure_skip_verify: false# Prometheus 采集配置
# prometheus.yml
scrape_configs:
- job_name: 'ssl_expiry'
metrics_path: /probe
params:
module: [tls_check]
static_configs:
- targets:
- example.com:443
- api.example.com:443
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: blackbox-exporter:9115# Prometheus 告警规则
# 证书 30 天内过期 → Warning
# 证书 7 天内过期 → Critical
groups:
- name: ssl_expiry
rules:
- alert: SSLCertExpiringSoon
expr: probe_ssl_earliest_cert_expiry - time() < 86400 * 30
for: 1h
labels:
severity: warning
annotations:
summary: "证书即将过期: {{ $labels.instance }}"
description: "剩余 {{ $value | humanizeDuration }}"
- alert: SSLCertExpiringCritical
expr: probe_ssl_earliest_cert_expiry - time() < 86400 * 7
for: 10m
labels:
severity: critical
annotations:
summary: "证书即将过期: {{ $labels.instance }}"
description: "剩余 {{ $value | humanizeDuration }},立即续期!"
八、RSA vs ECDSA 证书选型
| 特性 | RSA 2048 | RSA 4096 | ECDSA P-256 | ECDSA P-384 |
|---|---|---|---|---|
| 等效安全强度 | 112 bit | 128+ bit | 128 bit | 192 bit |
| 公钥大小 | 256 bytes | 512 bytes | 64 bytes | 96 bytes |
| 签名大小 | 256 bytes | 512 bytes | 64 bytes | 96 bytes |
| TLS 握手性能 | 基准 | 慢 2-3 倍 | 快 2-5 倍 | 快 1-3 倍 |
| 兼容性 | 最广 | 广 | 良好 | 良好 |
| 推荐 | 兼容性优先 | 非必要 | 新部署首选 | 高安全场景 |
# 生成 ECDSA 密钥对(推荐 P-256)
openssl ecparam -genkey -name prime256v1 | \
openssl ec -out ecdsa.key
# 对比 RSA 和 ECDSA 的签名性能
openssl speed rsa2048 ecdsap256
# rsa 2048 bits: sign: 1200/s verify: 42000/s
# ecdsa P-256: sign: 35000/s verify: 12000/s
# → ECDSA 签名快 29 倍(TLS 握手中服务器签名)
# → RSA 验证快 3.5 倍(TLS 握手中客户端验证)
# → 综合考虑,ECDSA 在握手中更高效
# Let's Encrypt 支持 ECDSA 证书
certbot certonly --standalone \
-d example.com \
--key-type ecdsa --elliptic-curve secp256r1九、证书轮换的工程实践
9.1 自动续期的可靠性保障
# 续期失败的常见原因和排查
# 1. 80 端口被占用(Standalone 模式)
ss -tlnp | grep :80
# → 需要临时停止 Web 服务器或使用 Webroot 模式
# 2. DNS 解析问题(DNS 验证模式)
dig _acme-challenge.example.com TXT
# → 检查 DNS API 权限和网络连通性
# 3. 防火墙阻断
# Let's Encrypt 的验证服务器需要访问你的 80/443 端口
# 检查是否有 IP 白名单限制
# 4. 续期后未重载服务
# certbot 支持 deploy hook
certbot renew --deploy-hook "systemctl reload nginx"
# 5. 配置 Cron 定时续期
# 每天凌晨 2 点检查并续期
0 2 * * * certbot renew --quiet --deploy-hook "systemctl reload nginx"
# 验证续期流程
certbot renew --dry-run --verbose9.2 零停机证书轮换
# Nginx 零停机证书轮换
# 1. 更新证书文件(certbot renew 已完成)
# 2. 热重载 Nginx(不中断现有连接)
nginx -t && nginx -s reload
# 或使用 systemctl
nginx -t && systemctl reload nginx
# 验证新证书已生效
echo | openssl s_client -connect localhost:443 \
-servername example.com 2>/dev/null | \
openssl x509 -noout -dates
# 确认 notAfter 是新的日期十、总结
证书管理看起来简单,但它是整个 HTTPS 安全链中最容易出错的环节:
自动化是唯一正确的答案。 手动管理证书必然导致过期——这不是”会不会”的问题,是”什么时候”。ACME 协议 + certbot/cert-manager 让证书的签发和续期完全自动化。如果你的证书还是手动管理的,这是最优先需要改进的事项。
证书链必须完整。 服务器必须发送叶子证书和中间 CA 证书。缺少中间 CA 是最常见的部署错误之一——桌面浏览器可能通过 AIA(Authority Information Access)自动下载中间 CA,但移动设备和命令行工具通常不会。
ECDSA 证书应成为新部署的默认选择。 P-256 ECDSA 证书的公钥只有 64 字节(RSA-2048 是 256 字节),签名速度快 29 倍。更小的证书意味着更少的网络传输,更快的签名意味着更低的 CPU 开销。
监控先于一切。 在证书过期之前 30 天就应该触发告警。用 Blackbox Exporter + Prometheus 对所有外部端点做证书监控。用脚本定期检查内部服务的证书。
私有 CA 用 step-ca,不要手动 OpenSSL。 手动用 OpenSSL 管理 CA 适合理解原理,但生产环境需要 ACME 支持、自动续期、审计日志——step-ca 提供了这些开箱即用的能力。
下一篇我们进入 mTLS 工程实践——服务间双向认证的证书分发挑战、SPIFFE/SPIRE 的身份模型,以及 Service Mesh 中 mTLS 的落地方案。
上一篇:TLS 1.3 工程实践:1-RTT 与 0-RTT 的安全权衡
同主题继续阅读
把当前热点继续串成多页阅读,而不是停在单篇消费。
【网络工程】CDN 与 HTTPS:边缘 TLS、证书管理与安全
CDN 的 HTTPS 部署涉及边缘 TLS 终止、证书托管、回源加密等多个工程环节。本文系统拆解 CDN HTTPS 的架构模式、证书管理方案、安全最佳实践与常见故障排查方法。
【网络工程】mTLS 工程实践:服务间双向认证
mTLS(双向 TLS)在微服务架构中实现服务间的身份认证和通信加密。本文从工程角度剖析 mTLS 的握手流程差异、证书分发的三种模式、SPIFFE/SPIRE 的标准化身份框架,以及 Istio 和 Linkerd 中 mTLS 的实现原理。覆盖性能开销测量、调试方法和大规模部署的证书轮换策略。
【网络工程】反向代理模式:TLS 终止、透传与重加密
系统解剖反向代理的三种 TLS 处理模式——终止、透传与重加密。从架构对比到 SNI 路由、证书管理、性能影响与安全权衡,给出生产环境的工程选型依据。
【网络工程】加密 DNS:DoH、DoT 与 DoQ 的工程部署
DNS 明文传输让运营商、WiFi 热点运营者和网络中间人能够窃听和篡改 DNS 查询。DoH、DoT、DoQ 三种加密 DNS 协议各自解决了不同场景的需求。本文对比三种协议的技术细节、性能差异和部署方式,分析企业环境中加密 DNS 的选型决策与落地实践。