本文为 SPIRE 官方文档 spire_agent.md 的中文译本,内容较长,以英文原文为准。 🔗 穿越源码分析:Agent 详解 · 职责与引导 · 整体架构
SPIRE Agent 配置参考
本文是 SPIRE Agent 的配置参考,内容涵盖插件类型(plugin type)、内置插件(built-in plugin)、Agent 配置文件、插件配置,以及 spire-agent 各命令的命令行选项。
插件类型
| 类型 | 说明 |
|---|---|
| KeyManager | 生成并存储 Agent 的私钥。可用于将密钥绑定到硬件等场景。 |
| NodeAttestor | 收集用于向服务端认证(attest)Agent 身份的信息。通常与同名的服务端插件配对使用。 |
| WorkloadAttestor | 探查某个工作负载(workload)以确定其属性,并生成与之关联的一组选择器(selector)。 |
| SVIDStore | 将 X509-SVID(私钥、叶子证书,以及可能存在的中间证书)、证书包(bundle)以及联邦证书包(federated bundle)存储到某个信任存储(trust store)中。 |
内置插件
| 类型 | 名称 | 说明 |
|---|---|---|
| KeyManager | disk | 将私钥写入磁盘的密钥管理器 |
| KeyManager | memory | 内存型密钥管理器,不持久化私钥(重启后必须重新认证) |
| NodeAttestor | aws_iid | 使用 AWS 实例身份文档(Instance Identity Document)认证 Agent 身份的节点认证器 |
| NodeAttestor | azure_imds | 使用 Azure 实例元数据服务(Instance Metadata Service)认证 Agent 身份的节点认证器 |
| NodeAttestor | azure_msi | 使用 Azure MSI 令牌认证 Agent 身份的节点认证器 |
| NodeAttestor | gcp_iit | 使用 GCP 实例身份令牌(Instance Identity Token)认证 Agent 身份的节点认证器 |
| NodeAttestor | join_token | 使用服务端生成的 join token 的节点认证器 |
| NodeAttestor | k8s_psat | 使用 Kubernetes 投射服务账号令牌(Projected Service Account token)认证 Agent 身份的节点认证器 |
| NodeAttestor | sshpop | 使用现有 ssh 证书认证 Agent 身份的节点认证器 |
| NodeAttestor | tpm_devid | 使用已预置 DevID 证书的 TPM 来认证 Agent 身份的节点认证器 |
| NodeAttestor | x509pop | 使用现有 X.509 证书认证 Agent 身份的节点认证器 |
| WorkloadAttestor | docker | 允许基于 docker 构造(如 label 与 image_id)生成选择器的工作负载认证器 |
| WorkloadAttestor | k8s | 允许基于 Kubernetes 构造(如 ns(namespace)与 sa(service account))生成选择器的工作负载认证器 |
| WorkloadAttestor | unix | 生成基于 unix 的选择器(如 uid 与 gid)的工作负载认证器 |
| WorkloadAttestor | systemd | 基于 systemd 单元属性(如 Id 与 FragmentPath)生成选择器的工作负载认证器 |
| SVIDStore | aws_secretsmanager | 一种 SVIDStore,将 Agent 有权获取的条目所对应的 X509-SVID 作为密文存入 AWS Secrets Manager。 |
| SVIDStore | gcp_secretmanager | 一种 SVIDStore,将 Agent 有权获取的条目所对应的 X509-SVID 作为密文存入 Google Cloud Secret Manager。 |
Agent 配置文件
下表列出了 SPIRE Agent 的配置选项。这些选项可以在配置文件顶层的 agent { ... } 段中设置。大多数选项都有对应的 CLI flag;若设置了该 flag,它将优先于文件中定义的值。
SPIRE 配置文件可以用 HCL 或 JSON 表示。完整示例请参见示例配置文件一节。
如果向 SPIRE 传入了 -expandEnv flag,则 $VARIABLE 或 ${VARIABLE} 形式的环境变量会在解析之前被展开。这在为配置文件做模板化时很有用,例如跨不同信任域复用配置,或用于插入 join token 之类的机密(secret)。
| 配置项 | 说明 | 默认值 |
|---|---|---|
admin_socket_path | 绑定 admin API socket 的位置(默认禁用) | |
allow_unauthenticated_verifiers | 允许 Agent 向未经认证的验证方(verifier)发放信任包 | false |
allowed_foreign_jwt_claims | 校验外部(foreign)JWT-SVID 时返回的受信任声明(claim)列表 | |
authorized_delegates | 已授权委派方(delegate)的 SPIFFE ID 列表。详见委派身份 API | |
data_dir | Agent 用于存放运行时数据的目录 | $PWD |
experimental | 实验性(experimental)选项,可能会变更或移除(见下文) | |
insecure_bootstrap | 若为 true,Agent 在引导(bootstrap)时不校验服务端身份 | false |
rebootstrap_mode | 可取 'never'、'auto' 或 'always' 之一 | never |
rebootstrap_delay | 在发现服务端 x509 证书不匹配后、开始重新引导(rebootstrap)之前的延迟时间 | 10m |
join_token | 由 SPIRE Server 生成的可选令牌(token) | |
join_token_file | 指向包含 SPIRE Server 所生成 join token 的文件路径 | |
log_file | 日志写入的文件 | |
log_level | 设置日志级别 <DEBUG|INFO|WARN|ERROR> | INFO |
log_format | 日志格式,<text|json> | Text |
log_selectors | 允许出现在诊断日志中的工作负载选择器前缀。选择器的值可能包含敏感信息;仅配置那些其值可以安全写入日志的前缀。示例:["k8s:ns", "k8s:sa", "unix:user"] | |
log_source_location | 若为 true,日志中包含源文件、行号和方法名字段(会带来少量运行时开销) | false |
profiling_enabled | 若为 true,启用 net/http/pprof 端点 | false |
profiling_freq | 将性能剖析(profiling)数据转储到磁盘的频率。仅当 profiling_enabled 为 true 且 profiling_freq > 0 时启用。 | |
profiling_names | 每个剖析周期(tick)会转储到磁盘的 profile 名称列表,参见 Profiling Names | |
profiling_port | net/http/pprof 端点的端口号。仅当 profiling_enabled 为 true 时使用。 | |
server_address | SPIRE Server 的 DNS 名称或 IP 地址 | |
server_port | SPIRE Server 的端口号 | |
socket_path | 绑定 SPIRE Agent API socket 的位置(仅 Unix) | /tmp/spire-agent/public/api.sock |
sds | 可选的 SDS 配置段 | |
trust_bundle_path | SPIRE Server CA 证书包的路径 | |
trust_bundle_url | 用于下载初始 SPIRE Server 信任包的 URL | |
trust_bundle_unix_socket | 让通过 trust_bundle_url 指定的请求改为对指定的 unix socket 发起。 | |
trust_bundle_format | 初始信任包的格式,pem 或 spiffe | pem |
trust_domain | 此 Agent 所属的信任域(trust domain)(长度不应超过 255 个字符) | |
workload_x509_svid_key_type | 工作负载 X509-SVID 的密钥类型 <rsa-2048|ec-p256|ec-p384> | ec-p256 |
availability_target | 期望能够平滑度过 SPIRE Server 或 Agent 停机的最短时长。该配置会影响 X509-SVID 轮换的激进程度。若设置,则至少为 24h。参见 Availability Target | |
x509_svid_cache_max_size | LRU 缓存中存储 X509-SVID 数量上限的软限制(soft limit) | 1000 |
jwt_svid_cache_max_size | LRU 缓存中存储 JWT-SVID 数量上限的硬限制(hard limit) | 1000 |
| experimental | 说明 | 默认值 |
|---|---|---|
named_pipe_name | 绑定 SPIRE Agent API 命名管道(named pipe)的管道名(仅 Windows) | \spire-agent\public\api |
sync_interval | 与 SPIRE Server 的同步间隔,采用指数退避(exponential backoff) | 5 sec |
use_sync_authorized_entries | 使用 SyncAuthorizedEntries API 定期同步已授权条目(authorized entry) | true |
require_pq_kem | 要求 TLS 握手使用抗量子安全(post-quantum-safe)的密钥交换方法 | false |
jwt_svid_cache_hit_timeout | 当缓存中已有有效 JWT-SVID 时,获取 NewJWTSVID 所用的自定义 gRPC 超时(介于 5 到 30s 之间) | 30s |
ratelimit | 针对 Workload API 与 SDS 方法的可选按调用方限流(rate limiting),在工作负载认证之后生效。详见 Workload API Rate Limiting。 | |
broker | 可选的 SPIFFE Broker API 端点配置。参见 SPIFFE Broker API。 |
Workload API Rate Limiting
ratelimit 配置块对 Workload API 与 Envoy SDS 方法施加按调用方(per-caller)的限流(rate limiting),以保护 Agent 免受"吵闹邻居"(noisy-neighbor)工作负载和重连风暴(reconnection storm)的影响。
该特性为实验性,位于 experimental 块之下。其配置在未来版本中可能变更或迁移(计划在 1.16/1.17 中转正或移除)。
键的解析方式: 限流在工作负载认证之后生效。调用方经认证得到的选择器集合(认证器返回的全部 type:value 对)被用作限流键——具有相同选择器集合的所有工作负载共享同一个令牌桶(token bucket),而选择器集合不同的工作负载之间互不干扰。无法被认证(选择器集合为空)的调用方共享单个 <unattested> 桶。Agent 自身的健康探针(health probe)不受限流约束。
| ratelimit | 说明 | 默认值 |
|---|---|---|
fetch_x509_svid | 每个选择器集合每秒对 FetchX509SVID 允许的最大流建立(stream open)数。0 表示禁用限流。 | 0 (disabled) |
fetch_jwt_svid | 每个选择器集合每秒对 FetchJWTSVID 允许的最大调用数。0 表示禁用限流。 | 0 (disabled) |
fetch_x509_bundles | 每个选择器集合每秒对 FetchX509Bundles 允许的最大流建立数。0 表示禁用。 | 0 (disabled) |
fetch_jwt_bundles | 每个选择器集合每秒对 FetchJWTBundles 允许的最大流建立数。0 表示禁用。 | 0 (disabled) |
stream_secrets | 每个选择器集合每秒对 SDS StreamSecrets 允许的最大流建立数。0 表示禁用。 | 0 (disabled) |
fetch_secrets | 每个选择器集合每秒对 SDS FetchSecrets 允许的最大调用数。0 表示禁用。 | 0 (disabled) |
对于流式 RPC(FetchX509SVID、FetchX509Bundles、FetchJWTBundles、StreamSecrets),限流在流建立时(即按每次重连)生效,而非按每条消息生效。
示例配置:
agent {
# ...
experimental {
ratelimit {
fetch_x509_svid = 100
fetch_jwt_svid = 500
fetch_x509_bundles = 20
fetch_jwt_bundles = 20
stream_secrets = 50
fetch_secrets = 50
}
}
}超过限流阈值的调用会收到 Unavailable gRPC 状态码。
服务端认证(Server Attestation)
Agent 需要能够与服务端建立受信任的网络连接。
一旦信任建立,Agent 会自动获取最新版本的信任包(trust bundle),以保持这些连接的安全。
有两种情况下无法做到这一点,此时必须执行服务端认证(Server Attestation)。
第一种情况是引导一个新 Agent 时。它从未与 SPIRE Server 进行过安全通信,因此无法下载最新的信任包。
第二种情况是信任丢失、必须重新建立,即所谓的重新引导(Rebootstrapping)。当 Agent 长时间无法联系服务端、导致其信任包过于陈旧,或服务端以无法保持信任包连续性的方式被重装时,就可能发生这种情况。
配置服务端认证的来源
共有三个主要选项和一个子选项:
- 若使用
trust_bundle_path选项,Agent 会从该路径下的文件读取引导信任包(bootstrap trust bundle)。你需要在启动 SPIRE Agent 之前安全地复制或共享该文件。 - 若使用
trust_bundle_url选项,Agent 会从指定 URL 读取引导信任包。- 若未设置 trust_bundle_unix_socket,出于安全考虑,该 URL 必须以
https://开头,且服务器必须持有有效证书(通过系统信任存储校验)。 这可用于快速部署 SPIRE Agent 而无需手动共享文件。请注意该 URL 的内容需要保持最新。 - 若设置了 trust_bundle_unix_socket,该 URL 必须以
http://开头。 这可以配合运行在该 socket 上的本地服务,通过某种站点特定的安全机制来获取最新的信任包。
- 若未设置 trust_bundle_unix_socket,出于安全考虑,该 URL 必须以
- 若将
insecure_bootstrap选项设为true,则 Agent 不会使用引导信任包,它会在不认证 SPIRE Server 的情况下与之连接。这不是一种安全的配置,因为中间人(man-in-the-middle)攻击者可能借此控制 SPIRE 基础设施。之所以保留该选项,是因为它在测试和开发中很有用。
这三个主要选项一次只能设置其中一个。
重新引导(Rebootstrapping)
有两个选项与重新引导相关。
rebootstrap_mode 可设置为 never、auto 或 always 之一。
- 设为
never时,Agent 将被禁止自动重新引导;一旦信任丢失,就需要人工恢复。 - 设为
always时,Agent 会在需要时尝试重新引导,使用trust_bundle_path、trust_bundle_url和/或trust_bundle_unix_socket设置再次认证服务端。重新引导的能力需要 Agent 的 NodeAttestor 插件以及服务端的配置共同支持。若插件、服务端和配置彼此不兼容,always模式会使 Agent 启动失败。 auto模式的行为与always相同,只是在不受支持时,它会自动禁用 Agent 的重新引导。
另一个选项是 rebootstrap_delay,默认值为 10m。它表示从首次发现某个不被 Agent 信任包信任的服务端,到开始重新引导流程之间需要等待的时长。在该延迟期内不允许进行任何重新引导。若在延迟期内成功建立了安全的服务端连接,延迟计时将被重置。
配置 rebootstrap_delay 时的考量:
- 在有人可能对 Agent 与服务端之间发起中间人攻击的环境中,将该时长设得更高可以尽量减少因不必要的重新引导而导致的 Agent 不可用。
- 将该时长设得更低,则可以在 Agent 离线过久、或服务端以无法保持信任包连续性的方式被重装时,更快地恢复 Agent 的信任。
SDS 配置
| 配置项 | 说明 | 默认值 |
|---|---|---|
default_svid_name | 在 Envoy SDS 中用于默认 X509-SVID 的 TLS 证书资源名 | default |
default_bundle_name | 在 Envoy SDS 中用于默认 X.509 证书包的 Validation Context 资源名 | ROOTCA |
default_all_bundles_name | 在 Envoy SDS 中用于全部证书包(含联邦证书包)的 Validation Context 资源名 | ALL |
disable_spiffe_cert_validation | 禁用 Envoy SDS 的自定义校验 | false |
Profiling Names
以下是可在 profiling_names 配置值中设置的可用 profile:
goroutinethreadcreateheapblockmutextracecpu
Availability Target
注意:availability_target 只影响 Agent 的 SVID 和工作负载 X509-SVID,不影响 JWT-SVID。
若设置了 availability_target,当某个 X509-SVID 的剩余生命周期达到 availability_target 时,Agent 就会轮换该 SVID。
为保证 availability_target,宽限期(grace period,即 SVID lifetime - availability_target)必须至少为 12h。若不满足,Agent 将按默认轮换策略(生命周期的 1/2)轮换 SVID。
插件配置
Agent 配置文件也包含 Agent 各插件的配置。插件配置位于 plugins { ... } 段下,其格式如下:
plugins {
pluginType "pluginName" {
...
plugin configuration options here
...
}
}可用于配置某个插件的选项如下:
| 配置项 | 说明 |
|---|---|
| plugin_cmd | 插件实现二进制文件的路径(可选,内置插件无需) |
| plugin_checksum | 插件二进制文件的可选 sha256 校验和(可选,内置插件无需) |
| enabled | 启用或禁用该插件(默认启用) |
| plugin_data | 插件专属数据(与 plugin_data_file 互斥) |
| plugin_data_file | 指向包含插件专属数据的文件路径(与 plugin_data 互斥) |
关于开箱即用的插件信息,请参见下文的内置插件一节。
示例
使用静态配置的内置插件
plugins {
SomeType "some_plugin" {
plugin_data = {
option1 = "foo"
option2 = 3
}
}
}使用动态配置的外部插件
在 agent.conf 中,使用 plugin_data_file 选项声明该插件,以从文件读取插件配置。
plugins {
SomeType "some_plugin" {
plugin_cmd = "./path/to/plugin"
plugin_checksum = "4e1243bd22c66e76c2ba9eddc1f91394e57f9f83"
plugin_data_file = "some_plugin.conf"
}
}然后在 some_plugin.conf 中放置插件配置:
option1 = "foo"
option2 = 3重新配置插件(仅 Posix)
使用动态配置源(即 plugin_data_file)的插件可以在运行时通过向 SPIRE Agent 发送 SIGUSR1 信号来重新配置。内置插件和外部插件均是如此。
SPIRE Agent 在收到该信号后会执行以下操作:
- 重新加载插件数据
- 将插件数据与之前的数据进行比较
- 若有变化,则用新数据重新配置该插件
遥测配置
关于如何配置 SPIRE Agent 输出遥测(telemetry)数据的更多信息,请参见遥测配置指南。
健康检查配置
Agent 可以暴露一个额外的端点用于健康检查。通过设置 listener_enabled = true 启用。目前它暴露两个路径:一个用于存活探测(liveness,Agent 是否已启动),另一个用于就绪探测(readiness,Agent 是否已准备好处理请求)。除非另行配置,健康检查端点默认监听 localhost:80。
health_checks {
listener_enabled = true
bind_address = "localhost"
bind_port = "8080"
live_path = "/live"
ready_path = "/ready"
}命令行选项
spire-agent run
上述所有配置文件选项都有完全对应的命令行形式。此外,还提供以下 flag:
| 参数 | 说明 | 默认值 |
|---|---|---|
-allowUnauthenticatedVerifiers | 允许 Agent 向未经认证的验证方发放信任包 | |
-config | SPIRE 配置文件路径 | conf/agent/agent.conf |
-dataDir | Agent 用于存放运行时数据的目录 | |
-expandEnv | 展开配置文件中的环境变量 $VARIABLES | |
-joinToken | 由 SPIRE Server 生成的可选令牌 | |
-joinTokenFile | 指向包含 SPIRE Server 所生成 join token 的文件路径 | |
-logFile | 日志写入的文件 | |
-logFormat | 日志格式,<text|json> | |
-logLevel | DEBUG、INFO、WARN 或 ERROR | |
-serverAddress | SPIRE Server 的 IP 地址或 DNS 名称 | |
-serverPort | SPIRE Server 的端口号 | |
-socketPath | 绑定 workload API socket 的位置 | |
-trustBundle | SPIRE Server CA 证书包的路径 | |
-trustBundleUrl | 用于下载 SPIRE Server CA 证书包的 URL | |
-trustDomain | 此 Agent 所属的信任域(长度不应超过 255 个字符) |
将 SPIRE Agent 作为 Windows 服务运行
在 Windows 平台上,SPIRE Agent 可以选择作为 Windows 服务运行。作为 Windows 服务运行时,唯一支持的命令是 run 命令。
注意:SPIRE 不会自动在系统中创建该服务,必须由用户创建。启动服务时,以 run 命令执行 SPIRE Agent 所需的全部参数都必须作为服务参数传入。
创建 SPIRE Agent Windows 服务的示例
> sc.exe create spire-agent binpath=c:\spire\bin\spire-agent.exe运行 SPIRE Agent Windows 服务的示例
> sc.exe start spire-agent run -config c:\spire\conf\agent\agent.confspire-agent api fetch
调用 workload API 获取一个 X509-SVID。该命令是 spire-agent api fetch x509 的别名。
| 参数 | 说明 | 默认值 |
|---|---|---|
-silent | 抑制标准输出(stdout) | |
-socketPath | SPIRE Agent API socket 的路径 | /tmp/spire-agent/public/api.sock |
-timeout | 等待响应的时间 | 1s |
-write | 将 SVID 数据写入指定路径 |
spire-agent api fetch jwt
调用 workload API 获取一个 JWT-SVID。
| 参数 | 说明 | 默认值 |
|---|---|---|
-audience | 以逗号分隔的 audience 值列表 | |
-socketPath | SPIRE Agent API socket 的路径 | /tmp/spire-agent/public/api.sock |
-spiffeID | 所请求 JWT 的 SPIFFE ID(可选) | |
-timeout | 等待响应的时间 | 1s |
spire-agent api fetch x509
调用 workload API 获取一个 x.509-SVID。
| 参数 | 说明 | 默认值 |
|---|---|---|
-silent | 抑制标准输出(stdout) | |
-socketPath | SPIRE Agent API socket 的路径 | /tmp/spire-agent/public/api.sock |
-timeout | 等待响应的时间 | 1s |
-write | 将 SVID 数据写入指定路径 |
spire-agent api validate jwt
调用 workload API 校验所提供的 JWT-SVID。
| 参数 | 说明 | 默认值 |
|---|---|---|
-audience | 以逗号分隔的 audience 值列表 | |
-socketPath | SPIRE Agent API socket 的路径 | /tmp/spire-agent/public/api.sock |
-svid | 待校验的 JWT-SVID | |
-timeout | 等待响应的时间 | 1s |
spire-agent api watch
连接到 workload API 并监听 X509-SVID 更新,在收到更新时打印详情。
| 参数 | 说明 | 默认值 |
|---|---|---|
-socketPath | SPIRE Agent API socket 的路径 | /tmp/spire-agent/public/api.sock |
spire-agent healthcheck
检查 SPIRE Agent 的健康状况。
| 参数 | 说明 | 默认值 |
|---|---|---|
-shallow | 执行较宽松的健康检查 | |
-socketPath | SPIRE Agent API socket 的路径 | /tmp/spire-agent/public/api.sock |
-verbose | 打印详细信息 |
spire-agent logger get
获取 SPIRE Agent 当前的日志级别。
| 参数 | 说明 | 默认值 |
|---|---|---|
-socketPath | SPIRE Agent Admin API socket 的路径 | /tmp/spire-agent/private/admin.sock |
spire-agent logger set
设置 SPIRE Agent 的日志级别。
| 参数 | 说明 | 默认值 |
|---|---|---|
-level | 新的日志级别,取值为 (panic, fatal, error, warn, info, debug, trace) 之一 | |
-socketPath | SPIRE Agent Admin API socket 的路径 | /tmp/spire-agent/private/admin.sock |
spire-agent logger reset
将 SPIRE Agent 的日志级别重置为启动时设定的级别。
| 参数 | 说明 | 默认值 |
|---|---|---|
-socketPath | SPIRE Agent Admin API socket 的路径 | /tmp/spire-agent/private/admin.sock |
spire-agent validate
校验一个 SPIRE Agent 配置文件。
| 参数 | 说明 | 默认值 |
|---|---|---|
-config | SPIRE Agent 配置文件路径 | agent.conf |
-expandEnv | 展开配置文件中的环境变量 $VARIABLES | false |
示例配置文件
本节提供一个示例配置文件,供格式与语法参考。
agent {
trust_domain = "example.org"
trust_bundle_path = "/opt/spire/conf/initial_bundle.crt"
data_dir = "/opt/spire/.data"
log_level = "DEBUG"
server_address = "spire-server"
server_port = "8081"
socket_path ="/tmp/spire-agent/public/api.sock"
}
telemetry {
Prometheus {
port = 1234
# optional TLS for prometheus
tls {
use_spire_svid = true
authorized_spiffe_ids = [
"spiffe://example.org/monitoring/prometheus",
]
# Alternatively, configure a web certificate directly:
# cert_file = "/path/to/cert.pem"
# key_file = "/path/to/key.pem"
# client_ca_file = "/path/to/ca.pem"
}
}
}
plugins {
NodeAttestor "join_token" {
plugin_data {
}
}
KeyManager "disk" {
plugin_data {
directory = "/opt/spire/.data"
}
}
WorkloadAttestor "k8s" {
plugin_data {
kubelet_read_only_port = "10255"
}
}
WorkloadAttestor "unix" {
plugin_data {
}
}
}委派身份 API(Delegated Identity API)
委派身份 API(Delegated Identity API)允许一个已授权的(即被委派的)工作负载,代表那些无法被 SPIRE Agent 直接认证的工作负载来获取 SVID 和证书包。
委派身份 API 通过 SPIRE Agent 的 admin API 端点提供服务。
请注意,这是明确且有意的设计:它赋予被授权的委派工作负载模拟(impersonate)任何它能获取 SVID 的其他工作负载的能力。任何被授权使用委派身份 API 的工作负载都会成为 SPIRE Agent 的"受信任委派方"(trusted delegate),并可以模拟并代表它从 SPIRE Agent 获取的所有工作负载 SVID 行事。
受信任委派方工作负载自身会先被 SPIRE Agent 认证,并将委派方的 SPIFFE ID 与已授权委派方的允许列表(allowlist)进行比对。
一旦满足这些要求,受信任委派方工作负载就可以为其所交互的 SPIRE Agent 实例范围内的任意工作负载获取 SVID。
受信任委派方工作负载有两种方式可以向 SPIRE Agent 为其他工作负载请求 SVID:
由委派方自己认证另一个工作负载,构建出一组选择器,然后通过委派身份 API 将这些选择器提供给 SPIRE Agent。 在这种方式下,受信任委派方工作负载完全负责认证另一个工作负载并构建经认证的选择器。 当这些选择器被提交给 SPIRE Agent 时,SPIRE Agent 只会为任何与所提供选择器匹配的工作负载注册条目返回 SVID, 不会执行其他任何检查或认证。
由委派方获取另一个工作负载的 PID,并通过委派身份 API 将该 PID 提供给 SPIRE Agent。 在这种方式下,SPIRE Agent 会对所提供的 PID 执行认证,构建经认证的选择器,并为任何与 SPIRE Agent 从该 PID 认证出的选择器匹配的工作负载注册条目返回 SVID。 这与前一种方式的区别在于,是由 SPIRE Agent 自身(而非受信任委派方)来处理对另一个工作负载的认证。 在大多数平台上,PID 并不是稳定的标识符,因此受信任委派方工作负载必须确保:它通过委派身份 API 提供给 SPIRE Agent 用于认证的 PID,在委派方发起委派身份 API 请求到获得响应这段时间内不会被回收复用。 如何做到这一点因平台而异,由受信任委派方负责(例如在 Linux 上使用 pidfd)。 通过委派身份 API 为某个 PID 获取的认证结果,在该 PID 所指进程终止或被重新认证之前(以先发生者为准)一直有效。
要启用委派身份 API,请配置 admin API 端点地址以及已授权委派方的 SPIFFE ID 列表。例如:
Unix 系统:
agent {
trust_domain = "example.org"
...
admin_socket_path = "/tmp/spire-agent/private/admin.sock"
authorized_delegates = [
"spiffe://example.org/authorized_client1",
"spiffe://example.org/authorized_client2",
]
}Windows:
agent {
trust_domain = "example.org"
...
experimental {
admin_named_pipe_name = "\\spire-agent\\private\\admin"
}
authorized_delegates = [
"spiffe://example.org/authorized_client1",
"spiffe://example.org/authorized_client2",
]
}SPIFFE Broker API
SPIFFE Broker API 允许一个已授权的基础设施组件(即"中介",broker)代表其所引用的工作负载获取 SVID 和信任包,而无需工作负载自己连接 SPIRE Agent。它实现了 SPIFFE Broker API 规范,由 SPIRE Agent 通过一个专用的、双向认证的端点提供服务,该端点独立于 Workload API。
状态: 实验性。随着上游 SPIFFE 规范逐渐成熟,Broker API 正在稳定化;在该配置移出
experimental之前,可能出现破坏性变更。
它与现有各 API 的区别:
- Workload API 由工作负载自己调用以获取其自身的 SVID, 工作负载通过其 socket 对端凭据(peer credentials)被隐式认证。
- 委派身份 API 允许已授权委派方模拟 Agent 范围内的任意工作负载; 委派方负责标识目标工作负载(通过选择器或 PID)。
- Broker API 同样属于委派式——中介提交一个用于标识工作负载的
WorkloadReference,Agent 针对该引用运行其已配置的工作负载认证器栈以生成 选择器。与委派身份 API 不同的是,中介绝不会手动提供选择器;对于某个引用 适用哪些选择器,Agent 自己的认证器始终是权威来源(source of truth)。这使得 Broker API 可以安全地跨网络(通过 mTLS)暴露,而不仅限于本地 UDS。
该规范目前定义了两种引用类型(reference type):
WorkloadPIDReference——Agent 所在节点上的一个进程 ID。根据 SPIFFE Broker API §3.1.2, 这是一个本地引用,不应跨越网络边界。 SPIRE Agent 通过每个中介的allowed_reference_types[].allow_over_tcp设置在服务端强制这一点(参见 配置),该设置默认为 false:除非运维人员显式为该引用类型开启, 否则 TCP 请求会被拒绝。KubernetesObjectReference——任意 Kubernetes 对象,由type(resource 与 group) 加上key(namespace 与 name)和/或uid标识。当 SPIRE Agent 的k8s工作负载 认证器的allowed_reference_types包含type.googleapis.com/spiffe.broker.KubernetesObjectReference时,它可以支持该 引用类型,并发出描述该对象的选择器(对于 Pod 为k8s:pod-name等;对于其他任意 资源则为通用的k8s:resource、k8s:kind、k8s:name等)。
当 k8s 工作负载认证器处理 Broker API 的 AttestReference 调用时, 对每一种引用类型都需要其插件级的 experimental.broker 块。将 experimental.broker.access_policy = "enforced" 设置后,认证器会运行 Kubernetes SubjectAccessReview 检查:对 WorkloadPIDReference 针对解析出的 Pod 进行检查, 对 KubernetesObjectReference 针对被引用对象进行检查。将 experimental.broker.access_policy = "permissive" 设置则跳过这些检查。该设置是 必填的,没有默认值。
传输与认证
Broker API 通过基于 X.509-SVID 的双向 TLS(mutual TLS)加以管控。中介应 先通过 Workload API 获取其自身的 SVID,然后用该 SVID 去拨号(dial)中介端点。 Agent 出示自己的 SVID,并将中介的证书与已配置的按中介(per-broker)允许列表进行 校验。
根据规范,每个请求都必须携带 broker.spiffe.io: true 这一 gRPC 元数据(metadata)头,作为对 SSRF 的缓解措施。SPIRE Agent 会以 InvalidArgument 拒绝缺少该头的请求。这适用于_每一个_方法,包括 gRPC 服务端反射 (server reflection,仅通过 UDS 提供)。grpcurl/grpcui 之类的工具默认不 发送该头,因此反射调用必须显式设置它,例如:
grpcurl -unix -rpc-header 'broker.spiffe.io: true' /path/to/broker.sock list配置
通过在 Agent 配置的 experimental 下添加一个 broker 块来启用该端点。 socket_path(仅 POSIX 的 UDS)或 bind_address(TCP,所有平台)至少必须设置 其一;两者也可同时设置。
socket_path 不得与 Workload API socket 位于同一目录——否则 SPIRE Agent 将拒绝 启动。
brokers 中的每个条目列出一个已授权中介的 SPIFFE ID(允许跨信任域身份)以及 它可以使用的引用类型。allowed_reference_types 列表是必填的,且必须至少包含 一个对象。每个对象都需要 type_url,即逐字的 protobuf type URL。仅当某引用类型 在网络上是安全的时,才在对应条目上设置 allow_over_tcp = true;它默认为 false, 因此允许 UDS 但拒绝 TCP。使用单个 type_url = "*" 的对象可以允许 Agent 认证器栈 所能理解的任意引用类型。
agent {
trust_domain = "example.org"
...
experimental {
broker {
socket_path = "/run/spire/broker-sockets/broker.sock" # POSIX UDS
bind_address = "0.0.0.0:8443" # optional TCP
brokers = [
{
id = "spiffe://example.org/some/broker"
allowed_reference_types = [
{
type_url = "type.googleapis.com/spiffe.broker.WorkloadPIDReference"
},
{
type_url = "type.googleapis.com/spiffe.broker.KubernetesObjectReference"
allow_over_tcp = true
},
]
},
{
id = "spiffe://example.org/wildcard/broker"
allowed_reference_types = [
{
type_url = "*"
},
]
},
]
}
}
}ID 不在此列表中的中介会在 TLS 层被拒绝。列表中存在、但使用了其 allowed_reference_types 之外引用类型的中介,会在 gRPC 层以 PermissionDenied 被拒绝。
Envoy SDS 支持
SPIRE Agent 支持 Envoy 的密钥发现服务(Secret Discovery Service,SDS)。SDS 通过与 Workload API 相同的 Unix 域套接字(Unix domain socket)提供服务。连接到 SDS 的 Envoy 进程会作为工作负载被认证。
包含 X509-SVID 的 tlsv3.TlsCertificate 资源可以用工作负载的 SPIFFE ID 作为资源名来获取 (例如 spiffe://example.org/database)。另外,若使用默认名称 "default",则获取的是 包含该工作负载(即 Envoy)默认 X509-SVID 的 tlsv3.TlsCertificate。 默认名称可配置(参见 SDS 配置下的 default_svid_name)。
包含受信任 CA 证书的 tlsv3.CertificateValidationContext 资源可以用目标信任域的 SPIFFE ID 作为资源名来获取(例如 spiffe://example.org)。 此外,还有另外两个特殊的资源名可用。第一个默认为 "ROOTCA",提供 Agent 所属信任域 的 CA 证书。第二个默认为 "ALL",返回 Agent 所属信任域以及适用于该 Envoy 工作负载的 任何联邦信任域的受信任 CA 证书。这些资源名的默认名称分别可通过 default_bundle_name 和 default_all_bundles_name 配置。"ALL" 资源名需要 SPIFFE Certificate Validator 扩展的支持,该扩展从 Envoy 1.18 起才可用。 默认名称可配置(参见 SDS 配置下的 default_all_bundles_name)。
SPIFFE Certificate Validator 让 Envoy 执行 SPIFFE 认证。SPIRE Agent 返回的校验上下文(validation context)默认包含此扩展。不过,若希望使用标准的 X.509 链校验,可以将 SPIRE Agent 配置为省略该扩展。默认行为可通过在 SDS 配置中设置 disable_spiffe_cert_validation 来更改。单个 Envoy 实例也可以通过在 Envoy 节点元数据中设置 disable_spiffe_cert_validation 键来覆盖默认行为。
OpenShift 支持
OpenShift 的默认安全配置(security profile)禁止访问主机级别的资源。可以应用一组自定义策略,以启用 Spire 在 OpenShift 内运行所需的访问级别。
注意:应用这些策略需要具有 cluster-admin 权限的用户。
安全上下文约束(Security Context Constraints)
Pod 所执行的操作受安全上下文约束(Security Context Constraints,SCC)控制,每个被准入(admitted)的 Pod 都会根据一系列条件被分配一个特定的 SCC。以下名为 spire 的自定义 SCC 可用于启用 Spire Agent 所需的主机级访问。
allowHostDirVolumePlugin: true
allowHostIPC: true
allowHostNetwork: true
allowHostPID: true
allowHostPorts: true
allowPrivilegeEscalation: true
allowPrivilegedContainer: false
allowedCapabilities: null
apiVersion: security.openshift.io/v1
defaultAddCapabilities: null
fsGroup:
type: MustRunAs
groups: []
kind: SecurityContextConstraints
metadata:
annotations:
include.release.openshift.io/self-managed-high-availability: "true"
kubernetes.io/description: Customized policy for Spire to enable host level access.
release.openshift.io/create-only: "true"
name: spire
priority: null
readOnlyRootFilesystem: false
requiredDropCapabilities:
- KILL
- MKNOD
- SETUID
- SETGID
runAsUser:
type: RunAsAny
seLinuxContext:
type: MustRunAs
supplementalGroups:
type: RunAsAny
users: []
volumes:
- hostPath
- configMap
- downwardAPI
- emptyDir
- persistentVolumeClaim
- projected
- secret将安全约束与工作负载关联
可以通过基于角色的访问控制(Role Based Access Control)策略,将 SCC 与 Pod 所引用的 Service Account 关联,从而向工作负载授予对安全上下文约束的访问权。
为使用 spire SCC,必须创建一个使用 use 动词(verb)引用该 SCC 的 ClusterRole:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
annotations:
include.release.openshift.io/self-managed-high-availability: "true"
rbac.authorization.kubernetes.io/autoupdate: "true"
name: system:openshift:scc:spire
rules:
- apiGroups:
- security.openshift.io
resourceNames:
- spire
resources:
- securitycontextconstraints
verbs:
- use最后,在 spire 命名空间中创建一个 RoleBinding,将 system:openshift:scc:spire 这个 ClusterRole 关联到 spire-agent Service Account:
注意: 在应用以下策略之前,若 spire 命名空间尚不存在,请先创建它。
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: system:openshift:scc:spire
namespace: spire
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:openshift:scc:spire
subjects:
- kind: ServiceAccount
name: spire-agent
namespace: spire由于 SCC 是在 Pod 准入时应用的,请删除任何已存在的 Spire Agent Pod。所有新准入的 Pod 都将使用 spire SCC,从而能够在 OpenShift 内运行。