4、证书签发实战:使用根CA签发子CA、签发服务器证书、签发客户端证书

理论讲完了,咱们得真刀真枪干一场。

这一章,我会带你走完三条核心签发路径:根CA签子CA、根CA签服务器证书、根CA签客户端证书。说白了,就是把上一章生成的根CA密钥对用起来,让它真正干活。

我个人习惯把这三步叫做「证书家族三代人」——爷爷(根CA)生爸爸(子CA),爸爸给员工(服务器)和访客(客户端)发身份证。你想想看,如果爷爷亲自给每个员工发证,那爷爷得累死,而且风险极高。所以实际生产里,我们几乎都是用子CA来签发终端证书。

核心原则:根CA只做一件事——签发子CA。根CA的私钥签完子CA后,就应该离线冷存储,甚至锁进保险柜。服务器和客户端证书,全部由子CA签发。

4.1 使用根CA签发子CA证书

先来第一步:让根CA给子CA签个「出生证明」。

子CA本质上也是一个X.509证书,只不过它的CA标志位是TRUE,并且Path Length限制了它还能往下签几层。我一般设pathlen:0,意思是子CA只能签终端证书,不能再签下一级CA。

操作步骤:

  1. 生成子CA的私钥和证书签名请求(CSR)
# 生成子CA私钥(4096位,RSA)
openssl genrsa -out subca.key 4096

# 生成子CA的CSR
openssl req -new \
  -key subca.key \
  -out subca.csr \
  -subj "/C=CN/ST=Beijing/L=Beijing/O=MyOrg/OU=CA/CN=MyOrg SubCA 2025"
  1. 使用根CA签发子CA证书
openssl x509 -req \
  -in subca.csr \
  -CA rootca.crt -CAkey rootca.key \
  -CAcreateserial \
  -out subca.crt \
  -days 3650 \
  -extfile <(echo "
basicConstraints=critical,CA:TRUE,pathlen:0
keyUsage=critical,keyCertSign,cRLSign
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid:always,issuer
  ")

我的习惯:子CA有效期我设10年(3650天),根CA设20年。这样在子CA生命周期内,根CA只需要签一次。我曾经见过一个项目,子CA有效期只设了1年,结果每年都要把根CA从保险柜里请出来续签,运维成本极高。

  1. 验证子CA证书
openssl verify -CAfile rootca.crt subca.crt

如果输出subca.crt: OK,说明子CA证书链已经建立。你可以用下面命令看看子CA的细节:

openssl x509 -in subca.crt -text -noout | grep -A2 "CA:"

你会看到CA:TRUE, pathlen:0,嗯,这就对了。

4.2 签发服务器证书

服务器证书,就是你的Nginx、Apache、Tomcat等Web服务器用的SSL证书。它的核心要求是:Common Name (CN) 或 Subject Alternative Name (SAN) 必须包含服务器的域名或IP。

我强烈建议你只用SAN,别依赖CN。为什么?因为从Chrome 58开始,浏览器已经不再看CN字段了,只看SAN。我踩过这个坑——当年给一个内部系统签证书,只填了CN,结果所有用户访问时都报「证书名称不匹配」。后来老老实实加了SAN,问题才解决。

操作步骤:

  1. 生成服务器私钥和CSR
openssl genrsa -out server.key 2048

openssl req -new \
  -key server.key \
  -out server.csr \
  -subj "/C=CN/ST=Beijing/L=Beijing/O=MyOrg/OU=IT/CN=www.example.com"
  1. 创建SAN扩展配置文件
cat > server_ext.cnf <<EOF
[v3_req]
basicConstraints = CA:FALSE
keyUsage = critical,digitalSignature,keyEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names

[alt_names]
DNS.1 = www.example.com
DNS.2 = example.com
DNS.3 = api.example.com
IP.1 = 192.168.1.100
EOF
  1. 使用子CA签发服务器证书
openssl x509 -req \
  -in server.csr \
  -CA subca.crt -CAkey subca.key \
  -CAcreateserial \
  -out server.crt \
  -days 365 \
  -extfile server_ext.cnf \
  -extensions v3_req

注意:服务器证书有效期通常不超过1年(365天)。现在业界趋势是90天,比如Let's Encrypt。如果你做内部PKI,建议最长设398天(约13个月),这是主流浏览器允许的最大值。超过这个天数,Chrome会报安全警告。

  1. 验证服务器证书链
openssl verify -CAfile <(cat rootca.crt subca.crt) server.crt

这里需要把根CA和子CA的证书拼接在一起,形成完整的信任链。输出server.crt: OK才算通过。

4.3 签发客户端证书

客户端证书,说白了就是「你是谁」的证明。它常用于双向TLS认证(mTLS)、VPN登录、代码签名等场景。

客户端证书和服务器证书最大的区别在于extendedKeyUsage:服务器证书是serverAuth,客户端证书是clientAuth。如果你搞混了,客户端拿着服务器证书去认证,服务端会直接拒绝握手。

操作步骤:

  1. 生成客户端私钥和CSR
openssl genrsa -out client.key 2048

openssl req -new \
  -key client.key \
  -out client.csr \
  -subj "/C=CN/ST=Beijing/L=Beijing/O=MyOrg/OU=Dev/CN=zhangsan@example.com"
  1. 创建客户端证书扩展配置
cat > client_ext.cnf <<EOF
[v3_req]
basicConstraints = CA:FALSE
keyUsage = critical,digitalSignature,keyEncipherment
extendedKeyUsage = clientAuth
subjectAltName = @alt_names

[alt_names]
email.1 = zhangsan@example.com
EOF
  1. 使用子CA签发客户端证书
openssl x509 -req \
  -in client.csr \
  -CA subca.crt -CAkey subca.key \
  -CAcreateserial \
  -out client.crt \
  -days 365 \
  -extfile client_ext.cnf \
  -extensions v3_req
  1. 打包为PKCS12格式(可选,用于导入浏览器或系统)
openssl pkcs12 -export \
  -in client.crt \
  -inkey client.key \
  -out client.p12 \
  -name "MyOrg Client Cert" \
  -passout pass:changeit

避坑指南:我曾经给一个团队签发客户端证书,忘了加clientAuth扩展。结果所有客户端TLS握手都失败,报错certificate verify error。排查了整整半天才发现是EKU配错了。所以签发完一定要用下面命令检查:

openssl x509 -in client.crt -text -noout | grep -A1 "Extended Key Usage"

看到TLS Web Client Authentication才算正确。

4.4 三种证书对比一览

对比维度 根CA证书 子CA证书 服务器证书 客户端证书
CA标志 TRUE TRUE FALSE FALSE
Path Length ≥1 0 无 无
Key Usage keyCertSign, cRLSign keyCertSign, cRLSign digitalSignature, keyEncipherment digitalSignature, keyEncipherment
Extended Key Usage 无 无 serverAuth clientAuth
典型有效期 10-20年 5-10年 90-398天 1-3年
私钥存储 离线冷存储 在线HSM或加密 服务器本地 用户本地/浏览器

4.5 签发流程总览

下面这张图,把整个签发链路串起来了。你可以把它当作操作手册的封面图。

证书签发流程总览 证书签发流程总览 根CA(离线) 有效期20年 签发子CA 子CA(在线) 有效期10年 签发服务器证书 签发客户端证书 服务器证书 有效期≤398天 客户端证书 有效期1-3年 Nginx / Apache / Tomcat Web服务器SSL mTLS / VPN / 代码签名 身份认证

4.6 批量签发小技巧

如果你需要一次性签发几十上百张证书,逐条敲命令肯定不现实。我一般写个简单的Shell脚本,把CSR生成和签发流程自动化。

核心思路就三步:

  • 准备CSR清单:一个CSV文件,每行包含域名、组织、OU等信息
  • 循环生成CSR:用openssl req -new批量生成
  • 批量签发:用openssl x509 -req配合-CA参数统一签发

重要提醒:批量签发时,一定要给每个证书生成独立的私钥。千万别复用私钥!我曾经见过一个团队,为了省事,所有服务器都用同一个私钥。结果一台服务器被入侵,所有服务器的TLS连接都得重新签发。私钥复用 = 安全归零。

嗯,这一章的内容就到这里。你现在应该能独立完成根CA签子CA、签服务器证书、签客户端证书这三条链路了。记住:根CA离线、子CA在线、终端证书按需签发——这个架构能陪你走很久。