2. 策略语法详解:版本、语句、Effect、Action、Resource、Condition

嗯,策略语法这东西,说白了就是IAM的“配置文件语言”。你写的每一行,都决定了谁能在什么条件下干什么。我刚开始接触IAM时,觉得它跟JSON区别不大——直到有一次因为搞混了Effect,差点把生产环境的写权限全开放出去……从那以后我就明白了:语法细节,一条都含糊不得。

2.1 策略的整体骨架

一个标准的IAM策略长这样:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::my-bucket/*",
      "Condition": {
        "IpAddress": {
          "aws:SourceIp": "192.168.0.0/24"
        }
      }
    }
  ]
}

我最喜欢把这个结构拆成两部分:头部(Version)和主体(Statement数组)。你想想看,每个Statement就像一条独立的小规则,而所有规则拼起来,就是这个策略的完整意图。

2.2 Version——别小看它

Version字段目前只有两个有效值:2012-10-17 和 2008-10-17(旧版)。我很奇怪,为什么有人写策略时会直接删掉Version?我个人习惯是一定留着,并且只用最新的。为什么?因为旧版本有些特性不支持,比如Condition的某些运算符。

我曾经接手过一个遗留系统,策略里Version写的是2008-10-17,结果新加的Condition条件怎么都不生效。排查半天才发现是版本限制了。所以——记住,策略创建时就把Version写成2012-10-17。

2.3 Statement——策略的核心容器

Statement是一个数组,每个元素包含Effect、Action、Resource、Condition四个部分。注意:数组里可以有多个语句,它们之间是逻辑或的关系。即,只要有一条语句匹配,整个策略就生效。

我通常建议:把权限分成小而明确的语句,而不是堆砌成一条庞然大物。你想想看,一条语句十几个Action和几十个Resource,排查问题时会疯掉的。

2.4 Effect——最关键的决策

Effect值含义典型使用场景
Allow允许操作授予权限
Deny拒绝操作覆盖其他允许项、安全护栏

很多人以为“Allow+Deny”同时出现时,Deny一定会赢。没错,显式Deny优先级最高。但我要提醒你:默认隐式Deny才是坑。如果你的策略既没有Allow也没有Deny,结果就是拒绝。我在项目中遇到过:某个团队写了一条只包含Condition的语句,忘了加Effect,结果所有请求都被默默拒绝,查了一整天。

避坑指南:一定要养成检查Effect的习惯。写策略时先问自己:“这一条是允许还是拒绝?”然后在脑子里跑一遍默认逻辑。

2.5 Action——具体允许或拒绝的操作

Action的格式通常是服务名:操作名,可以有多条。比如:

"Action": [
  "s3:GetObject",
  "s3:PutObject"
]

也可以用通配符*,但我不推荐滥用。为什么?因为它会让你失去对细粒度权限的控制。我个人习惯:先写最小需要的Action列表,后续再通过测试逐步放宽。说实话,一开始就写"Action": "*"的做法,除了Demo环境,在生产里就是定时炸弹。

2.6 Resource——权限作用的对象

Resource指定了哪些资源可以被操作。ARN的格式因服务而异,但通用模板是:

arn:partition:service:region:account-id:resource-type/resource-id

比如S3的ARN:arn:aws:s3:::my-bucket/*。注意那个/*——它表示桶内所有对象。如果只写arn:aws:s3:::my-bucket,那只能操作桶本身(比如列出桶),而不能操作对象。

在实际项目中,最容易出问题的地方就是Resource写得太宽了。我记得有一次,团队给一个Lambda函数的执行角色配了Resource: "*",结果它就能访问所有人的S3桶。虽然短期内没出事,但安全审计时直接被标红。我们后来强制要求:Resource必须明确到具体的桶或路径。

2.7 Condition——控制条件

Condition可以让你在特定条件下才生效。常见的有:IP地址限制、时间范围、是否使用MFA、资源标签等。语法结构是:

"Condition": {
  "条件运算符": {
    "条件键": "条件值"
  }
}

举个例子,只允许从公司内网访问:

"Condition": {
  "IpAddress": {
    "aws:SourceIp": "203.0.113.0/24"
  }
}

Condition里有个比较容易踩的坑:条件键的大小写。比如aws:SourceIp中间的SourceIp,S是大写的。如果写成小写,条件永远不会匹配。嗯,这里要注意。

2.8 它们如何协作?一张SVG结构图

下面这张图帮你串起整个语法结构。每个字段各自扮演什么角色,一目了然。

IAM策略语法结构图 IAM策略 (Policy) Version 策略版本 (2012-10-17) 1..N Statement (语句) Effect Allow / Deny Action s3:GetObject, etc. Resource ARN 资源标识 Condition 可选条件 条件运算符 IpAddress BoolIfExists DateGreaterThan 策略匹配流程:检查Effect→校验Action→匹配Resource→评估Condition

2.9 实战总结:写策略时的四个检查点

  1. Version——确保是 2012-10-17,不要用旧版。
  2. Effect + Action 组合——别漏写Effect,也别写超范围的Action。
  3. Resource——宁可写多个具体ARN,也别用“*”代替一切。
  4. Condition——条件键的大小写、运算符的选取都要核对。

我个人习惯:写完策略先做安全评审。把策略贴到内部工具或AWS IAM模拟器里测试一遍。别偷懒,我曾经就因为少写了一个Condition,差点让非内网IP也能访问敏感数据。测试就是成本最小的保险。

2.10 常见陷阱一览表

陷阱表现解决方法
Effect默认不含Deny权限意外泄露显式声明Deny语句
Resource中桶名不包含“/*”无法访问桶内对象检查ARN,对象权限加“/*”
Condition条件键大小写错条件永不生效查阅官方文档复制写法
多条Statement不按字面顺序执行逻辑混乱依赖显式Deny,不依赖顺序