评估流程
了解 IAM 在允许或拒绝请求时所采取的步骤。
现在我们已经讨论了IAM如何看待请求以及控制访问的策略工作原理,接下来需要了解其判断请求是否被允许或拒绝的具体步骤。
第一步:构建请求上下文
首先,系统会根据我们在访问元素课程中讨论的内容构建请求上下文。该上下文包括以下要素:
- 主体(Principal):发起请求的实体;
- 操作(Action):描述正在执行的动作;
- 资源(Resource):操作的目标AWS实体;
- 以及其他附加到请求上的元数据(metadata)。
遗憾的是,我们对这一步的结果了解有限。可以推测这是一个键值结构,其中每个键都来自请求本身。
例如,当用户向AWS发送请求以读取S3存储桶中的对象时,请求上下文可能如下所示:
1主体:arn:aws:iam::<id>:user/user1 2操作:s3:GetObject 3资源:<bucket>/text.txt
这些值直接来源于操作内容:主体对某个资源执行某项操作。随后,IAM会用其他可用信息填充元数据:
1主体:arn:aws:iam::<id>:user/user1 2操作:s3:GetObject 3资源:<bucket>/text.txt 4aws:SourceIp: 203.0.113.0 5aws:MultiFactorAuthPresent: true 6aws:MultiFactorAuthAge: 3000
上述请求上下文包含了请求来源的IP地址 aws:SourceIp,以及用户使用MFA设备进行认证的信息 aws:MultiFactorAuthPresent 与 aws:MultiFactorAuthAge。实际上,请求上下文包含的信息远不止这些,还包括主体的用户名和用户ID、附加到资源上的标签,以及请求是否通过SSL传输。
注意:请求上下文中确切的值并不明确。我们只能通过阅读文档来推测它们可能是什么。
第二步:收集所有适用的策略
下一步是收集所有适用的策略。正如我们在过滤器课程中所见,大多数IAM策略的属性用于指定该策略适用于哪些请求。IAM会检查所有策略,结合上一步构建的请求上下文,并逐一评估每条策略中的各个过滤条件。此步骤的目标是排除所有不匹配当前请求的策略。
注意:此过程是针对每条策略单独执行的。只有当一条策略的所有过滤条件都与请求上下文匹配时,它才会进入下一步。
举个例子,考虑一个附加到名为 user1 的用户的基于身份的策略。在这种情况下,Principal 元素是隐含的:
1{ 2 "Effect": "Allow", 3 "Action": "s3:*", 4 "Resource": "*" 5}
将其与以下请求上下文进行匹配:
1主体:arn:aws:iam::<id>:user/user1 2操作:s3:GetObject 3资源:<bucket>/text.txt
该策略中的过滤条件为 "Action": "s3:*"、"Resource": "*",以及由于策略附加在 user1 上,因此 Principal 也隐含为 user1。
| 过滤条件 | 值 | 是否匹配? |
|---|---|---|
| Action: s3:* | s3:GetObject | ✔ |
| Principal: user1 | user1 | ✔ |
| Resource: * | ✔ |
由于所有过滤条件均匹配,该策略将在下一步中被使用。
但如果请求是由另一个用户 user2 发起的,请求上下文中的主体就不同了:
1主体:arn:aws:iam::<id>:user/user2 2操作:s3:GetObject 3资源:<bucket>/text.txt
此时,该策略的过滤条件不再匹配此请求,因此不会进入下一步。
| 过滤条件 | 值 | 是否匹配? |
|---|---|---|
| Action: s3:* | s3:GetObject | ✔ |
| Principal: user1 | user2 | - |
| Resource: * | ✔ |
注意:在此步骤中,策略的
Effect是"Allow"还是"Deny"并不重要。IAM仅负责收集与请求匹配的策略。是否允许或拒绝访问将在下一步处理。
基于资源的策略可以定义 Principal 元素来指定其适用的实体。下面这个策略允许 user1 读取存储桶中的对象:
1{ 2 "Effect": "Allow", 3 "Action": "s3:GetObject", 4 "Principal": { 5 "AWS": "arn:aws:iam::<id>:user/user1" 6 }, 7 "Resource": "<bucket>/*" 8}
当 user1 尝试读取对象时,该策略匹配。
| 过滤条件 | 值 | 是否匹配? |
|---|---|---|
| Action: s3:GetObject | s3:GetObject | ✔ |
| Principal: user1 | user1 | ✔ |
| Resource: | ✔ |
但当 user2 执行相同操作时,则不匹配:
| 过滤条件 | 值 | 是否匹配? |
|---|---|---|
| Action: s3:GetObject | s3:GetObject | ✔ |
| Principal: user1 | user2 | - |
| Resource: | ✔ |
此过程同样适用于否定值。例如,当资源策略中定义了 NotPrincipal 时,它会影响那些不在策略中的用户:
1{ 2 "Effect": "Allow", 3 "Action": "s3:GetObject", 4 "NotPrincipal": { 5 "AWS": "arn:aws:iam::<id>:user/user2" 6 }, 7 "Resource": "<bucket>/*" 8}
由 user1 发起的请求将通过所有过滤条件:
| 过滤条件 | 值 | 是否匹配? |
|---|---|---|
| Action: s3:GetObject | s3:GetObject | ✔ |
| NotPrincipal: user2 | user1 | ✔ |
| Resource: | ✔ |
但由 user2 发起的相同请求则不会通过:
| 过滤条件 | 值 | 是否匹配? |
|---|---|---|
| Action: s3:GetObject | s3:GetObject | ✔ |
| NotPrincipal: user2 | user2 | - |
| Resource: | ✔ |
同样的逻辑也适用于 NotAction 和 NotResource 元素。
最后,Condition 元素用于检查请求上下文中的元数据。以下这个基于资源的策略要求必须使用MFA设备进行认证:
1{ 2 "Version": "2012-10-17", 3 "Statement": { 4 "Effect": "Deny", 5 "Principal": "*", 6 "Action": "*", 7 "Resource": "<bucket>/*", 8 "Condition": { 9 "Bool": { 10 "aws:MultiFactorAuthPresent": "false" 11 } 12 } 13 } 14}
当用户使用MFA设备时,该策略不匹配:
| 过滤条件 | 值 | 是否匹配? |
|---|---|---|
| Action: * | s3:GetObject | ✔ |
| Principal: * | user1 | ✔ |
| Resource: | ✔ | |
| aws:MultiFactorAuthPresent: false | true | - |
相反,当未使用MFA设备时,该策略则匹配:
| 过滤条件 | 值 | 是否匹配? |
|---|---|---|
| Action: * | s3:GetObject | ✔ |
| Principal: * | user1 | ✔ |
| Resource: | ✔ | |
| aws:MultiFactorAuthPresent: false | false | ✔ |
注意:此步骤的结果是一个与请求上下文匹配的策略集合。这些策略将在下一步中使用。
第三步:运行评估逻辑
在通过过滤条件收集到有效的策略语句后,系统将使用策略评估逻辑来决定请求是否被允许。AWS官方文档提供了一张描述性图表,总结了其工作方式:
虽然看起来复杂,但图表的大部分内容其实只体现了两个简单原则:
- 如果存在
Deny,则结果为拒绝。 - 如果不存在
Allow,则结果为拒绝。
其余部分主要是为了说明哪些策略是“足够”的,哪些是“可选”的。
服务控制策略(SCP)、权限边界和会话级策略属于特定使用场景,是可选的。如果我们没有使用它们,它们就不会影响策略评估,IAM会跳过这些部分。最重要的是基于身份的策略和基于资源的策略。绝大多数策略都属于这两种类型。
当我们去掉那些面向特定场景的部分后,评估逻辑变得简单明了:
关键点在于:只要基于资源的策略或基于身份的策略中有一个允许该操作,请求就会被允许。
让我们来测试一下你在这节课中学到的概念!
Quiz
请求上下文包含来自主体、资源、操作以及附加到请求的任何元数据的信息。