第二章:AWS IAM 策略基础 —— 用户、组、角色与策略语法

好,我们直接进入正题。IAM 是 AWS 权限体系的基石,你写每一条策略、配每一个角色,最后都要落回 IAM 的基本概念上。这章我想先帮你把地基打牢,后面讲细粒度策略和 KMS 权限才不会晕。

2.1 三个核心实体:用户、组、角色

说实话,很多新手会把角色和用户搞混。我当年也犯过这个错,给一个 EC2 实例配了用户凭证,结果密钥泄露……那叫一个惨。咱们先看定义:

  • IAM 用户:代表一个人或一个应用。有长期凭证(密码 + 访问密钥)。通常用来给同事开控制台登录,或者给 CI/CD 工具调用 API。
  • IAM 组:用户容器。把权限附加到组上,用户加入组就继承权限。省事,但也容易权限扩散。
  • IAM 角色:没有长期凭证,临时凭证由 STS 颁发。给 AWS 服务(EC2/Lambda)、跨账号访问、联合身份用。

我的一条经验:能用角色就别用用户密钥。我在一次安全审计中发现客户把管理员密钥写死在代码里,差点被合规卡死。后来全改成了角色+STS,干净多了。

2.2 策略语法入门

IAM 策略本质是一个 JSON 文档,结构固定。我们直接看一条最常见的例子:

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

五个核心字段:

字段说明我踩过的坑
Version策略版本,必须写 2012-10-17你写错一个字符,整个策略就解析失败
Statement数组,可以写多条规则注意是数组,只放一条也要加方括号
EffectAllow 或 DenyDeny 优先级比 Allow 高——显式拒绝永远覆盖允许
Action一个或多个操作,支持通配符 *我曾经写了个 "s3:*" 导致所有人都能删桶……记得收紧
ResourceARN,也可以用 *但别随便用 *,除非你确定要开放全部资源

2.3 条件(Condition)—— 策略的灵魂

前面那只是基础策略,真正让权限变细的,是 Condition。为啥这么说?

你想,如果没有条件,"Resource": "*" 就是给所有权限。但有了条件,就能写成:

{
  "Effect": "Allow",
  "Action": "kms:Decrypt",
  "Resource": "*",
  "Condition": {
    "IpAddress": {
      "aws:SourceIp": "10.0.0.0/8"
    }
  }
}

这就把解密操作限制在内部网段。我在客户那里遇到过一例:他们把 KMS 解密权限直接开放给了一个 IAM 用户,没有加条件,结果员工从家里 VPN 解密了敏感数据……后来加上了 VPC SourceVpce 条件,才算堵住。

常用条件键:aws:SourceIp、aws:RequestedRegion、kms:ViaService、aws:MultiFactorAuthPresent。其中 kms:ViaService 是第七章的重点,先记个印象。

2.4 四种策略类型

别以为就一种策略类型。实际你写策略时,要区分它挂在哪里:

  • 身份策略:直接挂用户/组/角色。最常见。
  • 资源策略:挂到 S3 桶、KMS 密钥等资源上。可以跨账号。
  • 权限边界:限制用户能获得的最大权限,不能越界。
  • 服务控制策略(SCP):组织级别限制,控制整个 OU 下的所有账号。

这些类型之间是叠加和优先级关系。我画了张图帮你理清流程:

IAM 策略授权决策流程 请求发起 SCP 显式拒绝? 拒绝(Deny) 权限边界拒绝? 身份策略 + 资源策略 评估 显式 Allow 存在? 最终:Allow 或 Deny 说明 • 显式 Deny 直接拒绝 • 权限边界限制最大值 • 最后看是否有 Allow

注意图上的两个关键点:显式 Deny 优先级最高,其次权限边界会砍掉超出范围的操作,最后才是身份和资源策略里的 Allow。别以为写了个 Allow 就万事大吉——如果 SCP 里 Deny 了,你无论如何也通不过。

2.5 策略生效逻辑

我习惯用一个口诀记:「拒绝优先,边界收口,Allow 放行,无 Allow 默认 Deny。」

  1. 显式允许(Allow)—直接放行,但必须没有被显式拒绝。
  2. 显式拒绝(Deny)—无论其他策略是什么,直接拒绝。
  3. 隐式拒绝—没有任何 Allow,默认 Deny。

我曾经摔过的跟头:给一个 S3 桶写了两条策略,一条 Allow 列出桶,另一条 Deny DeleteObject。结果因为 Deny 写成了 "Action": "s3:DeleteObject",忘了加星号,导致只有精确匹配的操作被拒绝,而 s3:DeleteObjectVersion 漏掉了……经过教训,现在我习惯在 Deny 里用 "Action": "s3:DeleteObject*" 通配。

2.6 实战:写一条最小权限策略

假设你有一个分析工作负载,只需要从 S3 读取日志文件,然后用 KMS 解密。应该怎么写?

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:ListBucket"
      ],
      "Resource": [
        "arn:aws:s3:::log-bucket",
        "arn:aws:s3:::log-bucket/*"
      ]
    },
    {
      "Effect": "Allow",
      "Action": "kms:Decrypt",
      "Resource": "*",
      "Condition": {
        "ForAnyValue:StringLike": {
          "kms:ViaService": "s3.*.amazonaws.com"
        }
      }
    }
  ]
}

这里用了 kms:ViaService 条件,意思是你只能用 KMS 解密通过 S3 发起的请求。这样即使用户拿到了密钥权限,也没法直接调用 KMS API 批量解密。这种细粒度的条件,就是咱们这门课要深入讲的内容。

2.7 本章小结

记住三个实体、一个 JSON 五字段、条件决定细粒度、四种策略类型。后面的章节我们会反复用到这些东西。尤其条件部分,你会看到它怎么配合 KMS 的上下文密钥策略做更精细的控制。今天先把框架搭好。