策略文档的基本结构:六要素拆解
写IAM策略,说白了就是在填一张表格。
只不过这张表格用JSON写,而且写错了整个应用都可能挂掉。我刚开始接触AWS策略时,总以为JSON写对了就行。后来发现,结构理解不透,十个策略八个出问题。
为什么?因为策略文档有它自己的规则。不管你是写IAM策略还是桶策略,底层都是同一套JSON骨架。今天我就带你把六个核心要素拆开看看。
1. Version(版本)
Version是个字符串。你只需要记住一个值:2012-10-17。
其他版本要么过时,要么没开放。我个人习惯在所有策略里都写死这个版本。它代表IAM策略语言的最新稳定版。
小提示:版本号决定了解析器怎么理解策略。错用旧版本可能导致“Deny”失效。嗯,这种坑我在线上环境见过。
2. Statement(语句)
Statement是个数组。里面可以写一条,也可以写多条。
我见过有人把所有权限写进一条Statement,结果一个Allow下面挂了十几个Action。说实话,那样子排查问题特别痛苦。
我建议你把不同用途的权限拆开:
- 允许读取放一条
- 禁止删除放一条
- 跨账户访问再单独放一条
每条Statement都是独立的。解析器会逐条评估,最后汇总结果。
3. Effect(效果)
就两个值:Allow 和 Deny。没有复杂逻辑,但优先级有讲究。
| Effect | 含义 | 使用场景 |
|---|---|---|
| Allow | 开放权限 | 日常授权 |
| Deny | 彻底禁止 | 安全边界、白名单之外的兜底 |
我记得有个项目曾被Deny覆盖Allows搞得焦头烂额。一条Deny写在最前面,后面几条Allow全成了废纸。因为在IAM里,Deny永远优先于Allow。
避坑指南:我曾经帮客户排查一个跨账户桶策略,明明写了Allow却总报403。最后发现是另一条显式Deny把整个桶写死了。解决方案:要么删Deny,要么在Allow里加条件绕开。
4. Principal(主体)
Principal就是“谁”在访问。注意,IAM策略里不写Principal,桶策略里必须写。
Principal支持的类型:
- AWS账户(arn:aws:iam::123456789012:root)
- IAM角色(arn:aws:iam::123456789012:role/MyRole)
- IAM用户(arn:aws:iam::123456789012:user/Alice)
- 联合身份(Federated session)
- 匿名用户( * )
写桶策略时,我建议尽量具体。用 * 只在你确定要公开桶时才考虑。我曾经见过一个桶策略把Principal写成 * ,还好桶里只有测试数据。
实战建议:跨账户配置时,Principal的ARN必须写在对方的账号里。写错了,整个权限都不生效。我习惯先建角色再对ARN,这样不容易出错。
5. Resource(资源)
Resource定义策略作用在哪个资源上。格式是ARN。
对于S3桶策略,Resource要对桶本身和桶内对象一起覆盖:
"Resource": [
"arn:aws:s3:::my-bucket",
"arn:aws:s3:::my-bucket/*"
]
第一条针对桶操作(如ListBucket),第二条针对对象操作(如GetObject)。少写一个,功能就可能残缺。
我见过人用 Resource: "*" 偷懒,结果权限给得太大。安全性上,我建议始终指定明确的ARN。
6. Condition(条件)
Condition是策略的“精细调节器”。它能限定什么条件下访问才生效。
常用的条件键举例:
| 条件键 | 作用 |
|---|---|
| aws:SourceIp | 限制来源IP |
| aws:SourceVpce | 限制特定VPC Endpoint |
| s3:x-amz-server-side-encryption | 强制加密 |
举个例子,只允许从公司IP访问:
"Condition": {
"IpAddress": {
"aws:SourceIp": "203.0.113.0/24"
}
}
注意:我曾经处理过一个数据泄露事故,就是因为Condition漏了。桶策略给了所有账户访问权限,但没有限制IP。结果某天被扫出来,桶里的机密数据被全量导出。从那以后,我每条策略都会自问一句:“条件写了吗?”
这六个要素组合起来,就构成了一条完整的Statement。我把它们画成一张结构图,看起来更清晰些:
结构讲完了。你可能会问:“这六个东西怎么配合起来写一个能用的策略?”
来,看一个完整例子。假设我想让运营团队的角色只能读my-bucket下的文件,且必须从公司IP访问:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "OnlyAllowReadFromOps",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123456789012:role/OpsRole"
},
"Action": [
"s3:GetObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::my-bucket",
"arn:aws:s3:::my-bucket/*"
],
"Condition": {
"IpAddress": {
"aws:SourceIp": "203.0.113.0/24"
}
}
}
]
}
这条策略里:
- Version:固定2012-10-17
- Statement:我只写了一条,因为功能单一
- Effect:Allow,主动授权
- Principal:指定OpsRole,不松手
- Action:只给GetObject和ListBucket,不写多余
- Resource:桶和对象一起保护
- Condition:限IP,防外网访问
核心思路:写策略就是在做权限的精确控制。六个要素,少写一个都可能开出漏洞。我每次写完策略都会对照六要素列表逐一检查,省得将来返工。
了解完结构,你已经有能力读懂和编写基础策略了。下一件事就是把这些策略放到实际场景里去跑,验证它有没有生效。