4. Condition条件键:常见条件键及其用法

Condition条件键,说白了就是密钥边界策略里的“精细控制器”。

一个策略看起来可能很宽泛,但在Condition的加持下,能变得非常精准。你想想看,你不能只告诉KMS“允许所有用户操作所有密钥”,那太粗暴了。你得说“允许张三,用特定的标签,在特定的时间,创建特定类型的密钥”。这里的“特定”二字,全靠Condition来实现。

4.1 条件键的分类

我个人习惯把KMS的条件键分成三大类:

  • 资源绑定类条件键:跟密钥本身属性相关的。比如密钥的标签(kms:RequestTag)、密钥的创建时间(kms:CreationDate)、密钥的ID(kms:KeySpec)等。这类条件键往往在kms:*Key动作中使用,用来限定“什么样的密钥才能被操作”。
  • 请求属性类条件键:跟API请求参数相关的。比如kms:EncryptionAlgorithm(加密算法)、kms:KeyUsage(密钥用途)。它们直接检查你发送的请求里带了什么参数。
  • 上下文类条件键:跟调用环境相关的。比如kms:CallerPrincipal(调用者主体)、kms:ViaService(通过哪个服务发起)。这类条件键我用的最多,因为在排查问题时,经常发现是某个服务误调用了密钥,通过kms:ViaService就能直接拦住。
分类 常见条件键 用途 注意事项
资源绑定类 kms:RequestTag, kms:CreationDate, kms:KeySpec 限定密钥的标签、创建时间、规格 kms:CreationDate 只能用 DateGreaterThan 或 DateLessThan
请求属性类 kms:EncryptionAlgorithm, kms:KeyUsage 限定加密算法、密钥用途 注意区分 kms:EncryptionAlgorithm 和 kms:DecryptionAlgorithm
上下文类 kms:CallerPrincipal, kms:ViaService 限定调用者主体、调用来源服务 kms:ViaService 常用于隔离不同云服务对密钥的使用

4.2 深度解析:kms:RequestTag

这个条件键很实用。它检查创建密钥时是否带了指定的标签。如果你做了一个策略,只有带Environment=Production标签的密钥才能被创建,那么用户就无法创建无标签或错误标签的密钥。

我在项目中遇到过一个问题:开发环境不小心创建了一个“生产环境”标签的密钥,导致测试数据落盘后被误认为生产数据。嗯,后来我用kms:RequestTag强制要求创建密钥时必须带上Environment标签,且值必须是Dev或Test,这样开发环境的人就再也创建不了Production标签的密钥了。

用法示例:

{
    "Effect": "Allow",
    "Action": "kms:CreateKey",
    "Resource": "*",
    "Condition": {
        "StringEquals": {
            "kms:RequestTag/Environment": "Production"
        }
    }
}

注意,kms:RequestTag只在CreateKey动作中生效。对于已存在的密钥,如果想基于标签来控制访问,需要用kms:ResourceTag,这个我们后面会讲到。

小提示: kms:RequestTag支持多值匹配。如果你需要允许多种标签,可以用 ForAnyValue:StringEquals 条件。

4.3 深度解析:kms:CreationDate

这个条件键控制的是密钥的创建时间。简单来说,你可以限制:只有某一天之后创建的密钥,才能执行某些操作。

为什么需要这个?我之前帮客户排查过一个异常:他们发现某个老密钥被意外删除。原因是一条旧策略过于宽泛,允许了所有密钥的删除操作。我建议他们用kms:CreationDate加一个DateGreaterThan条件,只允许对2024年1月1日之后创建的密钥执行删除。这样,老密钥就自动处于“只读不可删”的状态。避坑效果立竿见影。

用法示例:

{
    "Effect": "Deny",
    "Action": "kms:ScheduleKeyDeletion",
    "Resource": "*",
    "Condition": {
        "DateLessThan": {
            "kms:CreationDate": "2024-06-01T00:00:00Z"
        }
    }
}

这里用DateLessThan表示:如果密钥创建时间早于2024年6月1日,则拒绝删除。注意,日期格式必须是ISO 8601的UTC时间。

我踩过的坑: 不要把 kms:CreationDate 和 kms:KeyRotationStatus 混在一起用。我曾经想把“未开启自动轮转的老密钥”都禁止使用,结果发现策略生效时机不对,建议分两条策略来做。

4.4 深度解析:kms:KeySpec 和 kms:KeyUsage

这两个条件键绑定得很紧。kms:KeySpec决定了密钥的算法和长度(比如AES_256、RSA_2048、EC_P256等),kms:KeyUsage决定了密钥的用途(比如ENCRYPT_DECRYPT、SIGN_VERIFY)。

你想想看如果一个密钥既用来加密,又用来签名,一旦泄露风险极大。所以最好强制限定:KeyUsage必须是ENCRYPT_DECRYPT,而且KeySpec必须是AES_256。

用法示例:

{
    "Effect": "Allow",
    "Action": "kms:CreateKey",
    "Resource": "*",
    "Condition": {
        "StringEquals": {
            "kms:KeySpec": "AES_256",
            "kms:KeyUsage": "ENCRYPT_DECRYPT"
        }
    }
}

4.5 实战:组合使用条件键

很多时候,我们需要把多个条件键组合起来。比如:只允许创建带Environment=Production标签的、AES_256算法、用于加密解密的密钥。这在边界策略里非常常见。

不过有个细节要留心:条件键之间是“与”关系,也就是说必须同时满足所有条件。没有“或”的关系,除非你用ForAnyValue:StringEquals这样的集合条件符。

条件键组合判断逻辑 API请求进入 判断 密钥标签是否匹配 kms:RequestTag/Environment = Production 判断 密钥规格是否匹配 kms:KeySpec = AES_256 判断 密钥用途是否匹配 kms:KeyUsage = ENCRYPT_DECRYPT 允许操作(全部通过) 说明 1. 三个条件键之间 是“与”(AND)关系 2. 任何一个不满足 都会拒绝请求 3. 组合使用时 策略更精确

4.6 使用注意事项

最后说几个我踩过的坑,希望能帮你避开:

  • 条件键不适用于所有动作:比如kms:ListKeys这个动作不支持条件键。你在策略里写了kms:RequestTag也不管用,因为ListKeys不传标签参数。我曾见过有人在这个动作上加了kms:RequestTag,结果策略总是匹配失败。
  • 大小写敏感:条件键名称和值都区分大小写。StringEquals就是严格的匹配,Environment和environment不一样。嗯,这个我吃过亏。
  • 不要滥用ForAllValues:ForAllValues要求请求中的所有标签都在策略允许的范围内。如果你的策略只写了一个允许标签,但用户请求带了两个标签,就会失败。我建议只用ForAnyValue,它更宽容。

核心总结: 条件键是边界策略的灵魂。只要你想把策略做得细,就必须玩转kms:RequestTag、kms:CreationDate、kms:KeySpec、kms:KeyUsage这几个。我个人觉得,加一个条件键,比写一大段Action排除列表要安全得多。试试看,你会爱上这种精确控制的感觉。