桶策略五要素:Principal、Action、Resource、Condition、Effect 深度拆解
桶策略看起来就是一段 JSON,但真正要把它写对、写安全,你得理解背后的五个核心元素。我把它们叫做策略的五根骨头:Principal、Action、Resource、Condition、Effect。缺一个,策略可能就是废的;配错了,权限可能就漏了。
这五个元素怎么协同工作的?我画了张图,你看看就明白了。
1. Principal:谁可以访问?
Principal 就是策略的「主语」。说白了,这条策略是写给谁看的?可以是某个具体的 IAM 用户、一个角色、整个 AWS 账号,甚至是匿名用户(所有人)。
我在项目中见过最多的坑,就是把Principal写成 "AWS": "*",结果整个互联网都能访问。嗯,这种配置你要非常谨慎。我一般建议,如果你不确定,先用特定的 ARN 测试,确认无误再考虑放开。
{
"Principal": {
"AWS": "arn:aws:iam::123456789012:user/zhangsan"
}
}
2. Action:允许或拒绝哪些操作?
Action 定义了你能对桶或对象做什么。常见的包括:s3:GetObject(读对象)、s3:PutObject(上传)、s3:DeleteObject(删除)、s3:ListBucket(列举桶内容)等。
Action 可以写多个,用数组方式,也可以用通配符 "s3:*" 代表所有操作。但说真话,给通配符风险很高。我曾经在审计时发现一个策略给了 s3:*,结果某个实习生写脚本把整桶数据删了……虽然最后救了回来,但那种惊心动魄,我不想再体验。
一个靠谱的做法:只授权你确实需要的动作。比如,只读的客户端,你给它 s3:GetObject 就足够了,别给 s3:DeleteObject。
{
"Action": [
"s3:GetObject",
"s3:ListBucket"
]
}
3. Resource:作用于哪些资源?
Resource 就是你策略落地的「地盘」。它是 ARN(Amazon Resource Name)格式。比如桶本身:"arn:aws:s3:::my-bucket";桶里的所有对象:"arn:aws:s3:::my-bucket/*"。
这里有个关键点:Action 和 Resource 要匹配才能生效。比如 ListBucket 动作,它的 Resource 应该是桶本身的 ARN,而不是某个对象。而 GetObject 动作,Resource 应该指向对象(用 /* 或具体路径)。配错的话,策略明明看起来合理,但就是不生效。
我记得有一次排查了半天,才发现是 Resource 写错了范围。你想想看,这个错误很隐蔽,IAM 模拟器也不一定会报错,只有执行时才知道。
- 桶操作(如 ListBucket)的 Resource 写桶 ARN:
"arn:aws:s3:::my-bucket" - 对象操作(如 GetObject)的 Resource 写对象路径:
"arn:aws:s3:::my-bucket/*" - 如果需要两者兼顾,可以同时写出两个 Resource
4. Condition:在什么条件下生效?
Condition 是策略中最灵活、也最容易写错的地方。它允许你附加额外的约束条件。常见的条件包括:IP 地址范围、TLS 版本、请求时间、MFA 与否、对象标签等。
Condition 的语法是:"Condition": { "条件运算符": { "条件键": "条件值" } }。举个例子,我只允许来自公司内部 IP 的写入操作:
{
"Condition": {
"IpAddress": {
"aws:SourceIp": "203.0.113.0/24"
}
}
}
另一个常见场景:强制要求使用 HTTPS。我曾经帮一个客户配置桶策略,只允许通过 HTTPS 访问。如果不加这个条件,用户可以用 HTTP 明文传输数据,非常危险。写起来很简单:
{
"Condition": {
"Bool": {
"aws:SecureTransport": "true"
}
}
}
aws:SourceIp,不是 aws:sourceip。大小写错一个,策略就不起作用。我曾经见过一个客户配了三个月没生效,最后发现是字母大小写的问题。别笑,真的很容易犯。
5. Effect:允许还是拒绝?
Effect 只有两个值:Allow 或 Deny。它决定了策略的最终结果是「放行」还是「拦下」。默认情况下,所有请求都是隐式拒绝的。你写 Allow 就是显式允许,写 Deny 就是显式拒绝。
有一个优先级问题:显式 Deny 的优先级永远高于任何 Allow。也就是说,哪怕你写了一万个 Allow,只要存在一条匹配的 Deny,请求就会被拒绝。项目中我经常用这个特性来做“保底安全策略”。
比如,我想确保任何人都不能删除某个关键目录下的文件,就算管理员账号也不行。可以写一条 Deny,指定 Action 为 s3:DeleteObject,Resource 为 arn:aws:s3:::my-bucket/important/*,Principal 为 "*"。这样任何用户、任何角色都无法删除那个目录下的文件,包括我自己。
{
"Effect": "Deny",
"Principal": "*",
"Action": "s3:DeleteObject",
"Resource": "arn:aws:s3:::my-bucket/important/*"
}
好了,五大元素就这些。每个元素单独看都不难,但组合在一起,策略的复杂度就上来了。记住:Principal 是“谁”,Action 是“做什么”,Resource 是“对什么做”,Condition 是“在什么条件下”,Effect 是“结论”。掌握好这个框架,再复杂的权限场景你都能拆解清楚。