3、策略组成部分详解:策略结构(Version, Statement)、Effect、Principal、Action、Resource、Condition
3.1 开篇:别被JSON吓到
策略本质上就是一段JSON。我刚开始接触KMS的时候,看到一长串JSON头都大了。但拆开来看,其实就六个核心元素:Version、Statement、Effect、Principal、Action、Resource、Condition。今天咱们一个一个说清楚。
你想想看,写策略就像写一个「门禁规则」。Version是规则版本号,Statement是具体条款。每个条款里,Effect决定「放行还是禁止」,Principal指定「谁」,Action定义「做什么」,Resource限定「对哪个钥匙」,Condition加上「附加条件」。搞明白这些,你就能自己写策略了。
3.2 Version — 版本号,别乱填
Version字段只有一个值:1(字符串形式)。早期阿里云还有过其他版本,但现在已经统一成 "1"。
我要提醒你:千万别写成数字 1,必须是字符串 "1"。我曾经在一个自动化脚本里传了数字,结果策略死活不生效,排查了半天。所以,养成习惯,写 "Version": "1"。
3.3 Statement — 策略的“条款清单”
Statement是一个数组,里面可以放多个策略条款。每个条款是一个对象,包含Effect、Principal、Action、Resource、Condition。多个条款之间是「OR」关系——只要命中任意一条,就生效。
注意顺序:如果一条策略是Deny,另一条是Allow,Deny优先。这是阿里云IAM的规则,不是KMS独有的。我在做跨账号授权时,就踩过这个坑:Allow写在前面,Deny写在后面,结果Deny盖过了Allow,权限死活开不起来。
3.4 Effect — 允许还是拒绝?
Effect只有两个取值:Allow 和 Deny。
- Allow:明确允许某个操作
- Deny:明确拒绝某个操作(优先级高于Allow)
我习惯把Deny放在所有语句的最前面,这样一眼就能看到「禁区」。有一次我在生产环境误把Effect写成了「Deny」本该是Allow,导致整个部门无法使用KMS密钥。嗯,从那以后我每次部署前都会人工检查Effect的值。
3.5 Principal — 谁可以?
Principal指定策略对谁生效。在KMS密钥边界策略里,Principal通常跟RAM用户、RAM角色、阿里云服务账号相关。
| Principal类型 | 写法示例 | 说明 |
|---|---|---|
| RAM用户 | "RAM" : "acs:ram::1234567890:user/admin" | 精确指定某个用户 |
| RAM角色 | "RAM" : "acs:ram::1234567890:role/admin" | 精确指定某个角色 |
| 阿里云服务 | "Service" : "ecs.aliyuncs.com" | 允许ECS服务使用 |
| 所有人 | "*" | 慎用!等于全公开 |
我曾经见过有人直接在Principal写 "*",以为只是测试用,结果上线后密钥被非预期的账号使用了。所以我的建议是:除非你明确需要开放给所有RAM账号,否则一定要写具体的ARN。
3.6 Action — 能做什么?
Action指定允许或拒绝的操作。KMS的Action非常多,比如 kms:Encrypt、kms:Decrypt、kms:GenerateDataKey 等等。可以用通配符 * 匹配所有操作,但粒度越细越安全。
小技巧: 如果你不确定某个业务需要哪些Action,可以先用 kms:DescribeKey 这种只读操作测试,然后通过审计日志观察实际调用的API,再逐步收窄。
Action支持 List 和 NotAction。NotAction的意思是「除了这些操作之外的所有操作」,配合Deny效果很好。比如你只想禁止 kms:ScheduleKeyDeletion(计划删除密钥),其他操作都允许,就可以用Deny + NotAction。
3.7 Resource — 对哪个密钥?
Resource指定策略作用的KMS密钥。格式是 "acs:kms:${region}:${account}:key/${keyId}"。
- 精确指定:
"acs:kms:cn-hangzhou:1234567890:key/1234abcd-..." - 通配符:
"acs:kms:*:*:key/*"匹配所有密钥(谨慎使用) - 多密钥:可以用数组写多个ARN
我在项目中遇到过一位同事,Resource写了同一个区域所有密钥(用了 *),本来只打算给一个密钥授权,结果所有密钥都暴露了。所以,Resource一定要精确到keyId,除非你确实需要全局策略。
3.8 Condition — 附加限制条件
Condition是策略的「精细调节器」。它可以在Allow/Deny的基础上再附加条件,比如来源IP、是否使用HTTPS、是否使用临时凭证等。
常见条件操作符:
StringEquals— 字符串相等IpAddress— 来源IP匹配DateLessThan— 时间条件(比如只允许在某个时间段内操作)Bool— 布尔值条件(比如"kms:CallerIsKeyOwner")
注意: Condition写错可能导致策略永远不生效,或者永远生效。我曾经设置过一个 StringNotEquals 条件,本意是排除某个IP,结果写反了,变成了只允许那个IP访问。排查了两个小时才发现。
Condition的写法比较灵活,可以组合多个条件(AND、OR)。我个人习惯把条件写成 "Condition": { "IpAddress": { "acs:SourceIp": ["10.0.0.0/8"] } },这样限制来源网段,安全性高很多。
3.9 知识总结:策略结构图
我把上面的关系画成一张SVG图,方便你对照记忆。
3.10 实战对照:一条完整策略的拆解
我拿一条我常用的策略例子,咱们把每个部分对上。
{
"Version": "1",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"RAM": ["acs:ram::1234567890:role/ecs-app-role"]
},
"Action": [
"kms:Encrypt",
"kms:Decrypt"
],
"Resource": [
"acs:kms:cn-hangzhou:1234567890:key/abcd-1234"
],
"Condition": {
"IpAddress": {
"acs:SourceIp": ["10.0.0.0/8"]
}
}
}
]
}
解读:允许RAM角色 ecs-app-role 对指定密钥进行加密和解密,但只允许来自内网 10.0.0.0/8 的请求。这就是一个最小权限且附带网络限制的典型策略。
核心原则: Effect + Principal + Action + Resource + Condition 缺一不可,任何一个写错都可能造成权限泄露或业务中断。写完后,用RAM策略模拟器测试一下,我每次都会这么做。