3. 证书发现与资产盘点:如何自动发现网络中的设备证书

说实话,很多团队做证书管理,第一步就卡住了。

我问你一个问题:你手头到底有多少张设备证书?分布在哪些IP上?哪些快要过期了?

我见过不少运维同事,拍着胸脯说「证书都在CMDB里管着呢」。结果一查,CMDB里只录了三分之一。剩下的证书,散落在各个业务服务器、负载均衡器、甚至是开发测试环境里。嗯,这就是典型的「证书黑户」问题。

所以这一章,咱们就聊聊怎么把这些「黑户」揪出来。

3.1 证书发现的核心思路

证书发现,说白了就是回答三个问题:

  • 在哪找?——扫描范围
  • 怎么找?——扫描手段
  • 找到以后怎么办?——资产入库

我个人习惯把证书发现分成两个维度:

维度 目标 典型工具
主动扫描 从外部探测网络中的证书 nmap、sslscan、masscan
被动采集 从服务器本地读取证书文件 Agent、SSH命令、配置管理工具

你想想看,主动扫描适合「摸家底」,被动采集适合「精细化管理」。两者结合,才能把证书资产盘清楚。

核心原则:先粗后细,先扫后采。先用主动扫描把网络里的证书「照」出来,再用被动采集把证书的详细信息「拉」回来。

3.2 主动扫描:从外部发现证书

主动扫描是最直接的方法。我记得有一次帮一个金融客户做证书审计,他们说自己只有200张证书。我用nmap扫了一圈,好家伙,扫出来将近400张。多出来的那些,全是「僵尸证书」——证书还在,服务早停了。

3.2.1 使用nmap进行证书扫描

nmap的ssl-cert脚本,是发现证书的利器。来看一个例子:

# 扫描单个网段,发现所有HTTPS证书
nmap -p 443 --script ssl-cert 192.168.1.0/24

# 扫描多个常见端口
nmap -p 443,8443,9443 --script ssl-cert 10.0.0.0/8

# 输出为XML格式,方便后续处理
nmap -p 443 --script ssl-cert -oX cert_scan.xml 192.168.1.0/24

这个脚本能返回什么信息?我列一下:

  • 证书主题(Subject)
  • 颁发者(Issuer)
  • 有效期(Not Before / Not After)
  • 序列号
  • SAN(Subject Alternative Names)

小技巧:如果网段很大,建议先用masscan快速扫出开放443端口的IP,再用nmap做精细扫描。masscan号称「10分钟扫全网」,效率比nmap高一个数量级。

3.2.2 使用sslscan做深度检测

nmap能拿到证书基本信息,但如果你想看证书链是否完整、有没有弱加密套件,我推荐用sslscan。

# 扫描单个目标
sslscan --show-certificate example.com:443

# 批量扫描
for ip in $(cat ip_list.txt); do
  sslscan --show-certificate $ip:443 >> sslscan_output.txt
done

sslscan的输出里,我最关注的是证书链部分。曾经有个项目,客户说他们的证书是正规CA签发的,结果我一扫发现中间证书没配全,导致移动端访问报错。这种问题,光靠nmap是看不出来的。

3.3 被动采集:从内部获取证书

主动扫描有个局限——它只能发现对外暴露的证书。那些内部服务之间用的mTLS证书、Kubernetes集群里的Ingress证书,主动扫描是扫不到的。这时候就需要被动采集了。

3.3.1 通过SSH远程采集

对于Linux服务器,我习惯写一个采集脚本,通过SSH批量执行:

#!/bin/bash
# 采集服务器上的所有PEM证书文件

CERT_DIRS="/etc/ssl/certs /etc/pki /etc/kubernetes/pki /opt/app/certs"

for dir in $CERT_DIRS; do
  if [ -d "$dir" ]; then
    find "$dir" -name "*.crt" -o -name "*.pem" -o -name "*.cert" | while read cert; do
      echo "=== $cert ==="
      openssl x509 -in "$cert" -noout -subject -dates -issuer
    done
  fi
done

然后配合ansible或者pssh批量执行:

# 使用ansible批量采集
ansible all -m script -a "collect_certs.sh" -o cert_collection/

注意:采集脚本要处理好权限问题。有些证书文件只有root才能读。我建议用sudo执行,但要在脚本里做好日志审计,避免留下安全漏洞。

3.3.2 从Kubernetes集群采集

K8s环境里的证书,藏得比较深。我常用的方法是:

# 采集所有Secret中的证书
kubectl get secrets --all-namespaces -o json | jq -r '
  .items[] | 
  select(.type == "kubernetes.io/tls") |
  {namespace: .metadata.namespace, name: .metadata.name, 
   cert: .data["tls.crt"] | @base64d}
'

这里有个坑——很多团队把证书放在Secret里,但Secret的命名不规范。有的叫tls-secret,有的叫cert-secret,还有的直接叫my-cert。所以光靠名字过滤是不够的,必须按type来过滤。

3.4 资产入库与去重

证书找到了,接下来就是入库。这一步看似简单,但坑不少。

3.4.1 证书指纹:唯一标识

同一张证书可能出现在多个IP上(比如负载均衡场景)。怎么判断是不是同一张证书?看指纹。

# 计算证书的SHA256指纹
openssl x509 -in cert.pem -noout -fingerprint -sha256

我建议用SHA256指纹作为证书的唯一标识。为什么不用序列号?因为不同CA签发的证书,序列号可能重复。指纹是内容哈希,理论上不会重复。

3.4.2 资产表结构

这是我常用的证书资产表结构:

字段 类型 说明
fingerprint VARCHAR(64) SHA256指纹,主键
subject VARCHAR(512) 证书主题
issuer VARCHAR(512) 颁发者
not_before DATETIME 生效时间
not_after DATETIME 过期时间
san_list TEXT SAN列表,JSON格式
discovered_ips TEXT 发现该证书的IP列表
source VARCHAR(32) 发现方式:scan/agent/manual
first_seen DATETIME 首次发现时间
last_seen DATETIME 最近发现时间

经验之谈:一定要记录first_seen和last_seen。这两个字段能帮你发现「僵尸证书」——如果一张证书超过30天没被任何扫描任务发现,大概率已经没人用了。

3.5 自动化发现流程

手动扫描一次不难,难的是持续发现。我建议搭一个自动化流水线:

# 一个简单的定时任务示例(crontab)
# 每天凌晨2点执行全量扫描
0 2 * * * /opt/cert_monitor/scripts/full_scan.sh

# 每4小时执行增量扫描
0 */4 * * * /opt/cert_monitor/scripts/incremental_scan.sh

全量扫描和增量扫描的区别:

  • 全量扫描:扫所有网段,适合周末执行
  • 增量扫描:只扫新增IP或变更过的IP,适合工作日执行

我曾经踩过一个坑——全量扫描频率太高,把网络设备扫挂了。后来我学乖了,全量扫描控制在每周一次,增量扫描控制在每4小时一次。网络设备扛得住,数据也够实时。

3.6 本章知识体系

下面这张图,把证书发现与资产盘点的核心逻辑串起来了:

证书发现与资产盘点流程 主动扫描(外部探测) 被动采集(内部读取) nmap ssl-cert sslscan / masscan SSH + openssl K8s API + jq 证书数据汇聚与去重 证书资产表入库 定时扫描 + 增量更新 💡 核心原则 先扫后采,先粗后细

这张图你看懂了吗?从上到下,就是一条完整的证书发现流水线。从主动扫描和被动采集两条腿走路,到数据汇聚去重,再到资产入库,最后形成持续监控的闭环。

本章小结:证书发现不是一次性工作,而是一个持续的过程。我建议你从主动扫描入手,快速摸清家底;然后逐步建立被动采集能力,覆盖内部证书;最后用资产表把证书管起来,配合定时任务实现自动化发现。