证书这活儿:PEM/JKS/P12 怎么选、免费证书哪家强、自动轮换怎么搞

Posted on 二 24 3月 2026 in Journal

Abstract 证书这活儿:PEM/JKS/P12 怎么选、免费证书哪家强、自动轮换怎么搞
Authors Walter Fan
Category learning note
Version v1.0
Updated 2026-03-24
License CC-BY-NC-ND 4.0

短大纲

  • 先讲一个我自己犯过的蠢错:个人网站证书忘了续,结果在公司里打不开
  • 把 Root CA / Intermediate CA / Leaf Certificate 这条信任链掰开揉碎
  • 再讲 PEM / JKS / PKCS#12 三种格式,到底谁装什么、谁给谁看
  • 免费证书怎么选,自动轮换怎么做,最后给一张能照抄的检查清单

前几天我在公司里想打开自己的个人网站,结果浏览器直接给我甩了一张红脸:证书校验失败,页面打不开。

这事说起来挺丢人。平时给别人的服务配 TLS,讲起安全来头头是道,轮到自己的站,证书却悄悄过期了。家里电脑上偶尔还能点进去,一到公司网络环境里就不行,浏览器、代理、系统信任链,一层层都比我更较真。它们不像老朋友,不会跟你讲情面,只认日期、签名、链路和策略。

这件事又一次提醒我:证书管理这活儿,看着像“抄个配置,跑个命令”,其实更像值班。平时风平浪静,大家都想不起它;一旦到期、链条断了、格式塞错了,它就会在你最不想处理的时候跳出来,给你上一课。

所以这篇文章我不只想讲“怎么续期”。我想把证书这套东西里最容易糊涂的几层讲透,特别是下面这条链子:

Root CA → Intermediate CA → Leaf Certificate

别小看这三个名字。很多证书事故,表面看是“网站打不开”,骨子里其实就三类:要么 leaf 过期了,要么 intermediate 没带全,要么客户端根本不信任你上游那条根。把这三层搞清楚,再看 PEM、JKS、P12,脑子里就不会是一锅粥。

先搞清楚:证书到底是什么

不扯太多密码学术语,咱们先抓住最要紧的部分。

一张 TLS 证书,本质上是一个 X.509 结构化文档。它不是一张“截图”,也不是“一个公钥文件那么简单”,而是一份带签名的数据结构。里面至少有四类信息:

  1. 主体信息(Subject):这张证书是谁的。对网站来说,最重要的是域名
  2. 公钥(Public Key):客户端后面要拿它来协商密钥、验证签名
  3. 用途与约束:这张证书能干什么,能不能签别人,能不能做服务器认证
  4. 签发者签名(Issuer Signature):上一级 CA 用自己的私钥给它盖章

所以证书不是“加密算法”,它更像一张带防伪章的介绍信。公钥是介绍信里的联系方式,Subject 是名字,签名是公证处的钢印。

浏览器或操作系统拿到证书后,不是只看“锁有没有变绿”,它其实在背后做一串检查:

  1. 这张证书是不是发给当前访问的域名
  2. 现在时间是不是在有效期内
  3. 这张证书是不是被一个我信任的上级签发
  4. 上级自己是不是也被更上级签发
  5. 整条链有没有断,有没有人拿错证书冒名顶替
  6. 这张证书的用途是不是允许它拿来做 HTTPS 服务器

只要其中一项不对,浏览器就翻脸。它不会想“这个站长平时人还不错”。机器没有人情世故。

把那条链讲透:Root CA、Intermediate CA、Leaf Certificate 到底各管什么

很多人看到这几个词,脑子里有印象,可是一落到排障就开始晕。无他,这几个名字像,文件也像,打开之后还都是一坨 Base64,看久了确实容易眼花。咱们一个一个说。

1. Root CA:信任的起点,但不是天天拿出来抛头露面

Root CA 是整条证书链的祖师爷。

它有几个关键特征:

  • 通常是自签名(self-signed):也就是 Subject == Issuer
  • 长期存在:有效期往往是十几年到几十年
  • 不会轻易直接签网站证书
  • 预装在系统、浏览器或企业信任仓库里

Root CA 证书里最关键的不是域名,而是“我有资格当 CA”。这通常体现在扩展字段里,比如:

  • Basic Constraints: CA:TRUE
  • Key Usage: Certificate Sign, CRL Sign

它像银行总行的总印章。平时不拿出来盖每一份业务单据,因为一旦根私钥泄露,整个体系都得翻车。所以现实世界里,Root CA 很少直接签你的网站证书。

Root CA 常见的存在位置:

  • 操作系统 trust store
  • 浏览器自己的信任库
  • Java cacerts
  • 企业内网设备或代理注入的自定义根证书

这也解释了一个现象:为什么同一个站,在家里能开,在公司里不一定能开。公司网络里如果有 HTTPS inspection、中间代理、或者额外的企业根证书策略,验证路径和你家里的浏览器就不是同一套了。

2. Intermediate CA:真正天天干活的那层

Intermediate CA 是中间 CA,也叫中级 CA。它是 Root CA 签发出来的“代理掌门”。

它的职责是:

  • 替 Root CA 干活,去签发大量业务证书
  • 把 Root CA 私钥和日常签发操作隔离开
  • 允许 CA 做更细的分层和权限控制

Intermediate CA 的证书长这样理解就行:

Subject: R3
Issuer: ISRG Root X1
Basic Constraints: CA:TRUE
Key Usage: Certificate Sign, CRL Sign
Authority Key Identifier: 指向 Root CA
Subject Key Identifier: 自己的 key 指纹

你会发现它和 Root CA 一样,也有 CA:TRUE,因为它也能签别人。区别在于:

  • Root 是信任锚(trust anchor)
  • Intermediate 是被 Root 授权出来干活的

这层非常关键。很多线上事故并不是 leaf 证书错了,而是部署的时候只放了 leaf,没把 intermediate 一起带上。浏览器有时靠缓存还能“脑补”出来,curl、移动端 SDK、某些企业代理就没那么好说话了,当场报错。

3. Leaf Certificate:真正挂在你网站门口那张牌子

Leaf Certificate 就是服务器证书,也叫终端证书、站点证书。它是给最终服务用的,不再拿去签别的证书。

它的典型特征:

  • Basic Constraints: CA:FALSE
  • Extended Key Usage: TLS Web Server Authentication
  • Subject Alternative Name (SAN) 里放域名
  • 有较短有效期,比如 90 天

举个例子,我的个人网站证书如果是发给 www.fanyamin.com,那 Leaf Certificate 里你最关心的是:

Subject Alternative Name:
  DNS:www.fanyamin.com
  DNS:fanyamin.com

Issuer:
  Let's Encrypt R3

Not Before / Not After:
  2026-01-01 ... 2026-03-31

注意,现在浏览器对域名校验几乎都看 SAN,而不是老式 CN(Common Name)。所以如果证书里没把域名写进 SAN,哪怕别的字段都漂亮,也照样不认。

4. 这三层在文件里通常长什么样

很多人的第二个困惑是:名字懂了,可文件看着还是乱。

拿 PEM 来说,三层证书本质上都是同一种 X.509 证书,只是角色不同。它们在磁盘上经常长这样:

-----BEGIN CERTIFICATE-----
... Leaf Certificate ...
-----END CERTIFICATE-----

-----BEGIN CERTIFICATE-----
... Intermediate CA ...
-----END CERTIFICATE-----

Root CA 往往不由服务器发送,因为客户端本地已经有了。服务器通常发的是:

  • 自己的 leaf cert
  • 一个或多个 intermediate cert

也就是大家常说的 fullchain.pem。如果你只部署 cert.pem,而没部署 fullchain.pem,浏览器就可能告诉你:“你这封介绍信像是真的,但你上面那个公证处我没接上。”

5. 客户端到底怎么验证这条链

这部分是最容易被“一句话带过”的,可真出了事,恰恰要靠它排查。

客户端在握手时,大体会按这个顺序检查:

第一步:拿到服务器送来的证书链

服务器通常会在 TLS 握手时送出:

  • leaf certificate
  • intermediate certificate(s)

如果只送 leaf,不送 intermediate,很多客户端就拼不出完整路径。

第二步:验证 leaf 的基本合法性

客户端先看 leaf 本身:

  • 有效期是否包含当前时间
  • SAN 里有没有当前访问域名
  • 签名算法是否还能接受
  • Key Usage / Extended Key Usage 是否允许做服务器证书
  • CA:FALSE 是否合理

像我这次个人网站在公司里打不开,最直白的原因就是 leaf 过期了。到期这件事其实没什么讨论空间,Not After 一过,后面全免谈。

第三步:拿 leaf 的 Issuer 去找上一级 intermediate

Leaf 上会写:

  • Issuer
  • Authority Key Identifier

客户端会拿这些信息去跟服务器送来的 intermediate 对上,看是不是这位“师父”签的。

然后它会做数学验签:拿 intermediate 的公钥,验证 leaf 上的签名是不是对的。

这一步如果失败,常见原因有:

  • 链接错 intermediate 了
  • 证书文件顺序不对
  • 证书被截断或损坏

第四步:继续往上追到 Root

Intermediate 也不是凭空可信。客户端还会继续验证:

  • intermediate 是不是被某个 root 签的
  • 这个 root 是不是在本机信任库里

到这里,链子才算闭环。要是走到头发现根不在 trust store 里,那浏览器照样不认。

所以“证书没问题”这句话,往往只说对了一半。你那张 leaf 没问题,不代表整条链就没问题。

第五步:检查约束条件是不是一路都合法

不是说签名对上就完事。客户端还要检查每一层的“权限”:

  • 上级是不是 CA:TRUE
  • 上级是不是有 keyCertSign
  • path length constraint 有没有超
  • leaf 有没有 serverAuth

这就像公司盖章流程。不是说印泥颜色对了就算通过,还得看这个人有没有审批权。

第六步:看吊销状态和额外安全策略

更严格的客户端还会继续看:

  • CRL / OCSP 吊销状态
  • CT Log / SCT
  • 企业网关自己的安全策略

这一步也是为什么“在我电脑上能开”的经验,经常没有普适性。你家里浏览器和公司代理的策略,可能压根不是同一套。

6. 一张图把链路串起来

[Leaf Certificate: www.fanyamin.com]
    signed by
[Intermediate CA: Let's Encrypt R3]
    signed by
[Root CA: ISRG Root X1]
    trusted by
[OS / Browser / Company Trust Store]

这条链只要有一段断掉,结果都一样:你的网站在用户眼里不是“有一点小毛病”,而是“不可信”。

7. 用 openssl 看这三层,最靠谱

纸上谈兵不如直接看证书。

# 看 leaf 证书内容
openssl x509 -in cert.pem -text -noout

# 看 fullchain 里到底塞了几张证书
openssl crl2pkcs7 -nocrl -certfile fullchain.pem | \
openssl pkcs7 -print_certs -text -noout

# 直接连线上服务,看看服务端到底送了什么链
openssl s_client -connect www.fanyamin.com:443 -servername www.fanyamin.com -showcerts

重点看这些字段:

  • Subject
  • Issuer
  • Not Before / Not After
  • Basic Constraints
  • Key Usage
  • Extended Key Usage
  • Subject Alternative Name

你把这几个字段看顺了,证书问题起码能查明白七八成。

PEM / JKS / PKCS#12:三种格式到底差在哪

这是我见过最容易搞混的地方。很多人被 .pem.crt.key.jks.p12.pfx 这些后缀搞得头大,其实理清楚只需要记住三个"容器"。

PEM:文本格式,Unix 世界的通用语

PEM 是 Privacy Enhanced Mail 的缩写,但跟邮件早没关系了。它就是 Base64 编码 + 头尾标记:

-----BEGIN CERTIFICATE-----
MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhki...
-----END CERTIFICATE-----

特点:

  • 纯文本,cat 就能看,diff 能比,git 能追踪
  • 一个文件可以串联多张证书(certificate chain)
  • 私钥单独存一个 .key 文件(也是 PEM 格式)
  • Nginx、Apache、HAProxy、Go、Python、Node.js 原生支持

PEM 是最"透明"的格式。你几乎可以用记事本编辑它——虽然没人推荐这么干。

JKS:Java 生态的老朋友

JKS 是 Java KeyStore,Java 自己搞的一种二进制容器格式。

特点:

  • 二进制,不能直接看内容,需要 keytool 命令操作
  • 可以在一个文件里同时存私钥、证书、信任链
  • 用密码保护整个 keystore 以及里面每个条目
  • 主要用于 Java 应用:Tomcat、Spring Boot、Kafka、Elasticsearch

JKS 的问题是只有 Java 生态认它。你想让 Nginx 读 JKS?不行。想用 Python 脚本解析?得先转格式。而且 JKS 用的加密算法比较老(早期版本用 SHA1),Oracle 从 Java 9 开始推荐用 PKCS#12 替代。

PKCS#12 (.p12 / .pfx):跨平台的二进制容器

PKCS#12 是一个 RSA 实验室定义的标准,文件后缀 .p12.pfx(Windows 偏好叫 .pfx,内容一样)。

特点:

  • 二进制,密码保护
  • 能把私钥 + 证书 + 信任链全部打包在一起
  • 跨平台:Java、.NET、Go、浏览器都能读
  • 是 Java 9+ 默认推荐的 keystore 格式

PKCS#12 像一个"加密的压缩包",把你需要的东西都塞进一个文件。搬运方便,但调试不如 PEM 透明。

三者对比

特性 PEM JKS PKCS#12 (.p12/.pfx)
编码 Base64 文本 二进制 二进制
可读性 cat 可看 需要 keytool 需要 openssl/keytool
私钥+证书同文件 通常分开 可以 可以
密码保护 私钥可选加密
生态 Nginx/Apache/Go/Python/Node Java 跨平台通用
信任链 文件内串联 store 内多条目 包内多条目
标准化 事实标准 Java 私有 PKCS#12 (RFC 7292)

一句话选型建议:Web 服务器和云原生场景用 PEM;纯 Java 栈用 PKCS#12(别再用 JKS 了);需要把私钥和证书打包给人的时候用 PKCS#12。

格式互转速查

工作中最常见的转换需求,opensslkeytool 基本能搞定:

# PEM → PKCS#12
openssl pkcs12 -export \
  -in cert.pem -inkey key.pem -certfile chain.pem \
  -out bundle.p12 -name myalias

# PKCS#12 → PEM
openssl pkcs12 -in bundle.p12 -out all.pem -nodes

# 只导出证书(不含私钥)
openssl pkcs12 -in bundle.p12 -nokeys -out cert.pem

# 只导出私钥
openssl pkcs12 -in bundle.p12 -nocerts -nodes -out key.pem

# PKCS#12 → JKS (Java 9+)
keytool -importkeystore \
  -srckeystore bundle.p12 -srcstoretype PKCS12 \
  -destkeystore app.jks -deststoretype JKS

# JKS → PKCS#12
keytool -importkeystore \
  -srckeystore app.jks -srcstoretype JKS \
  -destkeystore bundle.p12 -deststoretype PKCS12

转格式的时候最容易出的两个坑:

  1. 忘了带中间证书:只导了 leaf cert,没带 intermediate CA,客户端验不过信任链
  2. 密码搞丢了:PKCS#12 和 JKS 都有密码保护,转来转去密码对不上就完了。用密码管理器存好,别写在代码里

免费证书:不只是 Let's Encrypt

说到免费证书,大家第一反应是 Let's Encrypt。它确实改变了整个行业,但不是唯一选项。

Let's Encrypt

  • 全球最大的免费 CA,ISRG 运营
  • 支持 DV(Domain Validation)证书
  • 有效期 90 天,逼着你做自动续期(这其实是好事)
  • 通过 ACME 协议自动签发和续期
  • 支持通配符证书(需要 DNS-01 验证)
  • 速率限制:每个注册域名每周 50 张证书

ZeroSSL

  • 免费 DV 证书,也支持 ACME
  • 有 Web UI,适合不熟悉命令行的人
  • 免费层每月 3 张 90 天证书
  • 付费层有更多额度和 REST API

Google Trust Services

  • Google 自己的公共 CA
  • 支持 ACME 协议
  • 证书有效期和速率限制政策较宽松
  • 适合 GCP 生态里的服务

自签证书(Self-Signed)

  • 不是"免费 CA"但确实免费
  • 只适合开发、测试、内部服务
  • 客户端不会自动信任,需要手动导入 CA 证书
  • 工具:opensslmkcert(本地开发推荐)、cfssl

选型边界

场景 推荐
公网 Web 服务 Let's Encrypt / ZeroSSL
内部微服务 mTLS 自签 CA 或 SPIFFE/SPIRE
企业级需求(OV/EV证书) 商业 CA(DigiCert、Sectigo 等)
本地开发 mkcert
Kubernetes Ingress cert-manager + Let's Encrypt

免费证书有一个共同限制:只做 DV(域名验证)。需要 OV(组织验证)或 EV(扩展验证)证书的,还是得找商业 CA 付钱。不过老实说,对绝大多数服务来说,DV 够了。

自动轮换:别再靠日历提醒了

证书过期是最蠢但最常见的生产事故之一。手工续期有两个问题:人会忘,流程会断。

自动轮换有两条主流路径。

路径一:ACME 客户端

ACME(Automatic Certificate Management Environment)是 Let's Encrypt 推广的标准协议(RFC 8555)。流程大致是:

@startuml
!theme plain
skinparam backgroundColor #FEFEFE
skinparam defaultFontSize 12

participant "ACME Client\n(certbot/acme.sh)" as C
participant "ACME Server\n(Let's Encrypt)" as S
participant "Web Server\n(Nginx)" as W

C -> S : 1. 请求签发 example.com
S --> C : 2. 返回验证挑战\n(HTTP-01 / DNS-01)
C -> W : 3. 放置验证文件\n/.well-known/acme-challenge/xxx
S -> W : 4. 回调验证
S --> C : 5. 验证通过,签发证书
C -> W : 6. 部署新证书,reload
note over C : 定时任务每天检查\n到期前 30 天自动续期
@enduml

ACME 证书签发流程

常用 ACME 客户端:

  • certbot:Let's Encrypt 官方推荐,Python 写的,插件丰富
  • acme.sh:纯 Shell 脚本,零依赖,支持几十种 DNS 提供商
  • lego:Go 写的,单二进制,适合容器环境

一个 acme.sh 的典型配置:

# 首次签发(DNS 验证,支持通配符)
acme.sh --issue --dns dns_cf -d example.com -d "*.example.com"

# 自动部署到 Nginx
acme.sh --install-cert -d example.com \
  --key-file /etc/nginx/ssl/key.pem \
  --fullchain-file /etc/nginx/ssl/fullchain.pem \
  --reloadcmd "systemctl reload nginx"

# acme.sh 会自动在 crontab 里加续期任务

路径二:Kubernetes cert-manager

如果你的服务跑在 Kubernetes 里,cert-manager 是事实标准。

@startuml
!theme plain
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle
skinparam defaultFontSize 12

package "Kubernetes Cluster" {
  [cert-manager\nController] as CM #LightGreen
  [Issuer / ClusterIssuer\n(ACME config)] as ISS #LightYellow
  [Certificate CR] as CERT #LightBlue
  [Secret\n(tls.crt + tls.key)] as SEC #Plum
  [Ingress / Gateway] as ING #LightSkyBlue

  CERT --> CM : watch
  CM --> ISS : 读取签发配置
  CM --> SEC : 写入证书
  ING --> SEC : 引用 TLS Secret
}

cloud "Let's Encrypt\nACME Server" as LE

CM --> LE : ACME 协议\n签发/续期

note bottom of CM
  自动监控证书到期
  提前 30 天续期
  更新 Secret 后
  Ingress 自动生效
end note

@enduml

cert-manager 架构

一个最小可用配置:

# 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: 声明式证书,cert-manager 自动签发和续期
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
  renewBefore: 720h  # 到期前 30 天续期

cert-manager 的好处是声明式:你只管定义"我要一张什么证书",它负责签发、续期、更新 Secret。Ingress Controller 监听到 Secret 变化,自动重载。整条链路不需要人介入。

两条路径怎么选

场景 推荐
传统 VM 上的 Nginx/Apache certbot 或 acme.sh
Docker 单机部署 acme.sh + cron
Kubernetes 集群 cert-manager
多云、混合部署 acme.sh(通用性最好)
内部 CA 签发 cert-manager + 自定义 Issuer 或 Vault PKI

几个实操层面容易踩的坑

坑一:只部署了 leaf cert,没带中间证书

浏览器可能缓存了中间 CA 所以能打开,但 curl、SDK、移动端就报错。解决办法:部署 fullchain 而不是单张证书。用 openssl s_client 验证:

openssl s_client -connect example.com:443 -showcerts

看输出里有没有完整的证书链。

坑二:证书和私钥不匹配

换证书的时候用了旧的私钥,或者反过来。快速检查:

# 两个 md5 必须一致
openssl x509 -noout -modulus -in cert.pem | openssl md5
openssl rsa -noout -modulus -in key.pem | openssl md5

坑三:Let's Encrypt 速率限制撞了

测试时反复签发,把每周 50 张的额度用完了。生产签不了。测试环境永远用 staging endpoint

https://acme-staging-v02.api.letsencrypt.org/directory

坑四:自动续期配了但没验证

cron job 加了,从来没跑过。或者跑了但 DNS 验证失败,续期静默失败,直到证书过期才发现。

建议:监控证书剩余天数。Prometheus 有 ssl_certificate_expiry_time_seconds 这个 metric,Blackbox Exporter 也能探测。低于 14 天就报警。

坑五:内部服务用公共 CA 证书

内部 api.internal.company.com 也去 Let's Encrypt 签一张?能行,但暴露了内部域名结构(CT Log 里全是公开的)。内部服务建议自建 CA 或者用 SPIFFE/SPIRE 做 mTLS。

证书管理的生命周期

把上面的点串起来,证书管理不是"签一张就完了",而是一个持续循环:

@startuml
!theme plain
skinparam backgroundColor #FEFEFE
skinparam activityFontSize 12

start

:评估需求\n公网/内部? DV/OV/EV?;

:选择 CA\n免费(Let's Encrypt) / 商业 / 自建;

:选择格式\nPEM(Web) / P12(Java/跨平台) / JKS(旧Java);

:签发证书\n手动 or ACME 自动化;

:部署证书\n配置 Web Server 或 K8s Secret;

:监控到期\nPrometheus / Blackbox Exporter;

if (到期前 30 天?) then (yes)
  :自动续期\ncert-manager / acme.sh / certbot;
  :部署新证书\nreload / Secret 更新;
else (no)
  :继续监控;
endif

:审计与合规\nCT Log / 吊销检查 / 密钥轮换;

stop

@enduml

证书管理生命周期

明天就能做的检查清单

  • [ ] 盘点所有 TLS 证书:域名、格式、到期时间、存放位置
  • [ ] 确认每个服务部署的是 fullchain 而不是单张 leaf cert
  • [ ] 为公网服务配置 ACME 自动续期(certbot/acme.sh/cert-manager)
  • [ ] 测试环境用 staging endpoint,别消耗生产速率限制
  • [ ] 新 Java 项目用 PKCS#12 替代 JKS
  • [ ] 监控证书剩余天数,低于 14 天触发告警
  • [ ] 内部服务用自建 CA 或 mTLS,别把内部域名暴露到 CT Log
  • [ ] 私钥文件权限收紧到 600,不要提交到 Git
  • [ ] 做一次"证书突然过期"的演练,看恢复流程要多久

总结

证书管理不是什么高深的活儿,但它有个讨厌的特点:平时不出事,出事就是凌晨三点。 大部分证书事故的根因都不是技术不行,而是流程断了——该续的没续,该监控的没监控,该自动化的还在靠人。

格式上,PEM 最透明,PKCS#12 最通用,JKS 正在退场。免费证书领域,Let's Encrypt 已经是基础设施级别的存在,90 天有效期逼着你做自动化,这是件好事。自动轮换,传统环境用 acme.sh 或 certbot,Kubernetes 用 cert-manager,都是成熟方案。

一句话:证书管理的最高境界,是你忘了它的存在。 因为该自动的都自动了,该告警的都告警了,你只需要在续签成功的日志里偶尔看到一行 Certificate renewed successfully,然后继续睡觉。

@startmindmap
!theme plain
skinparam backgroundColor #FEFEFE

* 证书管理最佳实践
** 格式选型
*** PEM: 文本, Web/云原生
*** PKCS#12: 二进制, 跨平台
*** JKS: Java 遗留, 建议迁移
** 免费证书
*** Let's Encrypt (90天, ACME)
*** ZeroSSL (Web UI)
*** Google Trust Services
*** 自签 (内部/开发)
** 自动轮换
*** ACME 客户端
**** certbot
**** acme.sh
**** lego
*** Kubernetes
**** cert-manager
**** ClusterIssuer + Certificate CR
** 常见坑
*** 缺中间证书
*** 证书私钥不匹配
*** 速率限制
*** 续期静默失败
*** 内部域名暴露 CT Log
** 监控告警
*** 剩余天数 < 14 天
*** Prometheus + Blackbox
*** 续期失败告警

@endmindmap

证书管理思维导图

扩展阅读

  • Let's Encrypt 官方文档: https://letsencrypt.org/docs/
  • ACME 协议 RFC 8555: https://datatracker.ietf.org/doc/html/rfc8555
  • cert-manager 文档: https://cert-manager.io/docs/
  • acme.sh GitHub: https://github.com/acmesh-official/acme.sh
  • mkcert - 本地开发零配置 HTTPS: https://github.com/FiloSottile/mkcert
  • PKCS#12 RFC 7292: https://datatracker.ietf.org/doc/html/rfc7292
  • SSL Labs 服务器测试: https://www.ssllabs.com/ssltest/
  • ZeroSSL: https://zerossl.com/

本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可。