四级渐进学习法 · CA 证书与 mTLS · 第 2/9 篇 · 从信封火漆到零信任

两张证书碰面,
才敢说「是我」。

四级台阶:L1 受控语言 → L2 结构图 → L3 交互网页 → L4 定制视频。先用五十余句确定性短句建立词汇(签名、证书链、EKU、SAN),再用五张结构图搭起骨架(信任链、证书解剖、单向握手、双向握手、八步校验),然后亲手推一次 mTLS 握手、逐字段拆解一张真实证书、做题自测,最后看一支 2 分 56 秒的解说片,把两张证书的相遇串成一个故事。

X.509 v3 · TLS 1.3 · RFC 5280 Root → Intermediate → Leaf 双向认证 · CertificateVerify · SAN 有效期新规:2026-03-15 起 200 天
THE FRAMEWORK

先看地图,再出发THE FRAMEWORK — 四层渐进,层层加深

CA 证书与 mTLS 做一件事:让两台机器在一条谁都能偷看的线上,互相确认「对面确实持有那把私钥」,然后才开始传数据。顺序是固定的——先有密钥对,再有 CA 把它们和身份绑成证书,再用证书完成握手,最后用证书里的身份去做授权。四级台阶对这个链条逐层下钻。

L1

受控语言

五十四句确定性短句。每句一概念、一词一义,无形容词、无脑补空间。读完即拥有完整词汇表。

例:「证书把公钥和身份绑在一起。签名由签发者的私钥产生。」
L2

结构图

五张确定性结构图:PKI 信任链(可点击)、X.509 证书解剖、单向握手时序、双向握手时序、八步校验流水线。

例:双向握手比单向只多一行 CertificateRequest。
L3

交互网页

亲手推一次握手:明文 / 单向 / 双向三种模式逐报文推进;再逐字段拆一张真实证书;十四题自测;末尾附 openssl 签发与排障参考。

例:切到双向模式,第 4 步多出的那条报文就是全部差别。
L4

定制视频

2 分 56 秒解说片:七镜头、画面 + 中文配音 + 内嵌字幕。从两台机器第一次见面讲到授权,一条线串完。

例:第 6 镜里那条红色报文,就是 mTLS 的全部秘密。

一句话本质

证书=公钥+身份+有效期+用途,被 CA 的私钥签了名。
验证=顺着签名一路追到本地预置的根证书。
mTLS=把「客户端验证服务端」这件事,反向再做一遍。
认证只回答「你是谁」;授权才回答「你能干什么」。
最容易死的地方:证书链没发全、SAN 忘了写、到期没人管。

一句话数据流(背下来,全页都在展开它)

密钥对 → CA 签发证书(公钥+身份+用途,CA 私钥签名)→ 服务端出示叶子+中间证书 → 客户端验签至根 CA → mTLS 时服务端发 CertificateRequest → 客户端出示自己的证书 + CertificateVerify 签名 → 双方验签通过 → 会话密钥加密传输 → 用证书里的 SAN/CN 去做授权

L1 CONTROLLED LANGUAGE

受控语言:五十四句讲清证书与 mTLS简短、确定、一词一义——不靠形容词,只靠事实

每句话都可以被验证,也都能在 L2 找到对应的图、在 L4 找到对应的命令。读不懂的句子,去 L2 找图;想动手的句子,去 L4 找命令。

底层事实

§ 0

证书是什么

§ 1

CA 与信任链

§ 2

八步校验

§ 3

TLS 握手

§ 4

mTLS 双向认证

§ 5

生命周期与运维

§ 6
L2 DIAGRAMS

结构图:从信任链到握手报文五张图从静态到动态,每张都可复现,图 1 可点击

先看信任怎么建立(图 1),再看一张证书里到底装了什么(图 2),然后把单向握手逐报文排开(图 3),再把 mTLS 的差异叠上去(图 4),最后把校验规则做成流水线(图 5)。

信任锚(离线) 签发层 终端证书 根 CA · root.crt 自签名 · 私钥离线 · 预置进信任库 CA:TRUE · pathlen:1 · keyCertSign 用 root.key 签 中间 CA · inter.crt 签发终端证书 · 被根 CA 签 CA:TRUE · pathlen:0 · keyCertSign 签 server.csr 签 client.csr 服务端证书 · server.crt EKU = serverAuth SAN = DNS:api.corp.local CA:FALSE · 有效期 90 天 客户端证书 · client.crt EKU = clientAuth SAN = URI:spiffe://…/svc/order CA:FALSE · 有效期 7 天 本地信任库 /etc/ssl/certs · cacerts 验证到根即终止 在名单里 → 可信 验证方向永远向上:叶子 → 中间 → 根。服务器发「叶子 + 中间」,根不发。
图 1 · PKI 三级信任链(点击任意节点查看职责与扩展要求)
点击图中的根 CA / 中间 CA / 两类叶子证书 / 信任库,这里显示它的职责、扩展写法与常见错误。
TBSCertificate(被签名的部分) version serialNumber signature issuer validity subject subjectPublicKeyInfo extensions · basicConstraints · keyUsage · extendedKeyUsage signatureValue v3 唯一编号 签名算法名 谁签的 起止时间 这是谁 公钥 + 算法 用途扩展 能不能签证书 能干什么 服务端/客户端 CA 的私钥签名 被签名的原始字节(TBS) CA 对上面这一整块算摘要,再用自己的私钥签名。 改任何一个字节,签名立刻验不过。 issuer 是**上一级的 subject** 这两串字符串相等,链才对得上;不等就是拼错了证书链。 validity 是绝对时间(UTC),不是天数 两端时钟差 5 分钟都可能报 not yet valid;容器不校时是高频事故。 subject 里的 CN 已不用于校验域名 域名写在 subjectAltName(SAN)里,可以写 DNS、IP、URI、邮箱。 extensions 是真正的判定区 basicConstraints → 能不能当 CA;pathLen → 还能挂几层 keyUsage → 能签证书 / 能签名 / 能加密 extendedKeyUsage → serverAuth 还是 clientAuth(mTLS 的分水岭) signatureValue 不参与摘要——它就是摘要被私钥运算后的结果
图 2 · 一张 X.509 v3 证书的字段解剖(左列字段,右列判定含义)
客户端(浏览器 / curl) 服务端(api.corp.local) ClientHello · SNI / key_share / sig_algs / ALPN ServerHello · key_share → 双方算出同一个 ECDHE 共享密钥 {EncryptedExtensions} ← 从这里起全部加密 {Certificate} · server.crt + 中间 CA {CertificateVerify} · 用 server.key 签握手摘要 {Finished} · 服务端握手记录校验值 {Finished} · 客户端握手记录校验值 应用数据 ⇄ AEAD 加密(客户端已验证服务端) 1-RTT 内完成
图 3 · TLS 1.3 单向认证:客户端验服务端,服务端不验客户端
客户端 client.crt + client.key 服务端 server.crt + 信任库 ClientHello · SNI / key_share / sig_algs ServerHello · key_share → ECDHE 共享密钥 {EncryptedExtensions} {CertificateRequest} · certificate_authorities = [Corp Root] ★ mTLS 唯一新增 {Certificate} · server.crt + 中间 CA {CertificateVerify} · server.key 签摘要 {Finished} {Certificate} · client.crt + 中间 CA {CertificateVerify} · client.key 签摘要 {Finished} 应用数据 ⇄ 双方证书均已验证 服务端 验客户端 链 / 有效期 EKU clientAuth 吊销状态 红色那一条是 mTLS 的全部秘密:服务端主动索要客户端证书,并声明可接受的 CA 列表。
图 4 · mTLS 双向握手:在单向握手中间插入 CertificateRequest,末尾多出三报文
客户端拿到 server.crt 之后,按顺序做八件事;任何一步失败,连接立刻中止 ① 验签 用上一级公钥解签名 比对摘要是否一致 ② 有效期 now ∈ [notBefore, notAfter] 两端时钟要对齐 ③ basicConstraints CA 必须 CA:TRUE 叶子必须 CA:FALSE ④ pathLen 限制还能挂几层中间 CA 超深即拒绝 ⑤ keyUsage CA 需 keyCertSign 签名需 digitalSignature ⑥ extendedKeyUsage serverAuth / clientAuth 写错就整条链白搭 ⑦ 主机名 SAN 里要有目标域名 CN 已不作为依据 ⑧ 吊销 CRL / OCSP / 短有效期 至少一种 全部通过 → 握手继续,开始传应用数据 客户端在 Finished 里回一个校验值,服务端确认「对端确实验过了」 任一步失败 → alert 报文,连接断开 典型:unknown authority / expired / bad certificate / hostname mismatch
图 5 · 证书校验八步流水线(顺序即 RFC 5280 路径校验的简化版)
L3 INTERACTIVE

交互探索:亲手推一次握手三种模式逐报文推进 + 证书逐字段拆解 + 十四题自测

先切到「双向 mTLS」,从第 0 步一路点到第 11 步,注意第 4 步那条红色报文。再切回「单向 TLS」重播一遍,两条时间线的差别会自己浮出来。然后往下拆证书字段、做题。

Corp Root CA 信任锚 · 双方信任库均预置 root.crt root.crt 客户端 client.crt / client.key EKU = clientAuth 空闲 服务端 server.crt / server.key EKU = serverAuth 空闲 — — 通道:明文

提示:切模式会重置到第 0 步;每一步的右侧日志是累积的,能倒回去看前面发生了什么。

双向 mTLS · 握手剧本

11 步推进,重点看第 4 步与第 8–10 步。

等待开始……
点「下一步」开始。
0 / 11
证书逐字段拆解CLICK A FIELD
server.crt · PEM → 解析后X.509 v3 · ECDSA P-256
点击左侧任一字段,这里给出它的作用、在验证中的位置,以及写错时会发生什么。建议从 subjectAltName、extendedKeyUsage、basicConstraints 这三个开始——生产事故大多出在这三行。

三条最容易记反的

· CA 证书的 subject 会出现在它签发证书的 issuer 里,两串必须逐字相等。
· 域名写进 SAN,不写 CN;CN 只留作人看的备注。
· 客户端证书写 clientAuth,服务端证书写 serverAuth;写反了握手一定失败,而且报错往往只说「bad certificate」。

概念自测14 QUESTIONS
得分 0 / 14
L3 REFERENCE · 实战参考

从签发到排障五条命令 · 三套配置 · 一张报错表 · 一次过期复盘

交互玩过之后,这里是能直接粘进终端的东西。命令在 bash 下可直接跑;配置片段只保留了与证书相关的行,其余按你的框架补。

一、签发一套三级 CA(bash)

5 分钟
step 1 — 根 CA(只做一次,私钥离线保管)
# P-256 比 RSA-2048 短得多,握手更快,现代客户端全都支持
openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256 -out root.key
openssl req -x509 -new -key root.key -sha256 -days 3650 \
  -subj "/CN=Corp Root CA/O=Corp/C=CN" \
  -addext "basicConstraints=critical,CA:TRUE,pathlen:1" \
  -addext "keyUsage=critical,keyCertSign,cRLSign" \
  -out root.crt
step 2 — 中间 CA(日常签发用它,有效期短于根)
openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256 -out inter.key
openssl req -new -key inter.key -subj "/CN=Corp Issuing CA/O=Corp" -out inter.csr

printf 'basicConstraints=critical,CA:TRUE,pathlen:0\n' > inter.ext
printf 'keyUsage=critical,keyCertSign,cRLSign\n' >> inter.ext
openssl x509 -req -in inter.csr -CA root.crt -CAkey root.key -CAcreateserial \
  -days 1825 -sha256 -extfile inter.ext -out inter.crt
step 3 — 服务端证书(SAN 必须写全)
openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256 -out server.key
openssl req -new -key server.key -subj "/CN=api.corp.local" -out server.csr

printf 'basicConstraints=critical,CA:FALSE\n' > server.ext
printf 'keyUsage=critical,digitalSignature\n' >> server.ext
printf 'extendedKeyUsage=serverAuth\n' >> server.ext
printf 'subjectAltName=DNS:api.corp.local,IP:10.20.30.40\n' >> server.ext
openssl x509 -req -in server.csr -CA inter.crt -CAkey inter.key -CAcreateserial \
  -days 90 -sha256 -extfile server.ext -out server.crt

# 交付给服务进程的是「叶子 + 中间」拼接,不是只有叶子
cat server.crt inter.crt > server-fullchain.crt
step 4 — 客户端证书(EKU 换成 clientAuth,身份放 SAN)
openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256 -out client.key
openssl req -new -key client.key -subj "/CN=svc-order" -out client.csr

printf 'basicConstraints=critical,CA:FALSE\n' > client.ext
printf 'keyUsage=critical,digitalSignature\n' >> client.ext
printf 'extendedKeyUsage=clientAuth\n' >> client.ext
printf 'subjectAltName=URI:spiffe://corp.local/ns/prod/sa/order\n' >> client.ext
openssl x509 -req -in client.csr -CA inter.crt -CAkey inter.key -CAcreateserial \
  -days 7 -sha256 -extfile client.ext -out client.crt
step 5 — 自检(先验链,再打一次真实握手)
# 只给叶子 + 中间,看能不能追到根
openssl verify -CAfile root.crt -untrusted inter.crt server.crt
# server.crt: OK

# 带上客户端证书打一次,服务端会要求对端证书
openssl s_client -connect api.corp.local:443 \
  -servername api.corp.local \
  -cert client.crt -key client.key \
  -CAfile root.crt -state

# 打印整张证书,检查四个扩展
openssl x509 -in server.crt -noout -text | grep -A1 -E "Subject Alternative|Key Usage|Basic Constraints"

二、三套接入配置(只摘证书相关行)

NGINX / GO / ENVOY
server {
    listen 443 ssl;
    server_name api.corp.local;

    # 必须是「叶子 + 中间」拼接;只配叶子会让部分客户端报链不完整
    ssl_certificate     /etc/ssl/corp/server-fullchain.crt;
    ssl_certificate_key /etc/ssl/corp/server.key;

    ssl_protocols       TLSv1.2 TLSv1.3;
    ssl_ciphers         HIGH:!aNULL:!MD5;

    # mTLS 三件套:用哪套 CA 验客户端、验不验、链最深深到几层
    ssl_client_certificate /etc/ssl/corp/root.crt;
    ssl_verify_client      on;
    ssl_verify_depth       2;

    # 可选:吊销列表(需要定期更新文件并 nginx -s reload)
    ssl_crl /etc/ssl/corp/root.crl;

    location / {
        # 把验证结果和客户端身份透给后端,授权在后端做
        proxy_set_header X-Client-Verify $ssl_client_verify;
        proxy_set_header X-Client-DN     $ssl_client_s_dn;
        proxy_set_header X-Client-Fingerprint $ssl_client_fingerprint;
        proxy_pass http://127.0.0.1:8080;
    }
}
cert, err := tls.LoadX509KeyPair("server-fullchain.crt", "server.key")
if err != nil { log.Fatal(err) }

pool := x509.NewCertPool()
pem, _ := os.ReadFile("root.crt")
pool.AppendCertsFromPEM(pem)

srv := &http.Server{
    Addr: ":8443",
    TLSConfig: &tls.Config{
        Certificates: []tls.Certificate{cert},
        ClientCAs:    pool,
        // 无证书直接拒绝;TLS 1.3 下这就是 mTLS 的开关
        ClientAuth:   tls.RequireAndVerifyClientCert,
        MinVersion:   tls.VersionTLS13,
    },
}

// 认证过了,还要授权:从 SAN 里取工作负载身份
http.HandleFunc("/orders", func(w http.ResponseWriter, r *http.Request) {
    if r.TLS == nil || len(r.TLS.PeerCertificates) == 0 {
        http.Error(w, "no client cert", 401); return
    }
    c := r.TLS.PeerCertificates[0]
    var id string
    for _, u := range c.URIs { id = u.String() }
    if !acl.Allowed(id, r.URL.Path) {
        http.Error(w, "forbidden", 403); return
    }
    io.WriteString(w, "ok")
})

srv.ListenAndServeTLS("", "")
# downstream:面向客户端(Agent / 上游服务)
transport_socket:
  name: envoy.transport_sockets.tls
  typed_config:
    "@type": type.googleapis.com/extensions.transport_sockets.tls.v3.DownstreamTlsContext
    require_client_certificate: true
    common_tls_context:
      tls_certificates:
      - certificate_chain: { filename: /certs/server-fullchain.crt }
        private_key:       { filename: /certs/server.key }
      validation_context:
        trusted_ca: { filename: /certs/root.crt }
        # 生产建议打开吊销检查;文件不存在时 fail-open 需显式声明
        crl: { filename: /certs/root.crl }

# 用 SAN 做授权:把 spiffe id 映射成 header 交给上游
# 或者直接上 RBAC:
#   principal: spiffe://corp.local/ns/prod/sa/order

三、报错对照表(把日志原文贴进来搜)

8 类高频
报错原文真实原因处理
certificate signed by unknown authority客户端信任库没有签发链的根;或服务端只发了叶子、没发中间证书导入根证书;服务端改配 fullchain
unable to get local issuer certificateopenssl 手工验证时没给中间证书加 -untrusted inter.crt
certificate relies on legacy Common Name field证书只有 CN,没有 SAN重签,把域名写进 subjectAltName
certificate has expired or is not yet valid真过期,或容器/主机时钟漂移先校时 chronyc tracking,再换证
remote error: tls: certificate required服务端要求客户端证书,客户端没配客户端加载 cert/key;或确认是否真的需要 mTLS
remote error: tls: bad certificate客户端证书 EKU 不是 clientAuth、链不对、或被吊销查 EKU 与签发 CA,不要只看 CN
incompatible key usage拿 CA 证书或 serverAuth 证书当客户端证书用用正确的叶子证书
握手成功但接口 403认证过了,授权没过——证书身份不在 ACL 里不是证书问题,查 SPIFFE/ACL 映射

四、三类 CA 怎么选

DECISION

公共 CA(Let's Encrypt / DigiCert …)

用在:面向公网的域名,任意浏览器或未知客户端都要能直接连。
代价:受 CA/B 规则约束,有效期 2026 年起 200 天、2029 年起 47 天;必须做 ACME 自动化。
不适合:内部服务身份——你无法给一万个 Pod 各申请一张公网证书。

私有 CA(自建 openssl / Vault / step-ca)

用在:内网 API、数据库、消息队列、设备接入;客户端是自己能控的。
代价:根证书要分发到每台机器的信任库;吊销、轮换、清单全得自己管。
关键:私有 CA 不受 47 天规则限制,但「有效期长」不等于「可以不轮换」。

服务网格自动签发(Istio / Linkerd / SPIRE)

用在:K8s 里东西向流量,服务数量大、生命周期短。
做法:Sidecar 或 ambient 模式自动签发 24 小时 SVID,自动轮换,身份是 spiffe://…。
代价:引入控制面复杂度;跨集群要规划信任域联邦。

五、一次真实事故复盘:证书过期那天

TIMELINE
T-90 天

证书签发,有效期 90 天

签发时没登记到期日,也没接监控。这张证书只存在于某个 Nginx 目录里。

T-30 天

本该有的告警没有出现

监控只探了 TCP 端口和 HTTP 200,没探 notAfter。端口一直通,所以一片绿。

T-0 00:00

整点,全部客户端同时失败

服务端日志刷 certificate has expired,客户端刷 x509: certificate has expired。连接不是变慢,是全部失败。

T+0 分钟

先判断方向,再动手

用 openssl s_client -connect host:443 | openssl x509 -noout -dates 确认是服务端证书问题,不是客户端信任库问题。两条命令分清责任方。

T+15 分钟

换证而不是改时间

不要靠改系统时间绕过。签发新证书、拼 fullchain、reload。若客户端做了证书固定(pinning),新证书指纹会让固定校验失败——这是短有效期时代最容易被忽略的坑。

T+1 天

把三件事补上

① 证书清单:域名、签发者、到期日、负责人、部署位置;② 到期告警:T-30 / T-7 / T-1 三档;③ 自动化:ACME 或 Vault 签发 + reload 钩子,人只处理失败。

六、术语速查

GLOSSARY
术语一句话
CA签发并担保证书的机构或程序。
CSR证书签名请求:把公钥和主体信息打包,请 CA 签名。
CNCommon Name,历史字段;域名校验已改看 SAN。
SANsubjectAltName,装 DNS / IP / URI 身份的地方。
EKUextendedKeyUsage,决定这张证书能当服务端还是客户端。
CRL / OCSP吊销名单 / 在线查询;短有效期正在取代它们。
SPIFFE / SVID工作负载身份标准 / 它签出的短期证书,身份写在 URI SAN。
ACME自动签发与续期的协议,Let's Encrypt 用的就是它。
1-RTTTLS 1.3 一个往返完成握手,比 TLS 1.2 少一个来回。
L4 VIDEO

定制视频:两张证书的相遇七镜头 · 2 分 56 秒 · 1920×1080 · 中文配音 + 内嵌字幕

一支片子讲完 CA 证书与 mTLS。七个镜头从「两台机器第一次见面」讲到「认证之后还要授权」,画面里的每一条报文(ClientHello / CertificateRequest / CertificateVerify)、每一个扩展名(SAN / EKU / pathLen)都与 L1–L3 同源。用 Remotion 逐帧渲染——画面即代码:同一时间轴,永远渲染出同一帧,改一个字重渲即可。

成片 · ca-mtls-explainer.mp4 ✓ 已交付

00:00 开场:两张证书碰面 00:14 密钥对:谁持有私钥 00:38 证书:给公钥开一张证明 01:04 信任链:一路追到根 01:32 单向 TLS:只验服务端 01:58 mTLS:互相验明正身 02:30 授权:认证之后

规格:1920×1080 · 30fps · 2:56 · H.264 + AAC · 中文配音(zh-CN-Yunxi,36 句逐句合成;每句实测时长都落在自己的字幕窗口内,最紧的一句 4.73s / 5.0s)+ 画面内嵌字幕。底部常驻六阶进度轨(密钥 → 证书 → 信任链 → 握手 → 双向 → 授权),随镜头推进点亮。

分镜脚本

7 镜头 · 旁白即片中字幕

镜头 1 · 开场:两张证书碰面

画面:客户端与服务端隔着一条虚线登场,线中间浮出红框「中间人:可读 / 可改 / 可冒充」。
旁白:两台机器,第一次见面。中间隔着一条谁都能看的线。凭什么相信对面?

镜头 2 · 密钥对:谁持有私钥

画面:私钥卡(上锁)与公钥卡(开锁)左右并置,中间双向箭头分别标「用私钥签名」「用公钥验证」,底部一条公式 sign → verify = ✓。
旁白:每台机器都有一对钥匙。私钥不出门,公钥随便给。私钥签的字,只有对应公钥能验过。签名证明的,是私钥在我手里。可这把公钥,到底是谁的?

镜头 3 · 证书:给公钥开一张证明

画面:server.crt 逐行展开——version、issuer、validity、subject、SAN、EKU、keyUsage,最后 signature 一行高亮为绿色。
旁白:证书,就是给公钥开的一张身份证明。里面写着公钥、身份与用途。最后一行,是签发 CA 的签名。改任何一个字节,签名立刻作废。所以证书不能自己证明自己,它靠谁签的。

镜头 4 · 信任链:一路追到根

画面:根 → 中间 → 终端三层竖排,左侧「本地信任库」虚线接入根,右侧一支向上箭头标「验证方向」,收尾弹出红字 unknown authority。
旁白:签发者,就叫 CA。根 CA 自签,靠预装进信任库获得信任。中间 CA 由根签,替它干活。验证时,顺着签名一路往上追。追到信任库里的根,就停。追不到,就断。

镜头 5 · 单向 TLS:只验服务端

画面:两条生命线,ClientHello 到 Finished 六条报文依次划过,末尾提示「客户端身份:未知」。
旁白:握手开始,先谈出一个会话密钥。然后服务端出示证书,证明自己是谁。客户端验链、验期、验用途。八条全过,才开始加密传数据。可服务端,始终不知道客户端是谁。

镜头 6 · mTLS:互相验明正身

画面:同一张时序图,第三条插入红色 CertificateRequest;从第六条起箭头方向反转,客户端出示证书与签名。
旁白:双向认证,只多了一句问话。服务端多发一条请求,要客户端出示证书。客户端回自己的证书,再加一段签名。服务端用证书里的公钥,验这段签名。到这一步,双方都确认对方持有私钥。中间人拿不到私钥,冒充不了任何一方。

镜头 7 · 授权:认证之后

画面:已认证身份 → 策略引擎 → 目标资源,两段箭头分别标「认证 ✓」「授权 ✓」;底部三件长期工程:短有效期、自动轮换、证书清单。
旁白:但认证,不等于授权。证书只说你是谁,不说你能干什么。能不能做,要拿身份去查策略。证书会过期,所以轮换必须自动。信任不是一次握手,是一条持续运转的链。

三道开放思考题(留给观众)

① 私有 CA 的根证书怎么分发到上万台终端,又能在一台失窃后精准撤销?
② 47 天有效期之下,你手上最不敢自动化的那张证书是哪张?为什么?
③ 服务网格替你轮换证书之后,谁还能说清某一次请求到底是谁发出的?

制作管线(Remotion · 画面即代码)

React 组件写画面 → 逐帧确定性渲染 → 1920×1080 H.264;旁白逐句 TTS(36 句,每句实测时长必须短于自己的字幕窗口,脚本逐句校验)→ 按时间轴 adelay 铺轨、统一响度(loudnorm −16 LUFS)→ 与画面合流。字体本地化落盘(Noto Serif SC / Noto Sans SC 分片 woff2,不联网取字)。时间轴与字幕表分离管理:改一句文案,只改 src/ca/timeline.ts 再重渲,画面、字幕、配音自动对齐。源码在 video/ 目录,出片与配音各一条命令。