IAM 策略语法:核心六大元素拆解

说白了,IAM 策略就是一段 JSON,告诉 AWS “谁(Principal)在什么条件下(Condition)可以对什么资源(Resource)做什么操作(Action)”。我刚开始接触时,总觉得这东西很绕,后来拆成六个字段就清晰了。来,一个个过。

Version:版本声明

Version 指定策略使用的语法版本。目前只有两个有效值:

  • "2012-10-17" — 当前标准版本,新策略必须用这个。
  • "2008-10-17" — 旧版本,已不推荐。

小技巧:我习惯在所有策略里直接写 "Version": "2012-10-17",避免兼容性问题。这个字段其实是固定的,你基本不会改它。

Statement:策略的核心载体

Statement 是一个数组,里面每条就是一个权限规则。说白了,一条 Statement 就是一句话:允许或拒绝谁做什么事。它的子元素有四个:Effect、Action、Resource、Condition。

Effect — 允许还是拒绝

只有两个值:"Allow" 或 "Deny"。Deny 优先级总是高于 Allow,这是 AWS 的安全铁律。

注意:我曾经在项目中写了一个全局 Allow 的 S3 策略,然后又加了一条 Deny 特定桶的策略。结果 Deny 生效后,连我自己都访问不了那个桶了… Deny 是真的“一票否决”。

Action — 允许的操作

Action 是一组服务操作,格式为 "服务名:操作名称",比如 "s3:GetObject"。支持通配符 *,但要注意范围。

  • 写 "ec2:*" 就是所有 EC2 操作。
  • 精确写法比如 "kms:Decrypt" 只允许解密。

我在项目中常见一个坑:有人写 "Action": "s3:*",结果发现 ListBucket 也允许了,导致桶里文件列表可被枚举。最好按最小权限原则,只写需要的操作。

Resource — 作用于哪些资源

Resource 的格式是 ARN(Amazon Resource Name)。例如:

"Resource": "arn:aws:s3:::my-bucket/*"

注意:有些操作要求 Resource 写 "*",比如 IAM 自身的 iam:PassRole。我刚开始老写错,后来记住了:服务自身管理类操作通常不绑定到具体资源。

资源类型 ARN 示例
S3 桶对象 arn:aws:s3:::my-bucket/*
KMS 密钥 arn:aws:kms:us-west-2:123456:key/xxxx
EC2 实例 arn:aws:ec2:us-east-1:123456:instance/*

Condition — 附加条件(可选但强大)

Condition 让你更精细地控制权限,比如限制来源 IP、要求 MFA、限制 TLS 版本。格式是 "条件运算符": { "条件键": "条件值" }。

举个例子:

"Condition": {
  "IpAddress": {
    "aws:SourceIp": "203.0.113.0/24"
  },
  "Bool": {
    "aws:SecureTransport": "true"
  }
}

这个策略只允许来自 203.0.113.0/24 网段且使用 HTTPS 的请求。嗯,这里要注意:条件键必须全局唯一,比如 aws:SourceIp 是通用的,s3:x-amz-server-side-encryption 是 S3 专属的。

避坑指南:我曾见过有人用 StringEquals 判断 IP,结果 IP 是字符串比较,忽略了 CIDR 范围,导致权限失效。记住:IP 范围必须用 IpAddress 或 NotIpAddress。

一张图看懂策略结构

下面我把整个 Statement 的骨架画出来,你照着写就不会漏字段了。

IAM 策略 JSON 结构图 IAM 策略 JSON 结构 Policy (根) Version Statement [ ] Effect Action Resource Condition 条件运算符 条件键 条件值 ⚠️ 注意 Effect: Allow / Deny Action: 服务:操作 Resource: ARN Condition: 可选但常见

实战:把六个元素拼在一起

来看一个完整的策略例子。这个策略只允许用户从公司内网 IP 访问 S3 的 my-bucket 桶内对象,且必须使用 HTTPS。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["s3:GetObject", "s3:PutObject"],
      "Resource": "arn:aws:s3:::my-bucket/*",
      "Condition": {
        "IpAddress": {
          "aws:SourceIp": "10.0.0.0/8"
        },
        "Bool": {
          "aws:SecureTransport": "true"
        }
      }
    }
  ]
}

经验之谈:我刚开始时总把 Condition 写成列表,结果 AWS 直接报错。Condition 里每个条件运算符只能出现一次,但可以包含多个条件键。比如同时限制 IP 和 MFA:

"Condition": {
  "IpAddress": { "aws:SourceIp": "10.0.0.0/8" },
  "Bool": { "aws:MultiFactorAuthPresent": "true" }
}

六个字段的常见错误

字段 常见错误 正确做法
Version 写错日期 固定 2012-10-17
Effect 拼写成 allow(小写) 首字母大写:Allow
Action 漏掉服务名前缀 完整格式如 s3:ListBucket
Resource 桶和对象 ARN 混淆 桶: arn:aws:s3:::bucket,对象: arn:aws:s3:::bucket/*
Condition 条件键用错 查文档确认全局键或服务专属键

提醒:我见过有人把 Condition 放在 Statement 外面,结果 JSON 格式虽然没错,但条件完全不生效。Condition 必须是 Statement 的子元素,别放错层级。

好,到这,IAM 策略的六大元素你就全掌握了。写策略时对照这张图,基本不会漏字段。记住最关键的一条:Deny 优先,最小权限,条件收窄。这九个字能帮你避开90%的权限事故。