本文为 SPIRE 官方文档 plugin_server_nodeattestor_azure_msi.md 的中文译本,以英文原文为准。 🔗 穿越源码分析:Server 详解 · NodeAttestor
Server 插件:NodeAttestor "azure_msi"
必须与 Agent 侧 azure_msi 插件配合使用
azure_msi 插件用于对运行在 Microsoft Azure 中、且启用了托管服务标识(Managed Service Identity,MSI)的节点进行认证。agent 节点会获取一个经签名的 MSI 令牌并将其传递给 server。server 校验该签名 MSI 令牌,并从中提取 Tenant ID 和 Principal ID 来构成 agent 的 SPIFFE ID。SPIFFE ID 的格式为:
spiffe://<trust_domain>/spire/agent/azure_msi/<tenant_id>/<principal_id>server 本身无需运行在 Azure 中即可执行节点认证或解析 selector。
Configuration(配置)
| Configuration | Required | Description | Default |
|---|---|---|---|
tenants | 必填 | 一个租户(tenant)映射,以 tenant ID 为键,列出被授权进行认证的租户。未指定租户对应的令牌将被拒绝。 | |
agent_path_template | 可选 | Agent SPIFFE ID 的 URL 路径部分格式,以 text/template 格式描述。 | "/{{ .PluginName }}/{{ .TenantID }}/{{ .PrincipalID }}" |
主配置中的每个租户支持以下配置:
| Configuration | Required | Description | Default |
|---|---|---|---|
resource_id | 可选 | 该租户 MSI 令牌的资源 ID(或受众 audience)。资源 ID 不同的令牌将被拒绝。 | https://management.azure.com/ |
subscription_id | 可选 | 该租户所在的订阅(subscription) | |
app_id | 可选 | 应用 id(application id) | |
app_secret | 可选 | 应用密钥(application secret) |
需要特别注意的是,resource ID 必须是一个众所周知的 Azure 服务,或是 Azure AD 中一个已注册应用的 app ID。对于自己不认识的资源,Azure 不会签发 MSI 令牌。
向 Azure 认证(Authenticating to Azure)
本插件需要凭据(credentials)来向 Azure 进行认证,以便查询被认证节点的属性并生成 selector。
默认情况下,插件会尝试通过 DefaultAzureCredential API 使用应用默认凭据(application default credential)。DefaultAzureCredential API 会按以下顺序依次尝试各种机制进行认证——环境变量、工作负载标识(Workload Identity)、托管标识(Managed Identity),一旦某种方式成功即停止。当使用 Workload Identity 或 Managed Identity 时,插件必须能够获取所配置 tenant ID 的凭据,否则使用该认证器的节点认证将会失败。
或者,也可以将插件配置为使用某个在租户内注册的应用的静态凭据(subscription_id、app_id 和 app_secret)。
出于向后兼容的原因,认证配置目前并非必需,但在未来的版本中它将成为必需项。
Sample Configurations(示例配置)
默认 Resource ID 与应用认证(App Authentication)
NodeAttestor "azure_msi" {
plugin_data {
tenants = {
"00000000-1111-2222-3333-444444444444" = {
subscription_id = SUBSCRIPTION_ID
app_id = APP_ID
app_secret = APP_SECRET
}
}
}
}
}自定义 Resource ID 与 MSI 认证(MSI Authentication)
NodeAttestor "azure_msi" {
plugin_data {
tenants = {
"00000000-1111-2222-3333-444444444444" = {
resource_id = "http://example.org/app/"
}
}
}
}Selectors(选择器)
插件生成以下 selector。
| Selector | Example | Description |
|---|---|---|
| Subscription ID | subscription-id:d5b40d61-272e-48da-beb9-05f295c42bd6 | 节点所属的订阅(subscription) |
| Virtual Machine Name | vm-name:frontend:blog | 虚拟机名称(例如 blog),以其资源组(resource group,例如 frontend)限定 |
| Network Security Group | network-security-group:frontend:webservers | 网络安全组名称(例如 webservers),以其资源组(例如 frontend)限定 |
| Virtual Network | virtual-network:frontend:vnet | 虚拟网络名称(例如 vnet),以其资源组(例如 frontend)限定 |
| Virtual Network Subnet | virtual-network-subnet:frontend:vnet:default | 虚拟网络子网名称(例如 default),以其虚拟网络和资源组限定 |
所有 selector 的类型均为 azure_msi。
Agent 路径模板(Agent Path Template)
Agent 路径模板(agent path template)是一种自定义 agent SPIFFE ID 生成格式的方式。模板格式化器采用 Golang text/template 约定,可以引用插件提供的值,或 MSI 访问令牌中的值。关于模板引擎的详情,见模板引擎文档。
一些有用的值包括:
| Value | Description |
|---|---|
| .PluginName | 插件名称 |
| .TenantID | Azure 租户标识符 |
| .PrincipalID | 对某个特定 application ID 而言唯一的标识符 |
Security Considerations(安全考量)
Azure 托管服务标识(Managed Service Identity)令牌是本认证器用于证明节点身份的凭据,默认情况下节点上运行的任何进程都可访问它。因此,节点上的非 agent 代码有可能向 SPIRE Server 完成认证,从而获取该节点被授权运行的任意工作负载身份(workload identity)。
尽管许多运维人员会选择配置系统以阻止对 Managed Service Identity 令牌的访问,但 SPIRE 项目无法保证这一安全态势。为缓解相关风险,azure_msi 节点认证器实现了首次使用即信任(Trust On First Use,简称 TOFU)语义。对于任意给定节点,认证只能发生一次,后续的认证尝试都将被拒绝。
非 agent 代码仍有可能先于 SPIRE Agent 完成节点认证;不过这种情况很容易被迅速发现,因为此时 SPIRE Agent 将无法启动,并且 SPIRE Agent 和 SPIRE Server 都会记录该事件。此类情况应作为可能的安全事件加以调查。