4、服务端证书签发:生成私钥、创建CSR、使用根CA签发证书

好,咱们接着往下走。上一章我们把根CA搭好了,相当于有了一个“身份证签发机关”。这一章,我们要给MQTT网关服务器办一张正式的“身份证”——也就是服务端证书。

整个过程分三步:生成服务端私钥 → 创建证书签名请求(CSR) → 拿根CA去签发。听起来不复杂,但每一步都有坑。我当年第一次部署生产环境时,就在CSR的Common Name上栽过跟头,后面细说。

核心逻辑:私钥是服务器的“秘密”,CSR是“申请表”,根CA是“审批盖章”。三者缺一不可。

服务端证书签发流程 服务端证书签发流程 ① 生成服务端私钥 openssl genrsa ② 创建CSR openssl req -new ③ 根CA签发证书 openssl x509 -req 输出:server.key 私钥文件(保密) 输出:server.csr 证书签名请求 输出:server.crt 签发的服务端证书 ⚠ 私钥必须保密,CSR可公开传输,最终产物是 server.key + server.crt 一对

4.1 生成服务端私钥

私钥是服务器的“数字指纹”,绝对不能泄露。我个人习惯用 2048位RSA,兼顾安全与性能。4096位当然更安全,但MQTT网关通常处理大量并发连接,密钥越长握手越慢,没必要。

执行命令:

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

你会看到类似这样的输出:

Generating RSA private key, 2048 bit long modulus (2 primes)
.............+++++
........................+++++
e is 65537 (0x010001)

嗯,这里要注意:私钥文件默认是明文存储的。如果服务器被入侵,私钥泄露,整个TLS体系就崩了。我在一个物联网项目里见过有人把私钥直接放在Git仓库里……那场面,简直是裸奔。

我的建议:生产环境一定要给私钥加密码保护。虽然每次重启服务需要手动输入密码,但可以用工具(如ssl-cert)配合systemd自动解锁。安全性和便利性要平衡。

加密码的命令也很简单:

# 生成带密码保护的私钥
openssl genrsa -aes256 -out server.key 2048

它会让你输入一个密码,至少12位,大小写+数字+符号。别偷懒。

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

CSR就是一张“申请表”,里面填了服务器的身份信息。根CA看到这张表,核实无误后才会签发证书。

创建CSR的命令:

openssl req -new -key server.key -out server.csr

执行后,它会交互式问你一堆问题。我直接给你一张表,告诉你每项该怎么填:

字段 说明 推荐值
Country Name (2 letter code) 国家代码 CN
State or Province Name 省份 Beijing
Locality Name 城市 Beijing
Organization Name 公司或组织名称 YourCompany Inc.
Organizational Unit Name 部门 IoT Department
Common Name 服务器域名或IP mqtt.yourcompany.com
Email Address 管理员邮箱 admin@yourcompany.com

⚠ 避坑指南:Common Name 是重中之重

我曾经帮一个客户排查TLS握手失败的问题,折腾了两天。最后发现,他的CSR里Common Name写的是“localhost”,但客户端连接的是公网域名。客户端验证证书时发现域名不匹配,直接拒绝连接。

记住:Common Name 必须填写客户端实际访问的域名或IP。如果MQTT网关有多个域名,建议用Subject Alternative Names(SAN),后面会讲。

如果你不想交互式输入,可以用一行命令搞定:

openssl req -new -key server.key -out server.csr \
  -subj "/C=CN/ST=Beijing/L=Beijing/O=YourCompany/OU=IoT/CN=mqtt.yourcompany.com"

这样更干净,适合脚本自动化。

4.3 使用根CA签发服务端证书

现在,我们拿着CSR去找根CA盖章。签发命令如下:

openssl x509 -req -in server.csr \
  -CA ca.crt -CAkey ca.key -CAcreateserial \
  -out server.crt -days 365 -sha256

参数解释:

  • -in server.csr:输入的CSR文件
  • -CA ca.crt -CAkey ca.key:根CA的证书和私钥
  • -CAcreateserial:自动创建序列号文件(ca.srl),用于唯一标识每张证书
  • -out server.crt:输出的服务端证书
  • -days 365:有效期1年。我建议别超过2年,定期轮换更安全
  • -sha256:摘要算法。别用SHA1了,早就不安全了

执行成功后,你会得到 server.crt。可以用这个命令查看证书内容:

openssl x509 -in server.crt -text -noout

输出里会包含签发者(Issuer)、有效期、公钥信息等。重点看 Issuer 是不是你的根CA,Subject 是不是你的服务器域名。

最终产物:你手上现在有三个关键文件:

  • server.key — 私钥,放服务器上,权限设为600
  • server.crt — 服务端证书,放服务器上,公开的
  • ca.crt — 根CA证书,客户端需要导入它来验证服务端

4.4 验证证书链

签发完了别急着部署。先验证一下证书链是否完整:

openssl verify -CAfile ca.crt server.crt

如果输出 server.crt: OK,说明证书链没问题。如果报错,多半是根CA证书没对上,或者证书过期。

我记得有一次,我在一个嵌入式设备上部署MQTT网关,证书链验证一直失败。查了半天,发现设备上的根CA证书是旧版本的,公钥对不上。重新导入一次就好了。这种问题最坑,因为OpenSSL报错信息很模糊。

小技巧:把验证命令写进CI/CD流水线,每次签发新证书自动跑一遍。省得手动检查。

4.5 关于SAN(Subject Alternative Names)

如果你的MQTT网关有多个域名或IP(比如内网用IP,外网用域名),Common Name只能填一个。这时候就需要SAN扩展。

创建一个 server.ext 文件:

subjectAltName = DNS:mqtt.yourcompany.com, DNS:mqtt2.yourcompany.com, IP:192.168.1.100

签发时加上 -extfile 参数:

openssl x509 -req -in server.csr \
  -CA ca.crt -CAkey ca.key -CAcreateserial \
  -out server.crt -days 365 -sha256 \
  -extfile server.ext

这样,客户端用任何一个域名或IP连接,证书验证都能通过。我强烈建议生产环境都用SAN,别省这一步。