策略文档的基本结构:六要素拆解

写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。我把它们画成一张结构图,看起来更清晰些:

策略文档 JSON 结构树 Version Statement [ ] Effect Principal Action Resource Condition 可选项 细化访问条件 Sid(可选ID字段) 用来区分多条Statements NotAction / NotPrincipal / NotResource 排除型写法,慎用 组装规则:一条Statement必含Effect+Action+Resource Principal和Condition按需添加

结构讲完了。你可能会问:“这六个东西怎么配合起来写一个能用的策略?”

来,看一个完整例子。假设我想让运营团队的角色只能读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,防外网访问

核心思路:写策略就是在做权限的精确控制。六个要素,少写一个都可能开出漏洞。我每次写完策略都会对照六要素列表逐一检查,省得将来返工。

了解完结构,你已经有能力读懂和编写基础策略了。下一件事就是把这些策略放到实际场景里去跑,验证它有没有生效。