3. AWS IAM 深度解析:用户、组、角色、策略、信任关系、跨账户访问

说到云上安全,IAM 是绕不开的核心。很多人觉得 IAM 就是个“创建用户、打勾权限”的地方,其实远没那么简单。我见过不少团队,因为 IAM 策略写得太松,结果一个开发账号能删整个 RDS 集群——嗯,那场面挺刺激的。

这一章,咱们把 IAM 的五个核心概念掰开揉碎:用户、组、角色、策略、信任关系。最后再聊聊跨账户访问怎么玩。你把这些搞明白了,多云数据湖的权限骨架就算搭起来了。

3.1 用户(User):谁在敲门?

IAM 用户代表一个实体,可以是人,也可以是应用。每个用户有唯一的 ARN(Amazon Resource Name),用来标识身份。

创建用户时,你通常会做两件事:

  • 控制台密码:给真人用的,记得开 MFA。
  • 访问密钥(Access Key):给程序用的,别硬编码在代码里。
我的习惯: 每个用户只分配最小必要权限。哪怕对方是 CTO,也别给 AdministratorAccess。我曾经见过一个团队,所有开发都用同一个 root 用户的密钥——后来密钥泄露,整个 S3 桶被清空。从那以后,我坚持“一人一用户,一应用一密钥”。

3.2 组(Group):批量管理的好帮手

组就是用户的集合。你把权限挂到组上,用户加入组就继承权限。这样管理起来省心多了。

举个例子:

# 创建组
aws iam create-group --group-name DataEngineers

# 给组附加策略
aws iam attach-group-policy \
  --group-name DataEngineers \
  --policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess

# 把用户加入组
aws iam add-user-to-group \
  --group-name DataEngineers \
  --user-name zhangsan

你想想看,如果公司有 50 个数据工程师,每个人单独挂策略,改一次权限得改 50 次。用组的话,改一个地方就行。说白了,组就是权限的“模板”。

3.3 角色(Role):临时通行证

角色和用户最大的区别是:角色没有长期凭证。角色是一组权限的集合,谁需要谁“扮演”。扮演成功后,AWS 临时给你发一组密钥,有效期默认 1 小时,最长 12 小时。

角色常用于:

  • EC2 实例访问 S3
  • Lambda 函数操作 DynamoDB
  • 跨账户访问
  • 联合身份认证(比如用 Okta 登录)
核心区别:
特性 用户 角色
凭证类型 长期(密码/密钥) 临时(STS )
适用场景 真人、长期应用 服务、跨账户、联合身份
管理复杂度 高(密钥轮转麻烦) 低(自动轮转)
安全风险 密钥泄露风险 相对更低

我个人强烈建议:能用角色就别用用户密钥。尤其是 EC2 和 Lambda,直接挂角色,AWS 帮你自动轮转临时凭证,省心又安全。

3.4 策略(Policy):权限的“法律条文”

策略就是 JSON 文档,定义了“谁能在什么条件下对什么资源做什么操作”。IAM 策略分两种:

  • AWS 托管策略:AWS 帮你维护的,比如 AmazonS3FullAccess。
  • 客户托管策略:你自己写的,更精细。

一个典型的策略长这样:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:ListBucket"
      ],
      "Resource": [
        "arn:aws:s3:::data-lake-prod",
        "arn:aws:s3:::data-lake-prod/*"
      ],
      "Condition": {
        "IpAddress": {
          "aws:SourceIp": "10.0.0.0/16"
        }
      }
    }
  ]
}

这里要注意几个关键点:

  • Effect:Allow 或 Deny。Deny 优先级高于 Allow。
  • Action:操作列表,支持通配符 s3:*。
  • Resource:资源 ARN,精确到桶或对象。
  • Condition:条件限制,比如来源 IP、时间、是否启用 MFA。
我曾经踩过的坑: 写策略时忘了加 /*,结果 ListBucket 能过,GetObject 死活报 403。因为 arn:aws:s3:::bucket 只代表桶本身,桶里的对象要用 arn:aws:s3:::bucket/*。嗯,这个细节卡了我一下午。

3.5 信任关系(Trust Relationship):谁可以扮演角色?

角色本身不决定谁能用它。谁可以扮演角色,由角色的信任策略决定。信任策略也是一份 JSON,它定义了哪些主体(Principal)被允许调用 sts:AssumeRole。

举个例子:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::123456789012:user/cross-account-user"
      },
      "Action": "sts:AssumeRole",
      "Condition": {
        "Bool": {
          "aws:MultiFactorAuthPresent": "true"
        }
      }
    }
  ]
}

这个信任策略的意思是:只允许账号 123456789012 下的 cross-account-user 这个用户,在启用了 MFA 的情况下,扮演这个角色。

你想想看,信任关系就像一把锁,权限策略是锁里面的内容。锁本身不关心谁来开,但信任策略决定了谁有钥匙。

3.6 跨账户访问:打通不同 AWS 账号

在多云数据湖场景下,你经常需要让账号 A 的某个服务访问账号 B 的 S3 桶。跨账户访问的标准做法就是角色扮演。

流程分三步:

  1. 账号 B(资源账号):创建一个 IAM 角色,挂上允许访问 S3 桶的策略。
  2. 账号 B:在角色的信任策略中,把账号 A 的某个用户或角色设为 Principal。
  3. 账号 A(访问账号):调用 sts:AssumeRole,拿到临时凭证,然后用这个凭证去访问账号 B 的资源。

代码示例:

# 账号 A 上的操作
aws sts assume-role \
  --role-arn "arn:aws:iam::222222222222:role/DataLakeAccessRole" \
  --role-session-name "cross-account-session"

# 返回临时凭证,然后设置环境变量
export AWS_ACCESS_KEY_ID=ASIA...
export AWS_SECRET_ACCESS_KEY=...
export AWS_SESSION_=...

# 现在可以访问账号 B 的 S3 桶了
aws s3 ls s3://data-lake-bucket-in-account-b/
我的建议: 跨账户访问时,一定要在信任策略里加 Condition,比如限制来源 IP 或要求 MFA。否则,只要密钥泄露,攻击者就能直接扮演角色。我曾经帮一个客户做安全审计,发现他们的跨账户角色没有任何条件限制——说白了,谁拿到密钥都能进。后来我们加了 IP 限制和 MFA 要求,安全等级直接拉满。

3.7 知识体系总览

下面这张图把 IAM 的核心概念串起来了。你一看就明白:用户和组是“谁”,角色是“临时身份”,策略是“能做什么”,信任关系是“谁可以来”。

AWS IAM 核心概念关系图 IAM 用户 IAM 组 IAM 角色 IAM 策略 信任关系 跨账户访问(角色扮演) 用户和组是“谁”,角色是“临时身份”,策略是“能做什么”,信任关系是“谁可以来”

3.8 避坑指南

最后,分享几个我亲身踩过的坑:

  • 策略大小限制:每个 IAM 策略最大 6,144 个字符。别把所有权限写在一个策略里,拆成多个。
  • 角色信任策略别写太宽:Principal 写成 "AWS": "*" 等于把门敞开,任何人都能扮演。除非你明确知道自己在做什么,否则别这么干。
  • 跨账户角色删除后遗症:如果你删除了角色,但账号 A 还在用旧的临时凭证,会一直报错。记得先停用凭证再删角色。
  • 权限边界(Permissions Boundary):可以用它限制用户或角色的最大权限。我习惯给每个开发账号加一个权限边界,防止他们意外给自己提权。

IAM 这东西,看着简单,用好了是安全基石,用不好就是安全漏洞。你把这些概念吃透了,后面搭建多云数据湖的权限体系就会顺手很多。