4. 证书签发与模板管理:CSR生成、模板定制与SAN配置
证书签发这件事,说白了就是回答三个问题:你是谁?谁给你担保?担保多久?但大规模环境下,这三个问题会变成:几千个设备分别是谁?怎么批量担保?怎么保证每个设备的SAN(Subject Alternative Name)都不写错?
我个人习惯把这一章拆成三个实操环节:CSR生成、模板定制、SAN与扩展属性。咱们一个一个来。
4.1 证书签名请求(CSR)生成
CSR是证书的“出生证明”。你向CA提交CSR,CA审核后签发证书。CSR里包含你的公钥和身份信息,私钥必须留在本地,绝不能随CSR一起发送。
4.1.1 使用OpenSSL生成CSR
最常用的工具就是OpenSSL。下面这个命令,我几乎每天都会敲几遍:
# 生成私钥(RSA 2048位)
openssl genrsa -out device.key 2048
# 生成CSR
openssl req -new \
-key device.key \
-out device.csr \
-subj "/C=CN/ST=Beijing/L=Beijing/O=MyCompany/OU=IoT/CN=device-001.example.com"
这里有个细节:-subj 里的CN(Common Name)最好和设备的主标识一致。我建议用设备的唯一标识符,比如序列号或FQDN。为什么?因为后面SAN配置会用到,保持一致性可以减少很多麻烦。
4.1.2 批量CSR生成策略
大规模环境下,一台台生成CSR会疯掉。我一般用两种方式:
| 策略 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 集中生成 | 设备有HSM或安全元件 | 私钥统一管理,审计方便 | 单点故障,网络开销大 |
| 边缘生成 | 设备本地生成CSR | 私钥不离开设备,安全性高 | 设备性能要求高,管理分散 |
我个人偏向边缘生成。你想想看,私钥如果集中存放,一旦被攻破,所有设备都得轮换。边缘生成虽然管理麻烦点,但安全边界更清晰。
#!/bin/bash
# 从设备清单文件读取,批量生成CSR
while IFS=',' read -r device_id fqdn; do
openssl req -new \
-newkey rsa:2048 -nodes \
-keyout "keys/${device_id}.key" \
-out "csrs/${device_id}.csr" \
-subj "/CN=${fqdn}/OU=IoT/O=MyCompany"
done < device_list.csv
4.2 证书模板定制
证书模板就是CA签发证书时的“配方”。你告诉CA:这个证书的有效期多长、密钥用途是什么、能不能做CA、SAN怎么填。模板定得好,后面轮换就省心。
4.2.1 模板的核心字段
我习惯把模板字段分成三类:身份类、用途类、约束类。
| 类别 | 字段 | 说明 | 我的建议值 |
|---|---|---|---|
| 身份类 | Subject | 证书主体的DN | CN=设备FQDN,O=公司名 |
| 用途类 | Key Usage | 密钥用途 | digitalSignature, keyEncipherment |
| 用途类 | Extended Key Usage | 扩展密钥用途 | serverAuth, clientAuth |
| 约束类 | Basic Constraints | 是否CA证书 | CA:FALSE(设备证书) |
| 约束类 | Validity | 有效期 | 90天(轮换周期短) |
4.2.2 使用OpenSSL配置文件定制模板
OpenSSL的配置文件是模板的载体。下面是我常用的设备证书模板:
[ req ]
default_bits = 2048
distinguished_name = req_distinguished_name
req_extensions = v3_req
prompt = no
[ req_distinguished_name ]
CN = device.example.com
O = MyCompany
OU = IoT
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth, clientAuth
subjectAltName = @alt_names
[ alt_names ]
DNS.1 = device.example.com
DNS.2 = device.local
IP.1 = 192.168.1.100
生成时指定配置文件:
openssl req -new -config device_template.conf -key device.key -out device.csr
嗯,这里要注意:prompt = no 表示不交互式输入,适合批量自动化。如果你需要调试,可以改成 prompt = yes。
4.3 SAN与扩展属性配置
SAN(Subject Alternative Name)是现代PKI的标配。从Chrome 58开始,浏览器已经不再信任仅依赖CN的证书了。SAN才是真正的“身份证明”。
4.3.1 SAN的类型与选择
| SAN类型 | 前缀 | 示例 | 适用场景 |
|---|---|---|---|
| DNS | DNS: | DNS:device-001.example.com | 域名访问的设备 |
| IP | IP: | IP:192.168.1.100 | 纯IP访问的设备 |
| URI | URI: | URI:spiffe://domain/device/001 | SPIFFE身份体系 |
我在项目中遇到过一个问题:设备同时有IPv4和IPv6地址,但只配了DNS SAN。结果IPv6链路通信时证书校验失败。从那以后,我要求所有设备证书至少包含一个DNS SAN和一个IP SAN。
4.3.2 扩展属性配置
除了SAN,还有一些扩展属性在大规模场景下非常有用:
- Authority Key Identifier:标识签发CA,方便证书链构建。我建议所有证书都带上。
- Subject Key Identifier:标识证书主体公钥,用于快速匹配。这个也建议必配。
- Certificate Policies:策略OID,用于标识证书用途。比如设备证书用1.3.6.1.4.1.12345.1.1。
- CRL Distribution Points:CRL分发点,告诉客户端去哪下载吊销列表。大规模环境必须配。
[ v3_ext ]
authorityKeyIdentifier = keyid:always,issuer
subjectKeyIdentifier = hash
certificatePolicies = @policy_section
crlDistributionPoints = @crl_section
[ policy_section ]
policyIdentifier = 1.3.6.1.4.1.12345.1.1
[ crl_section ]
fullname = URI:http://crl.example.com/device.crl
4.4 本章知识体系
下面这张图,是我自己梳理的CSR与模板管理流程。每次做新项目,我都会拿它来对一遍,防止漏掉环节。
这张图把整个流程串起来了。从设备身份信息输入,到CSR生成、模板定制、SAN配置,最后签发证书。每一步都有坑,但只要你按这个流程走,基本不会出大问题。
- CSR生成时,私钥必须留在设备本地,这是安全底线。
- 模板定制时,设备证书不要配CA权限,密钥用途要精确。
- SAN配置时,至少包含一个DNS和一个IP,别偷懒。
- 扩展属性里,AKI、SKI、CDP是必选项,别省略。