3. IAM策略深度解析
IAM 策略是 AWS 访问控制的“规则文本”。它本质上是一段 JSON 文档,描述“谁在什么条件下,能对哪些资源执行哪些操作,结果是允许还是拒绝”。理解策略,不能只记住字段名,而要理解每个字段在评估引擎中扮演的角色,以及它们如何组合成最终判定。
策略文档的基本骨架
一条身份策略通常由 Version 和 Statement 两个顶层字段组成,Statement 是一个数组,可以包含一条或多条语句。每条语句内部再使用 Effect、Action、Resource、Condition、Principal 等字段描述具体规则。下面是一个典型的 S3 只读策略示例:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowListAndReadReports",
"Effect": "Allow",
"Action": [
"s3:ListBucket",
"s3:GetObject"
],
"Resource": [
"arn:aws:s3:::example-reports",
"arn:aws:s3:::example-reports/*"
],
"Condition": {
"StringEquals": {
"aws:PrincipalTag/team": "analytics"
},
"IpAddress": {
"aws:SourceIp": "203.0.113.0/24"
}
}
}
]
}
这段策略的含义是:仅当请求者带有 team=analytics 的标签,且来源 IP 落在 203.0.113.0/24 网段时,才允许列出 example-reports 桶并读取其中对象。注意 ListBucket 作用于桶本身,GetObject 作用于桶内对象,因此 Resource 必须同时写出桶 ARN 和对象 ARN,否则会出现“列表能过、下载被拒”的典型问题。
Effect、Action、Resource 的语义
Effect 只有 Allow 和 Deny 两个取值。Action 描述允许或拒绝的具体 API 操作,例如 s3:GetObject、ec2:StartInstances、iam:PassRole。Action 支持通配符,如 s3:Get* 或 ec2:*,但通配符会显著扩大权限面,生产环境应尽量收敛到最小集合。Resource 使用 ARN 定位对象,不同服务的 ARN 格式不同:S3 是 arn:aws:s3:::bucket/key,IAM 是 arn:aws:iam::123456789012:role/name,EC2 是 arn:aws:ec2:region:account:instance/id。Resource 也支持通配符,但同样需要谨慎。
一个常见误区是认为“没有 Allow 就是拒绝”。实际上 IAM 默认隐式拒绝:如果没有任何语句显式允许某操作,该操作就被拒绝。因此策略设计的第一步是明确“需要允许什么”,而不是“需要禁止什么”。
Condition 与策略变量
Condition 是策略中最灵活也最容易出错的部分。它由条件运算符和键值对组成,常见运算符包括 StringEquals、StringLike、IpAddress、Bool、DateGreaterThan、NumericLessThan 等。条件键分为全局条件键(如 aws:SourceIp、aws:PrincipalTag、aws:RequestedRegion、aws:MultiFactorAuthPresent)和服务级条件键(如 s3:prefix、ec2:InstanceType)。
策略变量允许在策略中引用请求上下文中的值,从而写出“动态”规则。例如,让每个用户只能访问以自己名字命名的 S3 前缀:
{
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::team-bucket/home/${aws:username}/*"
}
当用户 alice 发起请求时,${aws:username} 会被替换为 alice,资源范围自动收敛到 home/alice/ 下。类似地,${aws:PrincipalTag/team}、${aws:SourceIp} 等变量可用于标签化授权和网络边界控制。变量必须与条件或资源字段配合使用,且要注意变量未定义时的行为——通常会导致语句不匹配,从而不生效。
策略评估逻辑
AWS 的授权判定遵循一套明确的评估顺序。理解这套顺序,比死记字段更重要。下图展示了从请求进入、策略收集、显式拒绝检查、允许匹配到最终判定的完整链路:
评估顺序可以概括为:先检查所有适用策略中是否存在显式 Deny,只要有一条 Deny 命中,请求立即被拒绝;如果没有 Deny,再检查是否存在至少一条 Allow 命中;如果存在,则允许;如果不存在,则隐式拒绝。SCP、权限边界和会话策略不会直接授予权限,它们只做“收窄”,即最终有效权限是身份策略允许范围与这些边界的交集。
常见策略设计陷阱
第一,Resource 与 Action 不匹配。例如只写桶 ARN 却要执行 GetObject,或只写对象 ARN 却要执行 ListBucket,都会导致权限不生效。第二,Condition 键拼写错误或大小写不一致,条件不匹配时语句静默失效,不会报错。第三,过度使用通配符,如 "Action": "*" 配合 "Resource": "*",等价于管理员权限,应严格避免。第四,忽略策略变量未定义的情况,例如未给用户打标签却使用 ${aws:PrincipalTag/team},语句不会命中。