AI Infra 训练营
总览
  • Day 1 · 集群起步 + CNI
  • Day 2 · 控制面 + etcd
  • Day 3 · CRD + Operator + Webhook
  • Day 4 · 存储深度
  • Day 5 · 卷扩容 + 安全
  • Day 6 · 调度 + 可观测
  • Day 7 · Harbor + ArgoCD + Mesh
  • Day 8 · AI Infra
  • Day 9 · Triton + GPU
  • Day 10 · MIG + HPA + 量化
  • Day 11 · AI Agent 端到端
  • Day 12 · 灾备
  • Day 13 · Operator + 联邦 + Mesh + RAG
  • Day 14 · CKA / CKS + 总结
  • LLM 训练手册
  • RAG + Agent 手册
  • 推理优化手册
  • 上下文工程手册
  • Agent 开发手册
  • 面试深度复盘
  • 训练 v2 深度手册
  • 心智模型
  • 看懂命令输出
  • 容器网络底层
  • K8s 网络深入
  • DNS 全套
  • 故障排查方法论
  • 心智模型
  • 容器挂载完整指南
  • K8s Volumes 大全
  • PV/PVC/CSI 深入
  • NFS 深入
  • 分布式存储概览
  • 故障排查 runbook
HiHuo 主站
GitHub
总览
  • Day 1 · 集群起步 + CNI
  • Day 2 · 控制面 + etcd
  • Day 3 · CRD + Operator + Webhook
  • Day 4 · 存储深度
  • Day 5 · 卷扩容 + 安全
  • Day 6 · 调度 + 可观测
  • Day 7 · Harbor + ArgoCD + Mesh
  • Day 8 · AI Infra
  • Day 9 · Triton + GPU
  • Day 10 · MIG + HPA + 量化
  • Day 11 · AI Agent 端到端
  • Day 12 · 灾备
  • Day 13 · Operator + 联邦 + Mesh + RAG
  • Day 14 · CKA / CKS + 总结
  • LLM 训练手册
  • RAG + Agent 手册
  • 推理优化手册
  • 上下文工程手册
  • Agent 开发手册
  • 面试深度复盘
  • 训练 v2 深度手册
  • 心智模型
  • 看懂命令输出
  • 容器网络底层
  • K8s 网络深入
  • DNS 全套
  • 故障排查方法论
  • 心智模型
  • 容器挂载完整指南
  • K8s Volumes 大全
  • PV/PVC/CSI 深入
  • NFS 深入
  • 分布式存储概览
  • 故障排查 runbook
HiHuo 主站
GitHub

openssl —— 证书 / 密钥 / TLS 调试工具箱

一句话定义

openssl 是 Linux 上最全能的密码学命令行工具:看证书、生成 key、签 CA、测 TLS、加解密、base64 ... 几乎所有"和加密 / 证书有关"的命令行操作都靠它。K8s 全靠 TLS 跑——证书排错绕不开 openssl。

典型场景

  • 看一个 cert 文件里有啥:openssl x509 -in cert.crt -text
  • 测远端 TLS 握手:openssl s_client -connect host:443
  • 看证书过期时间:openssl x509 -enddate -noout
  • 生成自签 CA + server cert(K8s 学习用)
  • base64 / 哈希等小工具

子命令架构

openssl <子命令> <参数...>

最常用:

子命令用途
x509看 / 操作 X.509 证书
rsa / ec / genpkey生成 / 查看私钥
req生成 CSR(证书请求)
s_client / s_serverTLS 客户端 / 服务端
verify验证证书链
pkcs12PKCS12 格式(.p12 / .pfx)
dgst哈希
enc对称加密
rand随机数

每个子命令独立 -help:

openssl x509 -help
openssl s_client -help

看证书:openssl x509

# 全文本
openssl x509 -in cert.crt -text -noout

# 只看关键字段
openssl x509 -in cert.crt -subject -noout
# subject=CN = www.example.com, O = Example Corp

openssl x509 -in cert.crt -issuer -noout
# issuer=CN = DigiCert Global Root CA, ...

openssl x509 -in cert.crt -enddate -noout
# notAfter=May 27 12:00:00 2027 GMT

openssl x509 -in cert.crt -startdate -enddate -noout
# notBefore=...
# notAfter=...

openssl x509 -in cert.crt -fingerprint -noout
# SHA1 Fingerprint=AA:BB:CC:...

openssl x509 -in cert.crt -fingerprint -sha256 -noout
# SHA256 Fingerprint=...

openssl x509 -in cert.crt -serial -noout
openssl x509 -in cert.crt -ext subjectAltName -noout
# X509v3 Subject Alternative Name:
#     DNS:www.example.com, DNS:example.com

-noout 阻止把证书原文重新输出。

快速看 K8s apiserver 证书

openssl x509 -in /etc/kubernetes/pki/apiserver.crt -text -noout \
  | grep -E 'Subject:|Subject Alternative Name:|Not (Before|After)'

Subject Alternative Name 是关键 —— 必须包含所有访问 apiserver 的 IP / 域名(VIP / 节点 IP / kubernetes.default 等)。


看远端服务的 TLS 证书:s_client

echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
  | openssl x509 -noout -subject -issuer -dates

-servername 设 SNI(关键,让对端知道你要哪个虚拟主机的证书)。

看完整握手细节

openssl s_client -connect example.com:443 -servername example.com
# 显示:
#   handshake 过程
#   提供的 cert chain
#   选用的 cipher
#   session info
#   ... 等输入 / Ctrl-D 关闭

看证书过期

echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
  | openssl x509 -noout -enddate
# notAfter=Apr 15 23:59:59 2027 GMT

封装成监控脚本:

expire=$(echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
  | openssl x509 -noout -enddate | cut -d= -f2)
expire_ts=$(date -d "$expire" +%s)
now_ts=$(date +%s)
days_left=$(( (expire_ts - now_ts) / 86400 ))
echo "Days until expiry: $days_left"

看证书链是不是完整

openssl s_client -connect example.com:443 -showcerts -servername example.com < /dev/null
# 显示完整 cert chain
# Certificate chain
#  0 s:/CN=example.com
#    i:/CN=DigiCert SHA2
#  1 s:/CN=DigiCert SHA2
#    i:/CN=DigiCert Global Root
# ---
# Verify return code: 0 (ok)

Verify return code: 0 (ok) —— 链验证通过。 Verify return code: 21 —— 中间证书缺失(最常见)。


生成私钥

# RSA 2048
openssl genrsa -out server.key 2048

# RSA 4096
openssl genrsa -out server.key 4096

# ECDSA P-256(现代推荐)
openssl ecparam -genkey -name prime256v1 -out server.key

# Ed25519(最现代)
openssl genpkey -algorithm ED25519 -out server.key

# 带密码保护
openssl genrsa -aes256 -out server.key 2048              # 提示输密码

K8s 证书一般 RSA 2048。SSL/TLS 现代场景用 ECDSA / Ed25519。


生成 CSR(让 CA 签名)

openssl req -new -key server.key -out server.csr -subj "/CN=example.com/O=Example Corp"

# 多 SAN(必加,浏览器不再认只看 CN 的证书)
openssl req -new -key server.key -out server.csr \
  -subj "/CN=example.com" \
  -addext "subjectAltName=DNS:example.com,DNS:www.example.com,IP:1.2.3.4"

CSR 是给 CA / 自签的输入。

看 CSR 内容

openssl req -in server.csr -text -noout

自签证书(学习 / 实验用)

全套自签 CA + server cert

# 1. 生成 CA 私钥
openssl genrsa -out ca.key 4096

# 2. 自签 CA 证书
openssl req -x509 -new -nodes \
  -key ca.key \
  -sha256 -days 3650 \
  -subj "/CN=My Self-Signed CA" \
  -out ca.crt

# 3. 生成 server 私钥
openssl genrsa -out server.key 2048

# 4. 生成 CSR
openssl req -new -key server.key \
  -subj "/CN=example.local" \
  -out server.csr

# 5. 用 CA 签 server cert
openssl x509 -req \
  -in server.csr \
  -CA ca.crt -CAkey ca.key -CAcreateserial \
  -out server.crt \
  -days 365 -sha256 \
  -extfile <(echo "subjectAltName=DNS:example.local,DNS:*.example.local")

# 6. 看结果
openssl x509 -in server.crt -text -noout

部署到 web server (nginx / haproxy) —— client 要信任 ca.crt:

# Ubuntu / Debian
cp ca.crt /usr/local/share/ca-certificates/my-ca.crt
update-ca-certificates

一步生成自签(不分 CA)

openssl req -x509 -newkey rsa:2048 -nodes \
  -keyout server.key -out server.crt \
  -days 365 \
  -subj "/CN=localhost" \
  -addext "subjectAltName=DNS:localhost,IP:127.0.0.1"

-nodes = no DES = 不给私钥设密码。


验证证书

openssl verify -CAfile ca.crt server.crt
# server.crt: OK

# 含中间证书
openssl verify -CAfile root-ca.crt -untrusted intermediate.crt server.crt

验证私钥和证书匹配

openssl x509 -in server.crt -noout -modulus | openssl md5
openssl rsa -in server.key -noout -modulus | openssl md5
# 两个 md5 应该一样 —— 一样表示 key 和 cert 配对

K8s 证书排错常用。


PKCS12 格式(.p12 / .pfx)

某些工具(Java keystore / Windows)用 PKCS12 而不是 PEM。

PEM → PKCS12

openssl pkcs12 -export \
  -in server.crt \
  -inkey server.key \
  -out server.p12 \
  -name "my-cert" \
  -passout pass:password

PKCS12 → PEM

openssl pkcs12 -in server.p12 -nokeys -out server.crt
openssl pkcs12 -in server.p12 -nocerts -nodes -out server.key

看 K8s 证书全套

kubeadm 集群的 PKI 都在 /etc/kubernetes/pki/:

ls /etc/kubernetes/pki/
# apiserver.crt              etcd/
# apiserver.key              apiserver-etcd-client.crt
# apiserver-kubelet-client.crt
# ca.crt   ca.key
# front-proxy-ca.crt   ...
# sa.key   sa.pub

# 批量看所有证书的过期时间
for f in /etc/kubernetes/pki/*.crt /etc/kubernetes/pki/etcd/*.crt; do
  echo "=== $f ==="
  openssl x509 -in $f -noout -subject -enddate
done

或者用 kubeadm 自带:

kubeadm certs check-expiration                          # 详见 kubeadm.md

TLS 服务端测试:s_server

启动一个 TLS 服务(测试 client 用):

openssl s_server -accept 4433 -cert server.crt -key server.key
# 监听 4433

另一个终端:

openssl s_client -connect localhost:4433

测试 mTLS:

openssl s_server -accept 4433 -cert server.crt -key server.key \
  -CAfile ca.crt -Verify 1
# -Verify 1 要求 client 出示 cert
openssl s_client -connect localhost:4433 \
  -cert client.crt -key client.key \
  -CAfile ca.crt

哈希 / base64 / 随机数

# 哈希
echo -n "hello" | openssl dgst -sha256
# SHA2-256(stdin)= 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824

# 文件哈希
openssl dgst -sha256 file.bin

# Base64
echo "hello" | openssl base64
# aGVsbG8K
echo "aGVsbG8K" | openssl base64 -d

# 随机字节
openssl rand -hex 16                                    # 32 字符 hex
# a1b2c3d4...

openssl rand -base64 32                                 # base64 编码
# 用作密码 / API key

openssl rand -out file 1024                              # 1024 字节随机数据

对称加密 / 解密

# 加密
openssl enc -aes-256-cbc -salt -in plain.txt -out encrypted.bin -k "my-password"

# 解密
openssl enc -aes-256-cbc -d -in encrypted.bin -out plain.txt -k "my-password"

# 用 PBKDF2 派生密钥(更安全)
openssl enc -aes-256-cbc -pbkdf2 -in plain.txt -out enc.bin

现代场景用 age / gpg 替代 openssl enc(更现代、更简单、更安全)。


实战场景

1. 排查"x509: certificate signed by unknown authority"

x509: certificate signed by unknown authority

说明 server 提供的证书链不完整 / client 不信任根 CA。

# 看 server 完整链
echo | openssl s_client -connect server:443 -showcerts -servername server 2>/dev/null \
  | sed -n '/BEGIN CERT/,/END CERT/p'

# 看 client 的根 CA
ls /etc/ssl/certs/ | head
# 或
cat /etc/ssl/certs/ca-certificates.crt | grep -c BEGIN

修:

  • server 配完整 chain(intermediate + leaf)
  • client 装对应根 CA

2. K8s apiserver SAN 缺少节点 IP

x509: certificate is valid for kubernetes.default.svc, not 10.0.24.99

apiserver 证书 SAN 没包含 10.0.24.99(新 VIP)。重生成证书:

# 备份
cp /etc/kubernetes/pki/apiserver.* /tmp/

# 删旧 cert
rm /etc/kubernetes/pki/apiserver.crt /etc/kubernetes/pki/apiserver.key

# 在 kubeadm-config 中加新 SAN
kubectl -n kube-system get cm kubeadm-config -o yaml > /tmp/kubeadm-config.yaml
# 编辑 apiServer.certSANs 加上新 IP,apply 回去

# 让 kubeadm 重生成
kubeadm init phase certs apiserver

# 看新证书
openssl x509 -in /etc/kubernetes/pki/apiserver.crt -text -noout | grep -A 1 'Subject Alternative'

# 重启 apiserver pod(动 manifest)
touch /etc/kubernetes/manifests/kube-apiserver.yaml

3. 私有 registry 自签证书

containerd 信任自签 registry:

# 节点上
mkdir -p /etc/containerd/certs.d/registry.example.com
cp registry-ca.crt /etc/containerd/certs.d/registry.example.com/ca.crt

# /etc/containerd/config.toml 启用 certs.d:
# [plugins."io.containerd.grpc.v1.cri".registry]
#   config_path = "/etc/containerd/certs.d"

systemctl restart containerd

4. 用 openssl 看 etcd 端点

echo | openssl s_client \
  -connect 10.0.24.28:2379 \
  -cert /etc/kubernetes/pki/etcd/healthcheck-client.crt \
  -key /etc/kubernetes/pki/etcd/healthcheck-client.key \
  -CAfile /etc/kubernetes/pki/etcd/ca.crt \
  2>/dev/null | head -30

mTLS 客户端测试 etcd。


常见踩坑

坑 1:openssl s_client 不加 -servername

openssl s_client -connect example.com:443
# 拿到错的证书(SNI 没设、server 给默认)

永远加 -servername(SNI):

openssl s_client -connect example.com:443 -servername example.com

坑 2:证书过期但本机时间不对

notAfter=2027-05-27
# 你机器时间: 2030-01-01
# 报错: certificate has expired

修:先校时(详见 chrony.md)。

坑 3:私钥被密码保护、自动化失败

openssl x509 -in cert.crt -text -noout                  # 不需要密码
openssl rsa -in encrypted.key -text -noout              # 提示输密码 → 脚本卡死

自动化场景用 unprotected key + OS 文件权限:

openssl rsa -in encrypted.key -out plain.key            # 解密保存
chmod 600 plain.key

或者用 K8s Secret(环境变量取密码)。

坑 4:忘了 SAN

openssl req -new -key key -out csr -subj "/CN=example.com"
# 浏览器拒:NET::ERR_CERT_COMMON_NAME_INVALID

现代浏览器只看 SAN、不看 CN(自 2017 Chrome 起)。永远加 SAN:

openssl req -new -key key -out csr \
  -subj "/CN=example.com" \
  -addext "subjectAltName=DNS:example.com"

坑 5:用 openssl rand 生密码、忘了去掉特殊字符

PASSWORD=$(openssl rand -base64 16)
# 输出含 /+= 等,URL / SQL 转义麻烦
openssl rand -hex 16                                    # 只含 0-9a-f
# 或
openssl rand -base64 32 | tr -d "+/="

坑 6:PEM 文件格式问题

cat cert.crt
# ... 看着对 ...
openssl x509 -in cert.crt -text
# unable to load certificate

可能:

  • DOS 行尾(\r\n)→ dos2unix cert.crt
  • 多 cert 拼接错乱 → 每个证书必须 -----BEGIN CERTIFICATE----- 到 -----END CERTIFICATE----- 完整 + 中间不能有空行外的字符
  • DER 格式(二进制)误当 PEM → openssl x509 -inform DER -in cert.der

坑 7:CA 和 server cert 不匹配

openssl verify -CAfile ca.crt server.crt
# error 20 at 0 depth lookup: unable to get local issuer certificate

CA 不是签 server 的那个。看:

openssl x509 -in server.crt -issuer -noout
# issuer=CN = Some Other CA           ← 不是你的 ca.crt 的 CN

要么换对的 CA、要么重签 server.crt。

坑 8:在线测但跨防火墙 / 代理

openssl s_client -connect example.com:443
# Connection timeout

防火墙 / 代理。用代理:

openssl s_client -proxy proxy.example.com:8080 -connect example.com:443

或者节点上跑(绕过本地网络)。

坑 9:用 -md5 等弱算法

openssl x509 ... -md5

MD5 / SHA1 已不安全。用 SHA256 或更高。

坑 10:openssl 命令换版本行为变

老 openssl 1.0 / 1.1 / 3.x 有些参数名 / 默认行为不同。生产脚本里查对版本:

openssl version
# OpenSSL 3.0.2 ...

不一致时 stack overflow / man page 多读几个版本。


关联命令

  • curl —— curl --cert / --key / --cacert 测 mTLS
  • kubeadm —— K8s PKI 在 /etc/kubernetes/pki/
  • etcdctl —— etcd mTLS 全套
  • ssh-keygen —— ssh 用 openssl 的算法,但工具不同
  • gpg / age —— 现代加密工具
  • cfssl —— Cloudflare 的更易用 PKI 工具
  • step (smallstep) —— 现代 PKI 工具集
在 GitHub 上编辑此页