第3章 密钥对与证书生成:RSA/ECDSA密钥对、CSR与签名

说实话,TLS 配置里最绕不开的一步,就是生成密钥对和证书。我见过不少运维同事在这环节栽跟头——密钥权限设错了、CSR 信息填反了、签名扩展忘了加……每个坑都够你折腾半天。这一章咱们就把这些基础操作捋清楚,我保证,看完你就能自己动手走完一遍。

本章路线图:先把密钥对搞定,然后生成 CSR,最后签名拿证书。中间我会穿插一些真实踩坑记录,帮你避开那些我当年交过学费的坑。
密钥对与证书生成全流程 选择密钥算法 RSA 密钥生成 ECDSA 密钥生成 导出密钥对 创建 CSR 自签名证书 CA 签名证书 输出 .key / .crt / .csr 💡 私钥全程不离开本地,CSR 中可附加 SAN 扩展,签名方式按部署场景选择

3.1 选 RSA 还是 ECDSA?先看这张表

生成密钥对之前,得先定算法。RSA 和 ECDSA 是目前主流的两条路。我个人习惯:如果兼容性排第一,选 RSA;如果性能敏感、终端设备新,选 ECDSA。

对比维度RSAECDSA
安全性基础大整数分解椭圆曲线离散对数
推荐密钥长度2048–4096 位256–521 位
签名性能较慢快 3–5 倍
验证性能较快略慢于 RSA
证书体积较大小 30%–40%
兼容性最广泛,覆盖旧设备现代浏览器/系统均支持

我的建议:新项目直接上 ECDSA 曲线 prime256v1(也叫 secp256r1),性能和体积都占优。如果客户环境有 Windows Server 2012 或更老的系统,才考虑 RSA 2048。

3.2 生成 RSA 密钥对

RSA 密钥生成,说白了就是让 OpenSSL 帮你找两个大素数。命令很简单,但参数别写错。

# 生成 RSA 私钥(2048 位,带 AES-256 加密保护)
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 \
  -aes-256-cbc -out server.key

# 从私钥提取公钥
openssl pkey -in server.key -pubout -out server.pub

注意私钥文件生成时会提示你输入密码。有人觉得麻烦直接不加 -aes-256-cbc,我强烈建议别图省事——私钥裸奔,万一服务器被拖库,证书直接就废了。

⚠️ 私钥权限:生成后立刻执行 chmod 600 server.key,确保只有 root 或运行 TLS 服务的用户能读。我曾经在客户现场发现私钥是 644 权限,运维 team 任何人都能 cat 出来…… 嗯,当场就改了。

3.3 生成 ECDSA 密钥对

ECDSA 的密钥比 RSA 短得多,生成速度也更快。关键是要选对曲线。

# 推荐曲线:prime256v1(等效 secp256r1)
openssl genpkey -algorithm EC \
  -pkeyopt ec_paramgen_curve:prime256v1 \
  -aes-256-cbc -out server.key

# 查看曲线列表(挑你需要的)
openssl ecparam -list_curves | grep -E 'prime|secp'

# 提取公钥(和 RSA 命令一样)
openssl pkey -in server.key -pubout -out server.pub

曲线选型上我踩过坑。以前图新鲜试过 secp521r1,结果某些 CDN 边缘节点不支持,折腾了两天才定位到问题。现在老老实实用 prime256v1,兼容性最好。

💡 曲线速查:
· prime256v1 —— 最通用,IoT、CDN、浏览器全覆盖
· secp384r1 —— 合规要求高的场景(如政务、金融)
· secp521r1 —— 除非明确要求,否则别碰

3.4 创建 CSR(证书签名请求)

CSR 就是你去 CA 那里办证书的"申请表"。里面写了你的域名、公司信息、公钥,还有签名。

# 交互式(OpenSSL 会问你一堆问题)
openssl req -new -key server.key -out server.csr

# 非交互式(我推荐这种方式,避免手误)
openssl req -new -key server.key -out server.csr \
  -subj "/C=CN/ST=Beijing/L=Beijing/O=Example Inc./OU=IT/CN=www.example.com"

Subject 字段里最重要的就是 CN(Common Name),必须填域名。不过现在浏览器已经不怎么看 CN 了,真正起作用的是 SAN。所以——

核心要点:生成 CSR 时顺手写好 SAN 扩展。没有 SAN 的证书,Chrome 会直接挂红锁。我见过有团队上线前才发现 SAN 忘加,又重新走了一遍签发流程,耽误了两天。

SAN 扩展通常用一个 ext 文件指定:

# san.ext
subjectAltName = DNS:example.com, DNS:www.example.com, DNS:api.example.com

然后在签名时用 -extfile san.ext 带进去。后面 3.5 节会展示完整命令。

3.5 签名证书:自签名 vs CA 签名

CSR 拿到手,下一步就是签名。自签名适合测试和内网,CA 签名用于生产环境。

自签名证书(测试用)

openssl x509 -req -in server.csr -signkey server.key \
  -out server.crt -days 365 \
  -extfile san.ext

自签名证书浏览器会报警,因为根证书不在受信任列表里。你需要在客户端手动导入信任。

CA 签名(生产环境)

如果你们公司有自己的内部 CA,或者你从 Let's Encrypt 等外部 CA 申请证书,流程是这样的:

# 用 CA 私钥签署 CSR
openssl x509 -req -in server.csr \
  -CA ca.crt -CAkey ca.key -CAcreateserial \
  -out server.crt -days 365 \
  -extfile san.ext

这里 -CAcreateserial 会自动生成序列号文件,避免序列号冲突。如果你把序列号弄重复了,CA 签发的证书可能会出问题,我遇到过类似情况,排查起来很头疼。

签名方式适用场景浏览器信任有效期管理
自签名开发 / 内网测试否(需手动导入)自行控制
内部 CA 签名企业内部应用是(需部署 CA 根证书)CA 统一管理
公共 CA 签名生产环境公网服务是(全球信任)通常 90 天–1 年

3.6 避坑指南:我替你试过的错

  • 私钥加密别省:生成时加 -aes-256-cbc,虽然每次重启服务要输密码,但安全等级高一个档次。可以用 openssl rsa -in server.key -out server.nopass.key 解密后给自动化工具用,注意用完删临时文件。
  • CSR 的 CN 和 SAN 必须匹配:Chrome 从 2017 年起就只认 SAN 了。CN 填错了还能改,SAN 漏了证书就废了。我建议生成 CSR 前就把 san.ext 准备好。
  • 密钥长度不是越长越好:RSA 4096 比 2048 安全冗余高,但握手性能下降 30%–50%。对于绝大多数场景,RSA 2048 或 ECDSA prime256v1 足够。
  • 证书链别漏:CA 签名后拿到的 .crt 往往只包含终端证书,你需要手动拼接中间证书和根证书。少了中间证书,某些客户端会报"证书链不完整"。
  • 别忘了备份:私钥和 CSR 文件丢了,证书到期续签时会很麻烦。我用一个加密的 USB 盘做冷备份,每季度更新一次。
⚠️ 最严重的坑 —— 私钥泄露
如果怀疑私钥被非授权人员访问过,立即吊销证书并重新生成。不要抱有侥幸心理,我曾经处理过一个案例:私钥在 Git 仓库里躺了三个月,直到被安全扫描工具发现才紧急更换,期间所有加密流量理论上都可被解密。

好啦,这一章的内容就是这些。从密钥对生成到 CSR 再到签名,你只要按流程走,每一步盯着参数别写错,基本不会出大问题。下回你遇到同事在终端前犹豫不决,可以直接把这章的步骤丢给他——省得他再踩一遍我踩过的坑。