本文为 SPIRE 官方文档 plugin_server_nodeattestor_x509pop.md 的中文译本,以英文原文为准。 🔗 穿越源码分析:Server 详解 · NodeAttestor
Server 插件:NodeAttestor "x509pop"
必须与 Agent 侧 x509pop 插件配合使用
x509pop 插件用于对那些通过带外(out-of-band)机制预置了 x509 身份的节点进行认证。它会验证证书是否根植于一组受信任的 CA,并向 agent 插件发起一次基于签名的持有性证明(proof-of-possession,PoP)挑战,以验证该节点确实持有对应的私钥。
插件生成的 SPIFFE ID 基于证书指纹(certificate fingerprint),该指纹定义为身份证书的 ASN.1 DER 编码的 SHA1 哈希。SPIFFE ID 的格式为:
spiffe://<trust_domain>/spire/agent/x509pop/<fingerprint>| Configuration | Description | Default |
|---|---|---|
mode | 若为 spiffe,则使用 spire server 自身的信任 bundle 进行校验;若为 external_pki,则使用指定的 CA。 | external_pki |
svid_prefix | 用于匹配有效 SVID 并将其兑换为 Node SVID 的 SVID 前缀。 | /spire-exchange |
ca_bundle_path | 磁盘上受信任 CA bundle 的路径。该文件必须包含一个或多个 PEM 块,构成用于信任链(chain-of-trust)校验的受信任根 CA 集合。如果 CA 证书分布在多个文件中,请改用 ca_bundle_paths。 | |
ca_bundle_paths | 磁盘上多个受信任 CA bundle 的路径列表。这些文件必须包含一个或多个 PEM 块,构成用于信任链校验的受信任根 CA 集合。 | |
agent_path_template | Agent SPIFFE ID 的 URL 路径部分格式,以 text/template 格式描述。 | 详见 Agent 路径模板(Agent Path Template) |
max_intermediates | 证书链中允许的中间证书(intermediate certificate)的最大数量。该上限有助于防止资源耗尽(resource exhaustion)攻击。 | 4 |
max_rsa_key_size | 证书中允许的 RSA 密钥的最大位数(bits)。该上限有助于防止来自超大密钥的资源耗尽攻击。 | 8192 |
verify_client_ip | 若为 true,则将连接对端(peer)的 IP 与叶子证书的 IP SAN 进行校验。如果没有任何 SAN 匹配,认证将失败。此处反映的是直接对端,在负载均衡器之后可能并不代表真实的客户端来源。 | false |
一份示例配置:
NodeAttestor "x509pop" {
plugin_data {
ca_bundle_path = "/opt/spire/conf/server/agent-cacert.pem"
# 修改 agent 的 SPIFFE ID 格式
# agent_path_template = "/cn/{{ .Subject.CommonName }}"
# 可选:中间证书的最大数量(默认:4)
# max_intermediates = 4
# 可选:RSA 密钥的最大位数(默认:8192)
# max_rsa_key_size = 8192
}
}Selectors(选择器)
| Selector | Example | Description |
|---|---|---|
| Common Name | x509pop:subject:cn:example.org | 主体(Subject)的通用名(Common Name)(参见 X.500 可辨别名称 Distinguished Names) |
| SHA1 Fingerprint | x509pop:ca:fingerprint:0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33 | PoP 链中每个证书(不含叶子证书)的 SHA1 指纹,以十六进制字符串表示。 |
| SerialNumber | x509pop:serialnumber:0a1b2c3d4e5f | 叶子证书的序列号,以小写十六进制字符串表示。 |
| San | x509pop:san:<key>:<value> | 叶子证书上的 SAN selector。URI SAN 的预期格式为 x509pop://<trust_domain>/<key>/<value>。每个符合 x509pop URI 方案(scheme)的 URI SAN 都会暴露一个 selector。 |
SVID 路径前缀(SVID Path Prefix)
当 mode="spiffe" 时,被兑换的 SPIFFE ID 必须带有所指定的 svid_prefix 前缀。在传递给 agent 路径模板之前,该前缀会从 .SVIDPathTrimmed 属性中被去除。如果 svid_prefix 设为 "",则允许所有前缀,此时限制逻辑必须在 agent_path_template 中自行实现。
示例: 如果你的信任域是 example.com,svid_prefix 设为其默认值 /spire-exchange,并且 agent_path_template 也保持默认,那么来自 x509 身份 spiffe://example.com/spire-exchange/testhost 的 SPIFFE ID 将被兑换为 spiffe://example.com/spire/agent/x509pop/testhost。如果给定的 SPIFFE ID 带有不同的前缀,例如 spiffe://example.com/other/testhost,则它与 svid_prefix 不匹配,将被拒绝。
Agent 路径模板(Agent Path Template)
指定 agent_path_template 的值提供了一种自定义 agent SPIFFE ID 生成格式的方式。每种 mode 的默认格式如下所示:
mode | agent_path_template |
|---|---|
spiffe | {{ .PluginName }}/{{ .SVIDPathTrimmed }} |
external_pki | {{ .PluginName }}/{{ .Fingerprint }} |
模板格式化器采用 Golang text/template 约定。它可以引用插件提供的值,或 golang x509.Certificate 中的值。关于模板引擎的详情,见模板引擎文档。
一些有用的值包括:
| Value | Description |
|---|---|
| .PluginName | 插件名称 |
| .Fingerprint | agent x509 证书的 SHA1 指纹 |
| .TrustDomain | 所配置的信任域 |
| .Subject.CommonName | agent x509 证书的通用名(common name)字段 |
| .SerialNumberHex | agent x509 证书的序列号字段,以小写十六进制表示 |
| .SVIDPathTrimmed | 去除 SVID 前缀后的 SVID 路径 |
| .URISanSelectors.<key> | 键为 <key> 的 URI SAN selector 的值 |