土法炼钢兴趣小组的算法知识备份

【系统架构设计百科】密钥管理与证书体系:PKI 的工程实践

文章导航

分类入口
architecture
标签入口
#PKI#certificate#ACME#Let-Encrypt#HSM#key-management

目录

2020 年 2 月,一家全球 CDN 服务商因为一张中间证书过期,导致数千个下游站点在 30 分钟内同时不可访问。事后的根因分析只有一行字:证书有效期到了,没人续。2023 年,某大型云厂商因为内部 mTLS 证书轮转失败,微服务之间的通信全部中断,影响了数百万用户的订单流程。

这些事故不是因为 PKI(Public Key Infrastructure,公钥基础设施)的概念有多复杂,也不是因为工具不够成熟。问题在于:大多数团队把证书当成一次性的运维任务——申请、安装、然后忘记它,直到它过期。

证书管理的核心挑战是生命周期管理:谁负责签发?什么时候轮转?过期了怎么发现?私钥存在哪里?撤销了怎么通知?这些问题中的每一个,如果没有自动化的答案,就是一颗定时炸弹。

本文要回答一个具体的问题:如何建立自动化的证书生命周期管理,彻底消除证书过期导致的宕机?

上一篇中,我们讨论了加密架构的整体设计。本文聚焦于加密体系中最容易在生产环境出问题的部分——密钥与证书的管理。


一、问题场景

1.1 证书过期事故的典型模式

证书过期事故几乎总是遵循同一个模式:

  1. 团队在项目上线时手动申请了证书,有效期一到三年。
  2. 证书信息记录在某个运维文档或者工单系统中,但没有人定期检查。
  3. 一年或两年后,负责申请证书的人已经离职或转岗。
  4. 证书过期,TLS 握手失败,用户看到浏览器警告页面,或者服务之间的 mTLS(mutual TLS,双向 TLS)连接直接断开。
  5. 运维团队紧急手动续期,但因为不熟悉流程,可能更新了错误的证书、遗漏了某些节点、或者忘了重启服务。

这个模式的根因不是”人的疏忽”,而是流程依赖人的记忆。任何依赖人类记忆的运维流程,在足够长的时间线上都会失败。

1.2 证书管理的规模问题

在传统架构中,一个组织可能只有几十张证书——几个域名的 TLS 证书加上一些内部系统的证书。但在微服务架构和零信任网络(Zero Trust Network)中,每个服务实例都需要自己的身份证书,证书数量可能达到数万甚至数十万。

架构类型 证书数量级 有效期 管理方式
传统单体 10 - 100 1 - 3 年 手动 / 电子表格
微服务 1,000 - 10,000 天 - 月 半自动
零信任 / 服务网格 10,000 - 100,000+ 小时 - 天 全自动

当证书数量达到上千张时,手动管理已经不可能。当有效期缩短到小时级别时,人工干预的窗口根本不存在。自动化不是”有了更好”——它是唯一可行的方案。

1.3 密钥泄露的后果

证书管理的另一面是私钥保护。如果私钥被泄露:

因此,密钥管理和证书管理是一枚硬币的两面,必须一起设计。


二、PKI 基础架构

2.1 信任模型

PKI 的核心是信任链(Chain of Trust)。信任从根证书颁发机构(Root CA)开始,逐级向下传递:

Root CA(根 CA)
  └── Intermediate CA(中间 CA)
        └── Leaf Certificate(叶子证书 / 终端实体证书)

为什么需要中间 CA?因为根 CA 的私钥极其重要,一旦泄露就意味着整个 PKI 体系崩溃。因此根 CA 通常是离线的(air-gapped,物理隔离),只在签发中间 CA 证书时使用。日常的证书签发由中间 CA 完成。即使中间 CA 被攻破,只需要撤销该中间 CA 的证书,根 CA 仍然安全。

2.2 证书链验证

当客户端(比如浏览器)收到服务器的证书时,验证过程如下:

  1. 检查叶子证书的签名:用中间 CA 的公钥验证叶子证书的数字签名。
  2. 检查中间 CA 的签名:用根 CA 的公钥验证中间 CA 证书的签名。
  3. 检查根 CA 是否在本地信任库中:操作系统和浏览器内置了一组受信任的根 CA 证书。
  4. 检查证书的有效期、域名匹配、扩展属性等。

如果链中任何一环验证失败,TLS 握手就会被拒绝。

2.3 X.509 证书结构

X.509 是最广泛使用的证书标准。一张证书包含以下关键字段:

Certificate:
    Version: v3
    Serial Number: 04:a3:b2:...
    Signature Algorithm: sha256WithRSAEncryption
    Issuer: CN=Example Intermediate CA, O=Example Inc
    Validity:
        Not Before: 2026-01-01 00:00:00 UTC
        Not After:  2026-04-01 00:00:00 UTC
    Subject: CN=api.example.com
    Subject Public Key Info:
        Algorithm: id-ecPublicKey (P-256)
        Public Key: 04:ab:cd:...
    X509v3 Extensions:
        Subject Alternative Name:
            DNS:api.example.com
            DNS:*.api.example.com
        Key Usage: Digital Signature
        Extended Key Usage: TLS Web Server Authentication
        Authority Information Access:
            OCSP - URI:http://ocsp.example.com
            CA Issuers - URI:http://ca.example.com/intermediate.crt
        CRL Distribution Points:
            URI:http://crl.example.com/intermediate.crl

几个值得注意的字段:


三、证书生命周期

证书从生成到废弃,经历五个阶段:

3.1 生成(Generation)

生成证书的流程:

  1. 生成密钥对(私钥和公钥)。
  2. 创建证书签名请求(CSR,Certificate Signing Request),包含公钥和主体信息。
  3. 将 CSR 提交给 CA。
  4. CA 验证请求者的身份,签发证书。

用 OpenSSL 生成 CSR 的示例:

# 生成 ECDSA P-256 私钥
openssl ecparam -genkey -name prime256v1 -out server.key

# 基于私钥创建 CSR
openssl req -new -key server.key \
  -out server.csr \
  -subj "/CN=api.example.com/O=Example Inc"

# 查看 CSR 内容
openssl req -in server.csr -text -noout

3.2 分发(Distribution)

签发的证书需要部署到目标服务器。分发方式取决于架构:

3.3 续期(Renewal)

续期是证书生命周期中最容易出错的环节。最佳实践:

3.4 撤销(Revocation)

当私钥泄露或证书信息有误时,需要撤销证书。有三种机制:

CRL(Certificate Revocation List,证书撤销列表)

CA 定期发布一份包含所有已撤销证书序列号的列表。客户端下载这份列表来检查证书是否被撤销。

缺点:CRL 文件可能很大(数 MB),更新频率低(通常每小时到每天),客户端需要缓存和定期下载。

OCSP(Online Certificate Status Protocol,在线证书状态协议)

客户端向 OCSP 响应器(OCSP Responder)发送实时查询,询问某张证书是否被撤销。

缺点:增加了 TLS 握手的延迟(需要额外的网络请求),且暴露了用户正在访问哪些网站(隐私问题)。

OCSP Stapling(OCSP 装订)

服务器预先从 OCSP 响应器获取自己证书的状态响应,并在 TLS 握手时将响应”装订”在证书上一起发给客户端。客户端无需额外请求。

# Nginx 启用 OCSP Stapling 配置
server {
    listen 443 ssl;
    server_name api.example.com;

    ssl_certificate     /etc/ssl/certs/api.example.com.crt;
    ssl_certificate_key /etc/ssl/private/api.example.com.key;

    # 启用 OCSP Stapling
    ssl_stapling on;
    ssl_stapling_verify on;
    ssl_trusted_certificate /etc/ssl/certs/ca-chain.crt;
    resolver 8.8.8.8 8.8.4.4 valid=300s;
    resolver_timeout 5s;
}

3.5 废弃(Retirement)

证书过期后,相关的密钥材料应该被安全销毁。但需要注意:如果有使用该证书加密的数据尚未解密,销毁私钥意味着数据永久丢失。因此密钥的保留策略需要与数据保留策略对齐。


四、ACME 协议与自动化

4.1 ACME 协议概述

ACME(Automatic Certificate Management Environment,自动化证书管理环境)是由 ISRG(Internet Security Research Group)设计的协议,最初为 Let’s Encrypt 开发,现已成为 IETF 标准(RFC 8555)。

ACME 的核心思想是:用自动化的域名控制权验证替代传统的人工审核。如果你能证明你控制了某个域名,CA 就自动签发证书。

4.2 ACME 协议流程

以下是 ACME 协议的完整交互流程:

sequenceDiagram
    participant Client as ACME 客户端
    participant Server as ACME 服务器(CA)
    participant DNS as DNS 服务器
    participant Web as Web 服务器

    Note over Client,Server: 第一步:账户注册
    Client->>Server: POST /acme/new-account(公钥,联系方式)
    Server-->>Client: 201 Created(账户 URL)

    Note over Client,Server: 第二步:创建订单
    Client->>Server: POST /acme/new-order(域名列表)
    Server-->>Client: 201 Created(订单 URL,授权 URL 列表)

    Note over Client,Server: 第三步:获取挑战
    Client->>Server: GET 授权 URL
    Server-->>Client: 200 OK(挑战列表:HTTP-01 / DNS-01)

    Note over Client,Server: 第四步:完成挑战(DNS-01 示例)
    Client->>DNS: 创建 TXT 记录 _acme-challenge.example.com
    Client->>Server: POST 挑战 URL(通知已就绪)
    Server->>DNS: 查询 TXT 记录验证域名控制权
    Server-->>Client: 200 OK(挑战状态:valid)

    Note over Client,Server: 第五步:提交 CSR
    Client->>Server: POST finalize URL(CSR)
    Server-->>Client: 200 OK(证书 URL)

    Note over Client,Server: 第六步:下载证书
    Client->>Server: GET 证书 URL
    Server-->>Client: 200 OK(完整证书链)

4.3 HTTP-01 vs DNS-01 挑战

ACME 协议支持多种域名控制权验证方式,最常用的是 HTTP-01 和 DNS-01。

HTTP-01 挑战

CA 给客户端一个令牌(token),客户端需要在 http://<域名>/.well-known/acme-challenge/<token> 路径下放置一个包含特定内容的文件。CA 通过 HTTP 请求验证该文件存在。

优点: - 实现简单,不需要 DNS API 权限。 - 大多数 ACME 客户端默认支持。

缺点: - 需要服务器的 80 端口可达。 - 不支持通配符证书(wildcard certificate)。 - 每个域名需要单独验证。

DNS-01 挑战

客户端在域名的 DNS 中创建一条 _acme-challenge.<域名> 的 TXT 记录,内容是 CA 指定的验证值。CA 通过 DNS 查询验证。

优点: - 支持通配符证书。 - 不需要 Web 服务器或者 80 端口。 - 可以为内部域名签发公开 CA 的证书。

缺点: - 需要 DNS API 的编程访问权限。 - DNS 传播有延迟,验证可能需要等待。

对比维度 HTTP-01 DNS-01
通配符证书 不支持 支持
端口要求 80 端口可达 无端口要求
DNS API 不需要 需要
内部域名 需要外部可达 只需 DNS 可控
验证速度 快(秒级) 慢(分钟级,DNS 传播)
适用场景 公网 Web 服务器 CDN、通配符、内部服务

4.4 cert-manager 在 Kubernetes 中的集成

cert-manager 是 Kubernetes 生态中最广泛使用的证书管理工具。它将证书管理抽象为 Kubernetes 原生资源(Custom Resource),实现了声明式的证书生命周期管理。

安装 cert-manager

# 使用 Helm 安装 cert-manager
helm repo add jetstack https://charts.jetstack.io
helm repo update

helm install cert-manager jetstack/cert-manager \
  --namespace cert-manager \
  --create-namespace \
  --set crds.enabled=true

配置 Let’s Encrypt 签发器

# cluster-issuer.yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: security@example.com
    privateKeySecretRef:
      name: letsencrypt-prod-account-key
    solvers:
      - http01:
          ingress:
            ingressClassName: nginx
      - dns01:
          cloudDNS:
            project: my-gcp-project
          selector:
            dnsZones:
              - "example.com"

声明证书资源

# certificate.yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: api-tls
  namespace: production
spec:
  secretName: api-tls-secret
  duration: 2160h      # 90 天
  renewBefore: 720h    # 到期前 30 天续期
  issuerRef:
    name: letsencrypt-prod
    kind: ClusterIssuer
  dnsNames:
    - api.example.com
    - "*.api.example.com"
  privateKey:
    algorithm: ECDSA
    size: 256

通过 Ingress 注解自动签发

# ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: api-ingress
  namespace: production
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  ingressClassName: nginx
  tls:
    - hosts:
        - api.example.com
      secretName: api-tls-secret
  rules:
    - host: api.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: api-service
                port:
                  number: 8080

这个配置实现了完全自动化:cert-manager 监听 Ingress 资源的变化,自动通过 ACME 协议向 Let’s Encrypt 申请证书,存储为 Kubernetes Secret,并在到期前自动续期。工程师只需要声明”我需要这个域名的证书”,剩下的全部由 cert-manager 处理。


五、短期证书策略

5.1 为什么证书应该短期化

传统的 TLS 证书有效期通常是一到三年。从 2020 年起,CA/Browser Forum(CA/浏览器论坛)已经将公共证书的最大有效期缩短到 398 天,并且趋势是继续缩短。Let’s Encrypt 的证书有效期只有 90 天。

短期证书的优势:

  1. 缩小攻击窗口。即使私钥被泄露,证书也会在短时间内自然过期,攻击者无法长期利用。
  2. 降低对撤销机制的依赖。CRL 和 OCSP 都有传播延迟和可用性问题。如果证书本身只有几个小时的有效期,撤销的必要性大幅降低。
  3. 强制自动化。当有效期短到无法手动管理时,团队被迫建立自动化流程。而自动化流程一旦建立,反而比手动流程更可靠。
  4. 减少证书管理的认知负担。不需要维护电子表格来跟踪证书过期时间,因为系统自动处理了。

5.2 极短期证书:小时级有效期

在服务网格(Service Mesh)和零信任架构中,证书的有效期可以缩短到小时甚至分钟级别。SPIFFE(Secure Production Identity Framework For Everyone,面向所有人的安全生产身份框架)定义了一种标准的工作负载身份格式——SVID(SPIFFE Verifiable Identity Document,SPIFFE 可验证身份文档)。

SPIFFE 的核心概念:

关于零信任架构中工作负载身份的更多讨论,参见零信任架构一文。

5.3 无停机证书轮转

短期证书的前提是轮转过程不能中断服务。实现无停机轮转的关键技术:

双证书缓冲区

服务同时持有当前证书和下一个证书。新证书在当前证书过期之前签发并加载。TLS 库在握手时使用当前有效的证书。

// Go 语言实现证书热轮转
package main

import (
    "crypto/tls"
    "log"
    "sync"
)

type CertReloader struct {
    mu       sync.RWMutex
    cert     *tls.Certificate
    certPath string
    keyPath  string
}

func (cr *CertReloader) LoadCertificate() error {
    cert, err := tls.LoadX509KeyPair(cr.certPath, cr.keyPath)
    if err != nil {
        return err
    }
    cr.mu.Lock()
    cr.cert = &cert
    cr.mu.Unlock()
    log.Println("证书已重新加载")
    return nil
}

func (cr *CertReloader) GetCertificate(
    hello *tls.ClientHelloInfo,
) (*tls.Certificate, error) {
    cr.mu.RLock()
    defer cr.mu.RUnlock()
    return cr.cert, nil
}

func main() {
    reloader := &CertReloader{
        certPath: "/etc/certs/tls.crt",
        keyPath:  "/etc/certs/tls.key",
    }
    if err := reloader.LoadCertificate(); err != nil {
        log.Fatal(err)
    }

    tlsConfig := &tls.Config{
        GetCertificate: reloader.GetCertificate,
    }
    _ = tlsConfig
    // 使用 tlsConfig 创建 TLS 监听器
    // 另起一个 goroutine 监听证书文件变化并调用 LoadCertificate
}

Envoy 的 SDS(Secret Discovery Service,密钥发现服务)

Envoy 代理通过 SDS API 动态获取证书,无需重启。SPIRE 作为 SDS 服务器,在证书轮转时通过 gRPC 流推送新证书给 Envoy。整个过程对应用完全透明。


六、内部 PKI

6.1 为什么需要内部 PKI

公共 CA(如 Let’s Encrypt、DigiCert)签发的证书适用于面向公网的服务。但内部服务之间的 mTLS 不应该使用公共 CA:

  1. 域名限制。公共 CA 只为你拥有的公共域名签发证书,而内部服务可能使用 service-a.namespace.svc.cluster.local 这样的内部域名。
  2. 签发速度。公共 CA 的签发需要域名验证,可能需要几秒到几分钟。内部 PKI 可以在毫秒内签发。
  3. 控制权。使用公共 CA 意味着你的内部服务身份依赖外部组织。如果公共 CA 出现问题,你的内部通信也会受影响。
  4. 成本。公共 CA 的通配符证书或大量证书可能费用不菲。内部 PKI 的签发成本为零。

6.2 内部 PKI 架构

一个典型的内部 PKI 架构如下:

离线根 CA(存储在 HSM 中,物理隔离)
  ├── 在线中间 CA - 服务网格(签发 mTLS 证书)
  │     ├── SPIRE Server(自动签发工作负载证书)
  │     └── cert-manager CA Issuer(签发内部服务证书)
  └── 在线中间 CA - 基础设施(签发基础设施证书)
        ├── 数据库 TLS 证书
        ├── 消息队列 TLS 证书
        └── 管理后台 TLS 证书

6.3 使用 cert-manager 构建内部 CA

cert-manager 内置了 CA 类型的 Issuer,可以直接用 Kubernetes Secret 中存储的 CA 证书和私钥来签发内部证书。

# 创建 CA 密钥对(实际生产中应该用更安全的方式生成)
# internal-ca-issuer.yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: internal-ca
spec:
  ca:
    secretName: internal-ca-keypair
---
# 使用内部 CA 签发服务证书
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: order-service-tls
  namespace: production
spec:
  secretName: order-service-tls
  duration: 24h
  renewBefore: 8h
  issuerRef:
    name: internal-ca
    kind: ClusterIssuer
  dnsNames:
    - order-service.production.svc.cluster.local
  usages:
    - server auth
    - client auth
  privateKey:
    algorithm: ECDSA
    size: 256

6.4 信任根的分发

内部 PKI 的一个关键问题是:如何让所有服务信任内部 CA 的根证书?

几种常见方案:

# trust-manager Bundle 示例
apiVersion: trust.cert-manager.io/v1alpha1
kind: Bundle
metadata:
  name: internal-ca-bundle
spec:
  sources:
    - secret:
        name: internal-ca-keypair
        key: ca.crt
  target:
    configMap:
      key: ca-certificates.crt
    namespaceSelector:
      matchLabels:
        trust-bundle: "enabled"

七、HSM 与密钥保护

7.1 HSM 是什么

HSM(Hardware Security Module,硬件安全模块)是一种专用硬件设备,用于生成、存储和使用加密密钥。HSM 的核心特性是:私钥永远不离开硬件。所有加密操作(签名、解密)都在 HSM 内部执行,软件只能通过 API 提交数据和获取结果,无法导出私钥。

7.2 FIPS 140 安全等级

FIPS 140(Federal Information Processing Standard 140,联邦信息处理标准 140)是美国国家标准与技术研究所(NIST)制定的密码模块安全标准。最新版本是 FIPS 140-3。

安全等级 要求 典型实现 适用场景
Level 1 至少使用一个经过认证的加密算法 软件加密库(如 OpenSSL) 开发和测试环境
Level 2 需要物理篡改证据(tamper-evident) 低端 HSM,加封条的服务器 一般商业应用
Level 3 需要物理防篡改(tamper-resistant),身份认证 专用 HSM 设备 金融、支付、CA 根密钥
Level 4 检测到物理攻击时主动销毁密钥 高端军用 HSM 政府、国防

大多数企业的 CA 根密钥需要 FIPS 140-2/3 Level 3 认证的 HSM。

7.3 云 HSM 服务

主流云厂商都提供了托管的 HSM 服务:

AWS CloudHSM

AWS KMS(Key Management Service,密钥管理服务)

Azure Dedicated HSM

Azure Key Vault Managed HSM

7.4 软件密钥管理

不是所有场景都需要 HSM。对于非根 CA 的密钥,软件密钥管理可能是更实际的选择:

HashiCorp Vault

Vault 是最流行的开源密钥管理工具。它的 PKI 密钥引擎可以作为内部 CA:

# 启用 PKI 密钥引擎
vault secrets enable pki

# 配置最大证书有效期
vault secrets tune -max-lease-ttl=87600h pki

# 生成根 CA 证书
vault write pki/root/generate/internal \
  common_name="Internal Root CA" \
  ttl=87600h

# 启用中间 CA
vault secrets enable -path=pki_int pki

# 生成中间 CA 的 CSR
vault write pki_int/intermediate/generate/internal \
  common_name="Internal Intermediate CA"

# 用根 CA 签发中间 CA 证书(省略了 CSR 传递步骤)

# 配置角色(定义可以签发哪些域名的证书)
vault write pki_int/roles/internal-service \
  allowed_domains="svc.cluster.local" \
  allow_subdomains=true \
  max_ttl=72h

应用通过 Vault API 或 Vault Agent 自动获取和续期证书。

7.5 密钥仪式(Key Ceremony)

对于根 CA 密钥的生成,需要执行严格的密钥仪式。这是一个高度正式的流程,通常包括:

  1. 多人在场:至少需要两名以上授权人员同时在场(双人控制原则)。
  2. 物理安全:在受控的安全房间中进行,全程录像。
  3. 离线操作:使用 air-gapped(物理隔离)的计算机,不连接任何网络。
  4. HSM 初始化:在 HSM 中生成密钥对,密钥永远不离开 HSM。
  5. 密钥分片:使用 Shamir 秘密共享(Shamir’s Secret Sharing)将 HSM 的访问凭证分成 N 片,至少需要 M 片才能重建(M-of-N 阈值方案)。
  6. 分片分发:将每一片交给不同的受托人(Key Custodian),受托人将分片存储在独立的保险箱中。
  7. 文档记录:记录整个过程的每一步,包括参与人员、使用的设备序列号、生成的证书指纹等。

Let’s Encrypt 的根密钥仪式文档是公开的,可以作为参考。


八、证书监控与告警

8.1 监控什么

即使证书管理已经自动化,监控仍然是必不可少的安全网。需要监控的指标:

  1. 证书过期时间:最关键的指标。当证书剩余有效期低于阈值时告警。
  2. 证书续期状态:cert-manager 的续期是否成功?ACME 请求是否失败?
  3. 证书链完整性:服务器是否正确配置了完整的证书链?
  4. 私钥与证书匹配:部署时是否错误地使用了不匹配的私钥?
  5. CT 日志(Certificate Transparency Log,证书透明日志):是否有未授权的证书被签发?

8.2 Prometheus 监控 cert-manager

cert-manager 原生暴露 Prometheus 指标。关键指标:

# Prometheus 告警规则
# cert-manager-alerts.yaml
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: cert-manager-alerts
  namespace: monitoring
spec:
  groups:
    - name: cert-manager
      rules:
        - alert: CertificateExpiringSoon
          expr: |
            certmanager_certificate_expiration_timestamp_seconds
            - time() < 7 * 24 * 3600
          for: 1h
          labels:
            severity: warning
          annotations:
            summary: "证书即将过期"
            description: >
              证书 {{ $labels.name }}(命名空间 {{ $labels.namespace }})
              将在 {{ $value | humanizeDuration }} 后过期。

        - alert: CertificateNotReady
          expr: |
            certmanager_certificate_ready_status{condition="True"} == 0
          for: 15m
          labels:
            severity: critical
          annotations:
            summary: "证书未就绪"
            description: >
              证书 {{ $labels.name }}(命名空间 {{ $labels.namespace }})
              已经 15 分钟未处于 Ready 状态。

        - alert: CertificateRenewalFailure
          expr: |
            increase(
              certmanager_controller_sync_call_count{
                controller="certificates-issuing",
                status="error"
              }[1h]
            ) > 0
          for: 5m
          labels:
            severity: critical
          annotations:
            summary: "证书续期失败"
            description: "cert-manager 在过去 1 小时内有证书签发失败。"

8.3 外部证书探测

对于非 Kubernetes 环境的证书,可以使用 Blackbox Exporter 或自定义脚本进行外部探测。

#!/bin/bash
# check_cert_expiry.sh
# 检查证书过期时间并输出 Prometheus 格式的指标

DOMAINS="api.example.com cdn.example.com admin.example.com"

for domain in $DOMAINS; do
  expiry_date=$(echo | \
    openssl s_client -servername "$domain" \
      -connect "$domain:443" 2>/dev/null | \
    openssl x509 -noout -enddate 2>/dev/null | \
    cut -d= -f2)

  if [ -n "$expiry_date" ]; then
    expiry_epoch=$(date -d "$expiry_date" +%s)
    now_epoch=$(date +%s)
    remaining_seconds=$((expiry_epoch - now_epoch))

    echo "cert_expiry_seconds{domain=\"$domain\"} $remaining_seconds"
  else
    echo "cert_probe_success{domain=\"$domain\"} 0"
  fi
done

8.4 CT 日志监控

证书透明(Certificate Transparency,CT)日志是公共的、只能追加的日志,记录了所有公共 CA 签发的证书。通过监控 CT 日志,可以发现是否有人为你的域名签发了未授权的证书。

工具如 CertSpotter 或 Facebook 的 ct-monitor 可以订阅 CT 日志,当发现你的域名出现新证书时发送告警。

告警策略建议:
  - 证书剩余有效期 < 30 天 → 信息级(Info)
  - 证书剩余有效期 < 14 天 → 警告级(Warning)
  - 证书剩余有效期 < 7 天  → 严重级(Critical)
  - 证书续期失败            → 严重级(Critical)
  - CT 日志发现未知证书     → 严重级(Critical)

九、工程案例

9.1 背景

某电商平台运营着 200 多个微服务,部署在 3 个 Kubernetes 集群上,分布在两个云区域。在实施自动化证书管理之前,团队经历了两次因证书过期导致的严重事故:

两次事故的根因相同:证书由运维团队手动管理,续期信息记录在内部 Wiki 中,但没有自动化的过期提醒。

9.2 改造方案

团队用 12 周时间完成了证书管理体系的全面改造。

第一阶段(第 1-3 周):证书清单盘点

首先做的事情是搞清楚”我们到底有多少证书”。团队编写了扫描脚本,遍历所有 Kubernetes 集群的 Secret、所有负载均衡器的证书配置、所有 CDN 的证书绑定,建立了一份完整的证书清单。

结果:共发现 347 张活跃证书,其中 89 张将在 60 天内过期,12 张已经过期但因为客户端没有强制校验而未被发现。

第二阶段(第 4-8 周):部署 cert-manager 和自动化

第三阶段(第 9-10 周):监控和告警

第四阶段(第 11-12 周):根 CA 密钥保护

9.3 改造成果

改造完成后的一年内:

指标 改造前 改造后
证书过期导致的事故 2 次 / 年 0 次
证书续期方式 手动 全自动
平均续期响应时间 2-4 小时(人工处理) 自动完成(无人工介入)
证书清单准确率 约 60%(多处遗漏) 100%(cert-manager 管理)
内部 mTLS 证书有效期 1 年 24 小时
根 CA 私钥存储 Kubernetes Secret AWS CloudHSM(FIPS 140-2 L3)

最重要的变化不是技术层面的,而是心理层面的:团队不再担心证书过期。证书管理从一个需要人记住的运维任务,变成了一个自我运行的自动化系统。

9.4 遇到的问题与教训

改造过程并非一帆风顺:

  1. DNS-01 挑战的 API 限流。在初始迁移时,cert-manager 同时为几百个域名申请证书,触发了 DNS 服务商的 API 限流。解决方案:配置 cert-manager 的并发限制,分批迁移。

  2. 旧客户端不信任新的内部根 CA。部分遗留系统没有更新信任库,在切换到新内部 CA 后无法连接。解决方案:设置过渡期,新旧 CA 并存,旧 CA 签发的证书在过期前继续使用。

  3. CloudHSM 的延迟。将 CA 签名操作迁移到 CloudHSM 后,签发延迟从亚毫秒增加到 5-10 毫秒。对于日常签发量来说不是问题,但在大规模滚动更新时可能成为瓶颈。解决方案:使用中间 CA 缓存策略,只有中间 CA 的密钥在 HSM 中,叶子证书由在线的中间 CA 快速签发。


十、选型对比

10.1 HSM vs 软件密钥管理

对比维度 HSM(硬件安全模块) 软件密钥管理(如 Vault)
安全等级 FIPS 140-2/3 Level 3 FIPS 140-2 Level 1-2
私钥可导出性 不可导出(物理隔离) 可导出(依赖访问控制)
签名性能 硬件加速,RSA 2048 约 1000 次/秒 受 CPU 限制,性能更高但安全性更低
延迟 5-10 毫秒(含网络) 亚毫秒(本地)到低毫秒(远程)
成本 高(专用 HSM 每小时 1-2 美元,年费约 1-2 万美元) 低(开源免费,企业版按节点计费)
运维复杂度 高(需要密钥仪式,物理安全,供应商锁定) 中(需要加固部署,密钥备份策略)
合规要求 满足 PCI DSS、金融监管等强制要求 可能不满足某些行业的强制要求
适用场景 根 CA 密钥、支付签名密钥、最高等级密钥 应用层加密密钥、中间 CA 密钥、API 密钥
灾备方案 HSM 集群跨区域同步 Vault 集群跨区域复制

选型建议

10.2 长期证书 vs 短期证书

对比维度 长期证书(月-年) 短期证书(小时-天)
管理方式 可以手动管理 必须自动化
攻击窗口 大(泄露后长期可用) 小(自然过期)
撤销依赖 强依赖 CRL / OCSP 弱依赖(自然过期即失效)
基础设施要求 低(手动即可) 高(需要自动化签发基础设施)
故障模式 遗忘导致过期 自动化故障导致无法签发
运维认知负担 高(需要跟踪过期时间) 低(系统自动处理)
适合场景 遗留系统、合作方系统 云原生、微服务、服务网格

选型建议

10.3 证书管理工具对比

工具 类型 适用环境 签发方式 特点
cert-manager Kubernetes 原生 Kubernetes ACME、内部 CA、Vault 声明式,Kubernetes 深度集成
SPIRE 工作负载身份 任意(Kubernetes / VM) 内部 CA SPIFFE 标准,极短期证书
Vault PKI 通用密钥管理 任意 内部 CA 灵活的策略引擎,审计日志
Certbot ACME 客户端 Linux 服务器 ACME 轻量,适合单机部署
acme.sh ACME 客户端 Linux / Docker ACME 纯 Shell 脚本,无依赖
step-ca 小型内部 CA 任意 内部 CA、ACME 轻量级,支持 ACME 协议

十一、总结

证书管理的本质是用自动化替代人的记忆。整个体系的设计可以归结为几条原则:

  1. 自动化优先。证书的签发、续期、分发、轮转都应该是自动化的。手动操作只出现在密钥仪式等极少数场景。

  2. 缩短有效期。证书有效期越短,攻击窗口越小,对撤销机制的依赖越低。但短期证书的前提是可靠的自动化基础设施。

  3. 分层保护密钥。根 CA 密钥用 HSM 保护并离线存储;中间 CA 密钥用 HSM 或加固的软件保护;叶子证书的私钥用标准的 Secret 管理。

  4. 监控是安全网。即使自动化流程运行正常,也需要监控来发现自动化本身的故障。证书过期告警是最后一道防线。

  5. 内外分离。公网服务使用公共 CA,内部服务使用独立的内部 PKI。两者的信任根、管理策略、有效期可以完全独立。

回到本文开头的问题:如何建立自动化的证书生命周期管理?答案不是某一个工具或某一个流程,而是一套完整的体系——从 CA 架构设计到自动化签发,从密钥保护到监控告警,每个环节都不能有缺口。

下一篇中,我们将讨论日志架构——另一个看似简单但在生产环境中极其容易出问题的基础设施。


参考资料

  1. R. Barnes, J. Hoffman-Andrews, D. McCarney, J. Kasten. “Automatic Certificate Management Environment (ACME).” RFC 8555, IETF, 2019.
  2. D. Cooper, S. Santesson, S. Farrell, S. Boeyen, R. Housley, W. Polk. “Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile.” RFC 5280, IETF, 2008.
  3. NIST. “Security Requirements for Cryptographic Modules.” FIPS 140-3, 2019.
  4. SPIFFE Project. “Secure Production Identity Framework for Everyone.” https://spiffe.io/
  5. cert-manager Project. “Cloud Native Certificate Management.” https://cert-manager.io/docs/
  6. HashiCorp. “Vault PKI Secrets Engine.” https://developer.hashicorp.com/vault/docs/secrets/pki
  7. Let’s Encrypt. “How It Works.” https://letsencrypt.org/how-it-works/
  8. E. Rescorla. “The Transport Layer Security (TLS) Protocol Version 1.3.” RFC 8446, IETF, 2018.
  9. S. Santesson, M. Myers, R. Ankney, A. Malpani, S. Galperin, C. Adams. “X.509 Internet Public Key Infrastructure Online Certificate Status Protocol - OCSP.” RFC 6960, IETF, 2013.
  10. B. Laurie, A. Langley, E. Kasper. “Certificate Transparency.” RFC 6962, IETF, 2013.

同主题继续阅读

把当前热点继续串成多页阅读,而不是停在单篇消费。

2026-04-13 · architecture

【系统架构设计百科】架构质量属性:不只是"高可用高性能"

需求评审时写下的'高可用、高性能、高并发',到了架构设计阶段几乎无法落地——因为它们不是可执行的需求。本文从 SEI/CMU 的质量属性理论出发,用 stimulus-response 场景模型把模糊需求变成可量化、可验证的架构约束,并拆解属性之间的冲突与联动关系。

2026-04-13 · architecture

【系统架构设计百科】告警策略:如何避免"狼来了"

大多数团队的告警系统都在制造噪声而不是传递信号。阈值告警看似直观,实则产生大量误报和漏报,值班工程师在凌晨三点被叫醒,却发现只是一次无害的毛刺。本文从告警疲劳的工业数据出发,拆解基于 SLO 的多窗口燃烧率告警算法,深入 Alertmanager 的路由、抑制与分组机制,结合 PagerDuty 的告警疲劳研究和真实工程案例,给出一套可落地的告警策略设计方法。

2026-04-13 · architecture

【系统架构设计百科】复杂性管理:架构的核心战场

系统复杂性是架构腐化的根源——本文从 Brooks 的本质复杂性与偶然复杂性划分出发,结合认知负荷理论与 Parnas 的信息隐藏原则,系统阐述复杂性的来源、度量与控制手段,并给出可操作的架构策略


By .