3. IAM与跨账户访问基础

跨账户数据共享的第一道门槛不是S3桶策略,也不是Glue Catalog资源策略,而是IAM身份与授权模型。很多团队在配置跨账户访问时,习惯性地把权限直接授予对方账户的某个用户,结果要么权限过大,要么在对方人员变动后留下长期有效的“幽灵权限”。要真正实现最小权限的跨团队数据访问,必须理解IAM角色、信任策略与权限边界三者的分工,并让它们协同工作。

一、为什么跨账户访问要用角色,而不是直接授权用户

IAM用户属于某一个AWS账户,它的凭证(访问密钥、密码)由该账户管理。当A团队需要访问B团队账户中的S3数据时,如果B团队直接给A团队的某个IAM用户附加权限,会带来两个问题:一是权限依附于具体用户,人员离职或密钥轮换时难以追踪;二是B团队无法控制A团队内部谁可以使用这份权限。

正确做法是由B团队创建一个IAM角色,在角色的信任策略(Trust Policy)中声明“允许A团队账户中的特定主体来扮演我”。A团队的用户或服务通过sts:AssumeRole获取临时凭证,凭证有效期通常为15分钟到12小时。这样权限的授予对象是“角色”,而不是“某个人”,B团队始终掌握着信任关系的开关。

核心分工:信任策略回答“谁能扮演这个角色”,权限策略回答“扮演后能做什么”,权限边界回答“这个角色最多能拥有多大权限”。三者缺一不可。

二、信任策略:跨账户访问的入口控制

信任策略是IAM角色的资源策略,它决定了哪些主体可以调用sts:AssumeRole。一个典型的跨账户信任策略如下:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::111122223333:root"
      },
      "Action": "sts:AssumeRole",
      "Condition": {
        "StringEquals": {
          "sts:ExternalId": "data-share-2024"
        }
      }
    }
  ]
}

这里有几个关键点。第一,Principal写的是A团队的账户根ARN,但这不代表整个账户的所有用户都能扮演。实际上,A团队内部还需要通过自己的IAM策略,显式授予某个用户或角色sts:AssumeRole的权限,才能完成扮演。也就是说,跨账户访问需要双方各授权一次:B团队在信任策略中允许,A团队在身份策略中放行。

第二,Condition中的sts:ExternalId是防止“混淆代理”问题的关键。当A团队使用第三方SaaS工具访问B团队数据时,ExternalId可以确保只有持有该标识的请求才能扮演角色。对于纯内部团队协作,ExternalId不是必须的,但建议保留,作为额外的审计线索。

第三,信任策略中应尽量缩小Principal范围。如果A团队只有一个特定角色需要访问,可以直接写该角色的ARN,而不是整个账户根。这样即使A团队账户被入侵,攻击者也无法随意扮演该角色。

三、权限策略与权限边界:控制“能做什么”和“最多能做什么”

角色被扮演后,实际能执行哪些操作由权限策略(Permission Policy)决定。例如,B团队希望A团队只能读取analytics-shared桶中reports/前缀下的对象,权限策略可以写成:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["s3:GetObject", "s3:ListBucket"],
      "Resource": [
        "arn:aws:s3:::analytics-shared",
        "arn:aws:s3:::analytics-shared/reports/*"
      ]
    }
  ]
}

注意ListBucket作用于桶本身,GetObject作用于对象,两者资源ARN的写法不同。如果只写对象ARN而漏掉桶ARN,控制台或CLI在列举对象时会报AccessDenied,但直接读取已知对象仍然成功,这种“半通不通”的状态在排障时很常见。

权限边界(Permissions Boundary)则是一个上限。它本身不授予任何权限,只是规定“这个角色即使被附加了更多策略,实际生效的权限也不会超过边界”。在跨团队场景中,B团队可以用权限边界来限制自己团队内部创建的角色,防止某个开发者无意中给角色附加了s3:*或kms:Decrypt之外的敏感权限。权限边界与身份策略的交集才是最终生效权限。

跨账户IAM角色访问控制模型 账户 A(数据使用方) IAM 用户 / 服务 analyst@team-a 身份策略 Allow sts:AssumeRole → arn:aws:iam::444455556666:role/DataReader STS 临时凭证 有效期 1 小时 账户 B(数据拥有方) IAM 角色 DataReader 信任策略:允许账户 A Condition: ExternalId 权限策略 s3:GetObject / ListBucket → analytics-shared/reports/* 权限边界(上限) 仅允许 S3 只读 + KMS 解密 sts:AssumeRole 临时凭证返回 权限交集生效 最终权限 = 身份策略 ∩ 权限策略 ∩ 权限边界(信任策略仅控制能否扮演)

四、最小权限的落地检查清单

在实际配置跨团队数据访问时,可以按以下顺序逐项确认,避免遗漏或过度授权:

  • 信任策略的Principal是否精确到角色ARN,而不是整个账户根;如果必须用账户根,是否附加了ExternalId或SourceArn条件。
  • 权限策略是否只包含必要的Action,例如只读场景下不出现s3:PutObject、s3:DeleteObject。
  • 资源ARN是否限定到前缀或具体对象,避免arn:aws:s3:::*这类通配。
  • 是否附加了权限边界,尤其是当角色由自动化流程或开发者自助创建时。
  • 是否配置了CloudTrail数据事件,用于记录跨账户的AssumeRole和S3对象访问。
  • 临时凭证的会话时长是否合理,长时间运行的任务可以设置1小时,交互式分析可以缩短到15分钟。
一个常见的误区是:在信任策略中写了账户根ARN,就以为对方账户的所有用户都能访问。实际上,对方账户内部还需要有身份策略允许sts:AssumeRole。如果对方没有配置,扮演会失败并返回AccessDenied。排障时先确认双方策略是否都到位。

五、验证与排障

配置完成后,可以用AWS CLI验证角色是否可以被成功扮演:

aws sts assume-role \
  --role-arn arn:aws:iam::444455556666:role/DataReader \
  --role-session-name test-cross-account \
  --external-id data-share-2024

如果返回Credentials字段,说明信任策略和身份策略都正确。接着用返回的临时凭证尝试读取目标对象:

aws s3 cp s3://analytics-shared/reports/2024/summary.csv . \
  --profile cross-account

如果AssumeRole成功但读取失败,问题通常出在权限策略的资源ARN或Action上;如果AssumeRole本身就失败,则检查信任策略的Principal、Condition以及调用方身份策略。通过CloudTrail的AssumeRole事件可以查看具体的错误码和请求参数,这是定位跨账户访问问题最直接的依据。

把IAM角色、信任策略和权限边界三者配合好,跨团队数据访问就不再是“给个账号密码”的粗放模式,而是可审计、可撤销、可收敛到最小权限的工程化实践。