Skip to content

本文为 SPIRE 官方文档 plugin_server_nodeattestor_gcp_iit.md 的中文译本,以英文原文为准。 🔗 穿越源码分析:Server 详解 · NodeAttestor

Server 插件:NodeAttestor "gcp_iit" ​

必须与 Agent 侧 gcp_iit 插件配合使用

gcp_iit 插件使用 GCP 实例身份令牌(GCP Instance Identity Token)自动对实例进行认证。它还允许运维人员在定义 SPIFFE ID 认证策略时使用 GCP 实例 ID(Instance ID)。由 gcp_iit 认证器认证的 agent 会被签发形如 spiffe://TRUST_DOMAIN/spire/agent/gcp_iit/PROJECT_ID/INSTANCE_ID 的 SPIFFE ID。本插件要求提供一个允许认证节点的 ProjectID 允许列表(allow list)。这也意味着你不应在同一个 GCP 项目中运行多个信任域(trust domain)。

Configuration(配置) ​

ConfigurationDescriptionDefault
projectid_allow_list允许认证节点的 ProjectID 列表。
use_instance_metadata若为 true,则从 Google Compute Engine API 获取实例元数据(metadata),用于补充插件生成的节点 selector。false
service_account_file用于向 Google Compute Engine API 认证的 service account 文件路径。
allowed_label_keys参与构建 selector 的实例标签键(label key)
allowed_metadata_keys参与构建 selector 的实例元数据键(metadata key)
max_metadata_value_size设置插件在构建 selector 时所考虑的元数据值(metadata value)的最大大小128
agent_path_templateAgent SPIFFE ID 的 URL 路径部分格式,以 text/template 格式描述。"/{{ .PluginName }}/{{ .ProjectID }}/{{ .InstanceID }}"

一份示例配置:

hcl
    NodeAttestor "gcp_iit" {
        plugin_data {
            projectid_allow_list = ["project-123"]
        }
    }

Selectors(选择器) ​

本插件基于实例身份令牌(Instance Identity Token)中包含的信息生成以下 selector:

SelectorExampleDescription
gcp_iit:project-idgcp_iit:project-id:big-kahuna-123456包含该实例的项目 ID
gcp_iit:zonegcp_iit:zone:us-west1-b包含该实例的可用区(zone)
gcp_iit:instance-namegcp_iit:instance-name:blog-server实例名称
gcp_iit:sagcp_iit:sa:123456789-compute@developer.gserviceaccount.comService account 邮箱

如果 use_instance_metadata 为 true,则会向 Google Compute Engine API 查询实例元数据,用于填充以下额外的 selector:

SelectorExampleDescription
gcp_iit:taggcp_iit:tag:blog-server实例标签(tag)(每个一个 selector)
gcp_iit:labelgcp_iit:label:key:value实例标签(label)
gcp_iit:metadatagcp_iit:metadata:key:value实例元数据(见下方注意事项)

并非所有实例的 label 和 metadata 值都对节点选择有用。为避免生成大量无用的 selector,label 和 metadata 默认不会被使用。若要显式启用某个特定的 label 或 metadata 值,请在 allowed_label_keys 或 allowed_metadata_keys 配置项中指定其键名。

实例 metadata 可容纳最大 256KiB 的大值。为避免将大量数据写入数据存储(datastore),插件会强制执行一个元数据值大小上限。如果遇到某个被允许的(即键名已在 allowed_metadata_keys 中指定)metadata 值超过该上限,认证将失败。

metadata 和 label 的值是可选的。如果值不存在,对应的 selector 仍会带有一个尾部冒号(即 gcp_iit:label:<key>:、gcp_iit:metadata:<key>:)。

通过 Google Compute Engine API 进行认证 ​

插件使用应用默认凭据(Application Default Credentials)向 Google Compute Engine API 进行认证,具体见 Setting Up Authentication For Server to Server 文档。当 SPIRE Server 运行在 GCP 内部时,它会使用其所在实例可用的默认 service account 凭据。当运行在 GCP 之外,或需要使用非默认凭据时,可以通过 GOOGLE_APPLICATION_CREDENTIALS 环境变量或 service_account_file 配置项(见 Configuration)指定包含凭据的 service account 文件路径。

该 service account 必须具备 IAM 权限和授权作用域(Authorization Scopes),以授予对以下 API 的访问:

Agent 路径模板(Agent Path Template) ​

Agent 路径模板(agent path template)是一种自定义 agent SPIFFE ID 生成格式的方式。模板格式化器采用 Golang text/template 约定,可以引用插件提供的值,或 Compute Engine 身份令牌中的值。关于模板引擎的详情,见模板引擎文档。注意,agent 的 SPIFFE ID 在一个信任域内必须唯一,因此如果两个 agent 使用了相同的 service account,则路径模板中必须包含额外的、能够完全区分它们的标识符。

一些有用的值包括:

ValueDescription
.PluginName插件名称
.ProjectID创建实例所在项目的 ID
.InstanceID该令牌所属实例的唯一 ID
.ProjectNumber创建实例所在项目的唯一编号
.Zone实例所在的可用区(zone)
.InstanceCreationTimestamp一个 Unix 时间戳,表示实例的创建时间
.ServiceAccountService account 邮箱("@" 被替换为 "_")

Security Considerations(安全考量) ​

实例身份令牌(Instance Identity Token)是本认证器用于证明节点身份的凭据,默认情况下节点上运行的任何进程都可访问它。因此,节点上的非 agent 代码有可能向 SPIRE Server 完成认证,从而获取该节点被授权运行的任意工作负载身份(workload identity)。

尽管许多运维人员会选择配置系统以阻止对实例身份令牌的访问,但 SPIRE 项目无法保证这一安全态势。为缓解相关风险,gcp_iit 节点认证器实现了首次使用即信任(Trust On First Use,简称 TOFU)语义。对于任意给定节点,认证只能发生一次,后续的认证尝试都将被拒绝。

非 agent 代码仍有可能先于 SPIRE Agent 完成节点认证;不过这种情况很容易被迅速发现,因为此时 SPIRE Agent 将无法启动,并且 SPIRE Agent 和 SPIRE Server 都会记录该事件。此类情况应作为可能的安全事件加以调查。