本文为 SPIRE 官方文档 plugin_server_keymanager_aws_kms 的中文译本,以英文原文为准。
🔗 穿越源码分析:Server 详解 · KeyManager
服务端插件:KeyManager "aws_kms"
aws_kms 密钥管理器(key manager)插件借助 AWS 密钥管理服务(Key Management Service,KMS)来创建、维护并轮换密钥对(以客户主密钥(Customer Master Keys)即 CMK 的形式),并按需签发 SVID,而私钥(private key)始终不会离开 KMS。
配置
该插件接受以下配置项:
| 键名 | 类型 | 是否必填 | 说明 | 默认值 |
|---|---|---|---|---|
| access_key_id | string | 见 AWS KMS 访问权限 | 用于向 KMS 认证的 Access Key Id | 环境变量 AWS_ACCESS_KEY_ID 的值 |
| secret_access_key | string | 见 AWS KMS 访问权限 | 用于向 KMS 认证的 Secret Access Key | 环境变量 AWS_SECRET_ACCESS_KEY 的值 |
| region | string | 是 | 密钥将存储在哪个区域(region) | |
| key_identifier_file | string | 若未设置 key_identifier_value 则必填 | 一个文件路径,用于持久化所生成密钥的相关信息 | |
| key_identifier_value | string | 若未设置 key_identifier_file 则必填 | SPIRE server 实例的静态标识符(用于替代 key_identifier_file) | |
| key_policy_file | string | 否 | 一个 JSON 格式的自定义密钥策略(key policy)文件路径 | "" |
| enable_tag_based_key_discovery | boolean | 否 | 启用基于标签的密钥发现(推荐)。参见基于标签的密钥发现。 | false |
服务端实例标识
插件需要一种方式来识别它正在其上运行的具体 server 实例。为此,必须使用 key_identifier_file 或 key_identifier_value 两者之一。设置**密钥标识文件(Key Identifier File)**会指示插件自动管理 server 的标识符,将 server ID 存储在指定 文件中。这种方式适用于大多数情况。如果配置了_密钥标识文件_而在 server 启动时未 找到该文件,则会以新的、自动生成的 server ID 重新创建该文件。因此,如果该文件丢 失,插件将无法识别它此前管理过的密钥,并会按需重新创建新密钥。
如果你需要对 server 所用的标识符有更多控制,可以使用 key_identifier_value 设置 来为 server 实例指定一个静态标识符。这种设置适用于无法持久化密钥标识文件的场景。
基于标签的密钥发现
推荐。 通过
enable_tag_based_key_discovery = true启用。
启用基于标签的密钥发现后,插件会使用 AWS Resource Groups Tagging API 来高效地只查找由本插件实例管理的 KMS 密钥。密钥通过以下在创建时打上的 SPIRE 专用标签(tag)来识别:
| 标签键 | 说明 |
|---|---|
spire-server-td | SPIRE server 的信任域(trust domain) |
spire-server-id | server 实例标识符 |
spire-active | 对处于活跃管理状态的密钥设为 true |
spire-key-id | SPIRE 密钥标识符 |
spire-last-update | 最近一次更新的 Unix 时间戳(在创建时设置,并会周期性刷新) |
插件在密钥创建时(以及迁移一个已有密钥时)打上 spire-last-update 标签,并周期性地在所有活跃密钥上刷新它。任何 spire-last-update 时间戳早于两周的密钥都会被视为陈旧(stale),被标记为非活跃(spire-active=false),其关联的 KMS 密钥会被安排删除。
从基于别名的发现迁移: 当在一个此前使用基于别名(alias)发现的 server 上启用基于标签的发现时,插件会在启动期间自动检测已有的未打标签的密钥,并为它们打上 SPIRE 标签。无需任何手动迁移步骤。
此模式需要 tag:GetResources 权限(来自 Resource Groups Tagging API)。完整权限列表见 AWS KMS 访问权限。
高可用部署中的配置一致性
enable_tag_based_key_discovery 设置应在同一信任域内的所有 SPIRE server 上保持一致。与基于别名的发现一样,每个 server 会周期性地在它所管理的密钥上刷新一个存活信号(liveness signal),并且任何 server 都会回收其信任域内那些存活信号已两周未刷新的密钥(被永久移除的 server 所拥有的密钥正是这样被清理的)。
两种发现模式使用各自独立的存活信号:基于别名的发现刷新别名的 LastUpdatedDate,而基于标签的发现刷新 spire-last-update 标签。server 只会为其当前配置的模式刷新对应的信号。这对回滚(rollback)有如下影响:
- 在整个集群范围内向前迁移(从基于别名到基于标签)是安全的:密钥会在启动时自动打标签,并从此持续刷新。
- 在部分节点上从基于标签回滚到基于别名、同时其他 server 仍使用基于标签,只有在两周窗口期内才是安全的。已回滚的 server 会保持其别名新鲜,但停止刷新
spire-last-update,因此两周之后,仍在使用基于标签的 server 会把它正在使用的密钥当作已废弃并安排删除。要安全回滚,需在该窗口期内在信任域的所有 server 上一并修改此设置。
基于别名的密钥发现
注意: 基于别名的密钥发现将在未来某个版本被弃用(deprecated),并在更晚的版本中移除。启用
enable_tag_based_key_discovery以完成迁移。
默认情况下,插件使用基于别名的密钥发现。插件会为它所管理的客户主密钥分配别名(alias)。别名具有如下形式:alias/SPIRE_SERVER/{TRUST_DOMAIN}/{SERVER_ID}/{KEY_ID}。别名中的 {KEY_ID} 会被编码为 KMS 可接受的字符集。
插件会尝试检测并清除陈旧的别名。为便于陈旧别名检测,插件每 6 小时主动更新一次所有别名的 LastUpdatedDate 字段。插件会周期性扫描别名。任何 LastUpdatedDate 早于两周的别名都会连同其关联密钥一起被移除。
插件也会尝试检测并清除陈旧的密钥。插件管理的所有密钥都会被赋予形如 SPIRE_SERVER/{TRUST_DOMAIN} 的 Description。插件会周期性扫描密钥。任何 Description 符合该形式、既未与任何别名关联、且 CreationDate 早于 48 小时的密钥都会被移除。
密钥打标签
插件支持通过 key_tags 配置项为 KMS 密钥打上用户自定义标签。这些标签以键值对形式指定,并会应用到插件创建的所有 KMS 密钥上。
使用密钥打标签时,必须在 IAM 策略中添加 kms:TagResource 权限。没有该权限,密钥创建会失败。
标签约束
- 标签键长度必须为 1-128 个字符
- 标签值长度可为 0-256 个字符
- 最多 50 个标签(AWS KMS 限制)
- 标签键与值必须使用合法字符:字母、数字、空格,以及以下特殊字符:
+ - = . _ : / @ - 标签键不能以
aws:开头(AWS 保留) - 标签键不能以
spire-开头(为 SPIRE 管理的标签保留)
标签校验 插件会在配置阶段校验所有用户自定义标签。如果有任何标签违反 AWS KMS 的标签约束,插件将配置失败,并报告一条详细的错误信息,指明具体的校验失败原因。
标签生命周期 当 key_tags 配置块被更新时,只有新创建的密钥才会按新配置打标签。已有密钥的标签不会被更新。
AWS KMS 访问权限
访问 AWS KMS 可以通过设置 access_key_id 和 secret_access_key 来授予,或者通过确保插件运行在一个绑定了具备特定权限集的 IAM 角色的 EC2 实例上来授予。
该 IAM 角色必须附加一个具备以下权限的策略:
kms:CreateAliaskms:CreateKeykms:DescribeKeykms:GetPublicKeykms:ListAliaseskms:ScheduleKeyDeletionkms:Signkms:UpdateAliaskms:DeleteAlias
根据配置的不同,还需要以下额外权限:
| 权限 | 何时需要 |
|---|---|
kms:ListKeys | 使用基于别名的密钥发现(当前默认) |
kms:TagResource | 使用基于标签的密钥发现或 key_tags |
tag:GetResources | 使用基于标签的密钥发现(enable_tag_based_key_discovery = true) |
tag:GetResources 属于 Resource Groups Tagging API,而不属于 KMS。它是一项基于身份(identity-based)的权限,必须在 IAM 身份的策略中授予。它无法通过 KMS 密钥策略授予(包括插件生成的默认策略)。
密钥策略
插件可以使用默认密钥策略来生成密钥,也可以加载并使用用户定义的策略。
默认密钥策略
默认密钥策略依赖 SPIRE Server 所担任(assumed)的角色。因此,SPIRE server 必须担任一个角色才能使用默认策略。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Allow full access to the SPIRE Server role",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::111122223333:role/example-assumed-role-name"
},
"Action": "kms:*",
"Resource": "*"
},
{
"Sid": "Allow KMS console to display the key and policy",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::111122223333:root"
},
"Action": [
"kms:Describe*",
"kms:List*",
"kms:Get*"
],
"Resource": "*"
}
]
}- 策略的第一条语句(statement)赋予当前 SPIRE server 所担任的角色对该 CMK 的完全访问权限。
- 第二条语句允许在 KMS 控制台中显示密钥和策略。
自定义密钥策略
用户也可以定义自定义密钥策略。如果设置了可配置项 key_policy_file,插件会使用该文件中定义的策略来替代默认策略。
插件配置示例
基础配置
KeyManager "aws_kms" {
plugin_data {
region = "us-east-2"
key_identifier_file = "./key_metadata"
}
}启用基于标签的密钥发现的配置(推荐)
KeyManager "aws_kms" {
plugin_data {
region = "us-east-2"
key_identifier_file = "./key_metadata"
enable_tag_based_key_discovery = true
}
}带标签的配置
KeyManager "aws_kms" {
plugin_data {
region = "us-east-2"
key_identifier_file = "./key_metadata"
enable_tag_based_key_discovery = true
key_tags = {
Environment = "production"
Team = "security"
Component = "spire"
}
}
}支持的密钥类型与 TTL
插件支持 SPIRE 支持的所有密钥类型:rsa-2048、rsa-4096、ec-p256 和 ec-p384。