SSL 证书导出器
从各种来源收集并导出证书指标:
这些指标都标有证书中的字段,便于创建信息仪表盘和灵活的告警路由。
构建
make
./ssl_exporter <参数>
与 blackbox_exporter 类似,访问 http://localhost:9219/probe?target=example.com:443 将返回 example.com 的证书指标。ssl_probe_success
指标表示探测是否成功。
Docker
docker run -p 9219:9219 ribbybibby/ssl-exporter:latest <参数>
发布流程
- 在 Github 中创建带有语义化版本标签的发布,GH actions 将:
- 添加变更日志
- 上传二进制文件
- 构建并推送 Docker 镜像
用法
用法: ssl_exporter [<参数>]
参数:
-h, --help 显示上下文相关帮助(也可尝试 --help-long 和 --help-man)。
--web.listen-address=":9219"
监听 web 界面和遥测数据的地址。
--web.metrics-path="/metrics"
暴露指标的路径
--web.probe-path="/probe" 暴露探测端点的路径
--config.file="" SSL 导出器配置文件
--log.level="info" 仅记录给定严重级别或更高级别的日志消息。有效级别: [debug, info, warn, error, fatal]
--log.format="logger:stderr"
设置日志目标和格式。示例:
"logger:syslog?appname=bob&local=7" 或
"logger:stdout?json=true"
--version 显示应用版本。
指标
指标 | 含义 | 标签 | 探测器 |
---|---|---|---|
ssl_cert_not_after | 对等证书过期的日期。以 Unix 时间戳表示。 | serial_no, issuer_cn, cn, dnsnames, ips, emails, ou | tcp, https |
ssl_cert_not_before | 对等证书生效的日期。以 Unix 时间戳表示。 | serial_no, issuer_cn, cn, dnsnames, ips, emails, ou | tcp, https |
ssl_file_cert_not_after | 文件探测器找到的证书过期日期。以 Unix 时间戳表示。 | file, serial_no, issuer_cn, cn, dnsnames, ips, emails, ou | file |
ssl_file_cert_not_before | 文件探测器找到的证书生效日期。以 Unix 时间戳表示。 | file, serial_no, issuer_cn, cn, dnsnames, ips, emails, ou | file |
ssl_kubernetes_cert_not_after | Kubernetes 探测器找到的证书过期日期。以 Unix 时间戳表示。 | namespace, secret, key, serial_no, issuer_cn, cn, dnsnames, ips, emails, ou | kubernetes |
ssl_kubernetes_cert_not_before | Kubernetes 探测器找到的证书生效日期。以 Unix 时间戳表示。 | namespace, secret, key, serial_no, issuer_cn, cn, dnsnames, ips, emails, ou | kubernetes |
ssl_kubeconfig_cert_not_after | kubeconfig 探测器找到的证书过期日期。以 Unix 时间戳表示。 | kubeconfig, name, type, serial_no, issuer_cn, cn, dnsnames, ips, emails, ou | kubeconfig |
ssl_kubeconfig_cert_not_before | kubeconfig 探测器找到的证书生效日期。以 Unix 时间戳表示。 | kubeconfig, name, type, serial_no, issuer_cn, cn, dnsnames, ips, emails, ou | kubeconfig |
ssl_ocsp_response_next_update | OCSP 响应中的 nextUpdate 值。以 Unix 时间戳表示 | tcp, https | |
ssl_ocsp_response_produced_at | OCSP 响应中的 producedAt 值。以 Unix 时间戳表示 | tcp, https | |
ssl_ocsp_response_revoked_at | OCSP 响应中的 revocationTime 值。以 Unix 时间戳表示 | tcp, https | |
ssl_ocsp_response_status | OCSP 响应中的状态。0=正常 1=已吊销 2=未知 | tcp, https | |
ssl_ocsp_response_stapled | 连接状态是否包含附加的 OCSP 响应? 布尔值。 | tcp, https | |
ssl_ocsp_response_this_update | OCSP 响应中的 thisUpdate 值。以 Unix 时间戳表示 | tcp, https | |
ssl_probe_success | 探测是否成功? 布尔值。 | 全部 | |
ssl_prober | 导出器用于连接目标的探测器。布尔值。 | prober | 全部 |
ssl_tls_version_info | 使用的 TLS 版本。始终为 1。 | version | tcp, https |
ssl_verified_cert_not_after | 已验证链中证书的过期日期。以 Unix 时间戳表示。 | chain_no, serial_no, issuer_cn, cn, dnsnames, ips, emails, ou | tcp, https |
ssl_verified_cert_not_before | 已验证链中证书的生效日期。以 Unix 时间戳表示。 | chain_no, serial_no, issuer_cn, cn, dnsnames, ips, emails, ou | tcp, https |
配置
TCP
就像 blackbox_exporter 一样,你应该在刮取配置中通过巧妙的重新标记将目标传递给导出器的单个实例。这允许你利用服务发现并将配置集中在 Prometheus 配置中。
scrape_configs:
- job_name: "ssl"
metrics_path: /probe
static_configs:
- targets:
- example.com:443
- prometheus.io:443
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: 127.0.0.1:9219 # SSL 导出器。
HTTPS
默认情况下,导出器将与目标建立 TCP 连接。这适用于大多数情况,但如果你想利用 http 代理,可以通过设置 https
模块参数来使用 HTTPS 客户端:
scrape_configs:
- job_name: "ssl"
metrics_path: /probe
params:
module: ["https"] # <-----
static_configs:
- targets:
- example.com:443
- prometheus.io:443
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: 127.0.0.1:9219
这将使用环境变量 HTTP_PROXY
、HTTPS_PROXY
和 ALL_PROXY
发现的代理服务器。或者,你可以在模块配置中设置 https.proxy_url
选项。
后者优先级更高。
文件
file
探测器为本地文件中找到的 PEM 编码证书导出 ssl_file_cert_not_after
和 ssl_file_cert_not_before
。
可以通过提供目标参数来刮取导出器本地的文件:
curl "localhost:9219/probe?module=file&target=/etc/ssl/cert.pem"
目标参数支持通配(由 doublestar 包提供),允许你一次捕获多个文件:
curl "localhost:9219/probe?module=file&target=/etc/ssl/**/*.pem"
此探测器的一个特定用途可以是在 Kubernetes 中将导出器作为 DaemonSet 运行,然后刮取每个实例以检查每个节点上证书的过期时间:
scrape_configs:
- job_name: "ssl-kubernetes-file"
metrics_path: /probe
params:
module: ["file"]
target: ["/etc/kubernetes/**/*.crt"]
kubernetes_sd_configs:
- role: node
relabel_configs:
- source_labels: [__address__]
regex: ^(.*):(.*)$
target_label: __address__
replacement: ${1}:9219
HTTP 文件
http_file
探测器为指定 URL 中找到的 PEM 编码证书导出 ssl_cert_not_after
和 ssl_cert_not_before
。
curl "localhost:9219/probe?module=http_file&target=https://www.paypalobjects.com/marketing/web/logos/paypal_com.pem"
这是一个示例 Prometheus 配置:
scrape_configs:
- job_name: 'ssl-http-files'
metrics_path: /probe
params:
module: ["http_file"]
static_configs:
- targets:
- 'https://www.paypalobjects.com/marketing/web/logos/paypal_com.pem'
- 'https://d3frv9g52qce38.cloudfront.net/amazondefault/amazon_web_services_inc_2024.pem'
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: 127.0.0.1:9219
对于代理到目标资源,此探测器将使用在环境变量 HTTP_PROXY
、HTTPS_PROXY
和 ALL_PROXY
中发现的代理服务器。或者,你可以在模块配置中设置 http_file.proxy_url
选项。
后者优先级更高。
Kubernetes
kubernetes
探测器为类型为 kubernetes.io/tls
的密钥中找到的 PEM 编码证书导出 ssl_kubernetes_cert_not_after
和 ssl_kubernetes_cert_not_before
。
以 <命名空间>/<名称>
的形式提供密钥的命名空间和名称作为目标:
curl "localhost:9219/probe?module=kubernetes&target=kube-system/secret-name"
目标的命名空间和名称部分都支持通配符匹配(由 doublestar 包提供):
curl "localhost:9219/probe?module=kubernetes&target=kube-system/*"
curl "localhost:9219/probe?module=kubernetes&target=*/*"
导出器按以下顺序从以下来源检索凭证和上下文配置:
- 模块配置中的
kubeconfig
路径 $KUBECONFIG
环境变量- 默认配置文件 (
$HOME/.kube/config
) - 如果在 pod 中运行,则为集群内环境
- job_name: "ssl-kubernetes"
metrics_path: /probe
params:
module: ["kubernetes"]
static_configs:
- targets:
- "test-namespace/nginx-cert"
relabel_configs:
- source_labels: [ __address__ ]
target_label: __param_target
- source_labels: [ __param_target ]
target_label: instance
- target_label: __address__
replacement: 127.0.0.1:9219
Kubeconfig
kubeconfig
探测器为指定 kubeconfig 文件中找到的 PEM 编码证书导出 ssl_kubeconfig_cert_not_after
和 ssl_kubeconfig_cert_not_before
。
可以通过提供目标参数来刮取导出器本地的 kubeconfig:
curl "localhost:9219/probe?module=kubeconfig&target=/etc/kubernetes/admin.conf"
此探测器的一个特定用途可以是在 Kubernetes 中将导出器作为 DaemonSet 运行,然后刮取每个实例以检查每个节点上证书的过期时间:
scrape_configs:
- job_name: "ssl-kubernetes-kubeconfig"
metrics_path: /probe
params:
module: ["kubeconfig"]
target: ["/etc/kubernetes/admin.conf"]
kubernetes_sd_configs:
- role: node
relabel_configs:
- source_labels: [__address__]
regex: ^(.*):(.*)$
target_label: __address__
replacement: ${1}:9219
配置文件
你可以通过提供配置文件的路径来进行进一步的模块配置,使用 --config.file
参数。该文件以 yaml 格式编写,由以下模式定义。
# 默认使用的模块。如果省略,则必须通过 'module' 查询参数提供模块
default_module: <string>
# 模块配置
modules: [<module>]
<module>
# 探测类型(https、tcp、file、kubernetes、kubeconfig)
prober: <prober_string>
# 探测目标。如果设置,则忽略 'target' 查询参数。
# 如果省略,则需要 'target' 查询参数。
target: <string>
# 探测等待超时时间。
[ timeout: <duration> ]
# TLS 配置
[ tls_config: <tls_config> ]
# 特定探测配置
[ https: <https_probe> ]
[ tcp: <tcp_probe> ]
[ kubernetes: <kubernetes_probe> ]
[ http_file: <http_file_probe> ]
<tls_config>
# 禁用目标证书验证。
[ insecure_skip_verify: <boolean> | default = false ]
# 配置 TLS 重新协商支持。
# 有效选项:never、once、freely
[ renegotiation: <string> | default = never ]
# 用于目标的 CA 证书。
[ ca_file: <filename> ]
# 用于目标的客户端证书文件。
[ cert_file: <filename> ]
# 用于目标的客户端密钥文件。
[ key_file: <filename> ]
# 用于验证目标主机名。
[ server_name: <string> ]
<https_probe>
# 用于连接目标的 HTTP 代理服务器。
[ proxy_url: <string> ]
<tcp_probe>
# 在启动 TLS 之前使用 STARTTLS 命令(适用于支持的协议:smtp、ftp、imap、pop3、postgres)
[ starttls: <string> ]
<kubernetes_probe>
# 用于配置探测的 kubeconfig 文件路径
[ kubeconfig: <string> ]
<http_file_probe>
# 用于连接目标的 HTTP 代理服务器。
[ proxy_url: <string> ]
示例查询
7 天内过期的证书:
ssl_cert_not_after - time() < 86400 * 7
即将过期的通配符证书:
ssl_cert_not_after{cn=~"\*.*"} - time() < 86400 * 7
在验证链中 7 天内过期且最晚过期的证书:
ssl_verified_cert_not_after{chain_no="0"} - time() < 86400 * 7
服务器提供的证书数量:
count(ssl_cert_not_after) by (instance)
识别失败的探测:
ssl_probe_success == 0
对等证书 vs 验证链证书
对等证书和客户端构建的验证链的 NotAfter
和 NotBefore
字段都会导出指标。
前者仅包括目标明确提供的证书,而后者可能包含多个由客户端持有的根证书到目标服务器证书构建的信任链。
这在监控证书过期时有重要影响。
例如,ssl_cert_not_after
可能报告目标提供的根证书即将过期,即使客户端可以使用本地持有的另一个有效根证书形成另一个更长寿命的信任链。在这种情况下,你可能想使用 ssl_verified_cert_not_after
来警告过期,因为这将包含客户端实际构建的链:
ssl_verified_cert_not_after{chain_no="0"} - time() < 86400 * 7
导出器按过期时间的相反顺序为每个链编号,因此 chain_no="0"
是最晚过期的链。因此,上面的查询只会在导出器和目标之间的信任链真正接近过期时发出警报。
非常重要的是要注意,这种查询仅代表导出器和目标之间的信任链。真正的客户端可能持有不同于导出器的根证书,因此可能有不同的验证信任链。
Grafana
你可以在这里找到一个简单的仪表板,用于跟踪证书过期日期和目标连接错误。