4、OPC UA证书管理:证书生命周期、CA搭建与CRL管理

证书管理,说白了就是OPC UA通信的“身份证系统”。我见过太多项目,安全策略配得再强,证书管理一塌糊涂,最后还是裸奔。今天咱们就把这块硬骨头啃下来。

4.1 证书生命周期——从出生到入土

一张OPC UA证书,跟人一样有完整的生命周期。我习惯把它分成六个阶段:

  1. 密钥生成:客户端/服务器自己造一对公私钥
  2. 证书签名请求(CSR):把公钥打包,申请官方盖章
  3. 证书签发:CA审核通过,发正式证书
  4. 证书部署:装到OPC UA应用里
  5. 证书使用:日常通信验证身份
  6. 证书吊销/过期:到期或出问题,证书作废

核心原则:私钥永远不出设备。CSR只传公钥部分,私钥必须留在本地。我在某汽车厂见过把私钥一起打包备份的,吓得我当场让他们销毁重做。

每个阶段都有坑。比如密钥生成,很多开发人员图省事用1024位RSA,现在至少得2048位,我建议直接上4096。为什么?你想想看,OPC UA设备生命周期动辄十年,现在省这点算力,过几年就得返工。

4.2 证书颁发机构(CA)搭建——自己当“公安局”

企业级OPC UA部署,我强烈建议自建CA。用公开CA?成本高、流程慢,而且你控制不了吊销。自己搭一个,说白了就是装个OpenSSL,然后按规矩办事。

4.2.1 根CA与中间CA的层级结构

我个人习惯用两级CA:根CA + 中间CA。根CA锁在保险柜里,平时不碰;中间CA负责日常签发。这样就算中间CA被黑,根CA还在,重新发一套就行。

# 生成根CA私钥(4096位,带加密)
openssl genrsa -aes256 -out root-ca-key.pem 4096

# 生成根CA自签名证书(有效期20年)
openssl req -x509 -new -nodes -key root-ca-key.pem \
  -sha256 -days 7300 -out root-ca-cert.pem \
  -subj "/C=CN/ST=Shanghai/L=Shanghai/O=MyCompany/CN=MyRootCA"

# 生成中间CA私钥
openssl genrsa -aes256 -out intermediate-ca-key.pem 4096

# 生成中间CA的CSR
openssl req -new -key intermediate-ca-key.pem \
  -out intermediate-ca.csr \
  -subj "/C=CN/ST=Shanghai/L=Shanghai/O=MyCompany/CN=MyIntermediateCA"

# 用根CA签发中间CA证书(有效期10年)
openssl x509 -req -in intermediate-ca.csr \
  -CA root-ca-cert.pem -CAkey root-ca-key.pem \
  -CAcreateserial -out intermediate-ca-cert.pem \
  -days 3650 -sha256 -extensions v3_ca

警告:根CA的私钥文件必须离线存储。我见过有人把根CA私钥放在NAS上共享,结果勒索病毒一锅端。正确的做法是:用U盘拷贝,锁进保险柜,签发时临时挂载。

4.2.2 OPC UA证书的扩展字段

OPC UA证书跟普通HTTPS证书不一样,它有几个强制扩展字段。少了任何一个,UA通信就会报错。我曾经排查过一个案例,折腾了两天,最后发现是extKeyUsage没配。

扩展字段 OPC UA要求 说明
keyUsage digitalSignature, nonRepudiation, keyEncipherment 必须包含这三个用途
extKeyUsage serverAuth / clientAuth 根据角色选一个或两个都加
subjectAltName URI / DNS / IP 必须包含应用的URI或主机名
basicConstraints CA:FALSE(终端证书) 终端证书不能当CA用
# 生成OPC UA服务器证书的CSR(带扩展字段)
openssl req -new -key server-key.pem \
  -out server.csr \
  -subj "/C=CN/ST=Shanghai/O=MyCompany/CN=opcua-server-01" \
  -reqexts v3_req -config <(cat openssl.cnf <(printf "\n[v3_req]\n\
keyUsage=digitalSignature,nonRepudiation,keyEncipherment\n\
extendedKeyUsage=serverAuth\n\
subjectAltName=URI:urn:MyCompany:OPCUA:Server01,DNS:server01.mycompany.com,IP:192.168.1.100\n"))

技巧:subjectAltName里的URI格式必须跟OPC UA应用的ApplicationUri完全一致。大小写、冒号、斜杠,一个字符都不能差。我习惯在部署前用openssl x509 -in cert.pem -text -noout检查一遍。

4.3 证书吊销列表(CRL)管理——让坏证失效

证书过期好办,到期自动失效。但私钥泄露、员工离职、设备退役,这些情况需要立即让证书失效。CRL就是干这个的。

4.3.1 CRL的生成与发布

CRL本质上是一张“黑名单”,由CA定期签发。OPC UA客户端在验证服务器证书时,会先查CRL。如果证书在列表里,直接拒绝连接。

# 生成初始CRL(有效期30天)
openssl ca -gencrl -out crl.pem \
  -config openssl.cnf -crldays 30

# 吊销一张证书(先拿到证书序列号)
openssl ca -revoke revoked-cert.pem \
  -config openssl.cnf \
  -crl_reason keyCompromise

# 重新生成CRL(包含已吊销的证书)
openssl ca -gencrl -out crl.pem \
  -config openssl.cnf -crldays 30

注意:CRL有有效期,过期后客户端会认为CA不可信。我建议CRL更新周期不超过7天,并且用脚本自动化。手动更新?你肯定会忘,我保证。

4.3.2 CRL分发点(CDP)配置

光生成CRL不够,还得告诉客户端去哪下载。这个信息写在证书的CRL Distribution Points扩展里。

# 在openssl.cnf中配置CDP
[ crl_ext ]
authorityInfoAccess = @issuer_info
crlDistributionPoints = @crl_info

[ crl_info ]
fullname = URI:http://crl.mycompany.com/opcua/crl.pem

[ issuer_info ]
caIssuers;URI.0 = http://crl.mycompany.com/opcua/ca-cert.pem

嗯,这里要注意:CDP的URL必须是OPC UA客户端能访问到的。如果客户端在隔离区(DMZ),你得确保HTTP服务开在白名单里。我遇到过客户把CRL服务器放在内网,结果外网设备连不上,证书验证全失败。

4.3.3 CRL与OCSP的选择

CRL有个缺点:列表越来越大,下载慢。OCSP(在线证书状态协议)可以实时查询单张证书状态,但需要OCSP响应器在线。我个人的建议:

  • 小规模部署(<100节点):CRL就够了,简单可靠
  • 大规模部署(>1000节点):上OCSP,配合CRL做降级备份
  • 中等规模:CRL + 增量CRL,只下载变化部分

最佳实践:不管用哪种方案,客户端必须配置“CRL检查失败时的行为”。我建议设为“拒绝连接”,而不是“忽略”。安全策略不能打折扣,宁可断网不可裸奔。

4.4 证书生命周期自动化——别用手工

手工管理证书?几十张还行,几百张上千张你试试?我见过一个工厂,IT管理员用Excel记证书到期时间,结果漏了三张,半夜产线停摆。自动化是唯一出路。

我推荐用证书生命周期管理平台,比如EJBCA、CFSSL,或者自己写脚本配合Ansible。核心功能:

  1. 自动生成CSR并提交CA
  2. 自动部署证书到目标设备
  3. 自动监控证书有效期,提前30天告警
  4. 自动吊销并更新CRL

下面是我用SVG画的一张证书生命周期管理流程图,把整个链条串起来:

OPC UA证书生命周期管理流程图 1. 密钥生成 RSA/ECC 4096位 2. CSR提交 包含公钥+扩展字段 3. CA签发 根CA/中间CA审核 4. 证书部署 安装到UA应用 5. 证书使用 TLS/签名验证 6. 吊销/过期 CRL/OCSP更新 CRL分发点(CDP) HTTP/HTTPS定期拉取 自动化监控平台 到期前30天告警 私钥永远不出设备,CRL更新周期≤7天 自动化是唯一出路,手工管理迟早出事

4.5 避坑指南——我踩过的雷

做了这么多年OT安全,证书管理这块的坑我基本都踩过。挑几个典型的说说:

  • 私钥权限:私钥文件权限必须设为600,属主是OPC UA运行用户。我曾经发现某厂商的OPC UA服务器私钥是644,任何用户都能读,等于把家门钥匙挂门口。
  • 证书存储路径:Windows用证书管理器,Linux用文件系统。我建议Linux下统一放/etc/opcua/certs/,别散落在各个目录。
  • 时钟同步:证书验证依赖系统时间。如果设备时间不准,有效证书可能被判过期。NTP必须配,而且得配多个源。
  • CRL缓存:客户端通常会缓存CRL,但缓存时间不能太长。我建议缓存时间不超过CRL有效期的1/3,比如CRL有效期7天,缓存设2天。

最后一句:证书管理不是一次性工作,是持续运营。把流程固化到运维体系里,用脚本和平台代替人工,你才能睡个安稳觉。