混淆代理人问题
混淆代理问题是一个安全问题,即没有执行操作权限的实体可能会迫使更具权限的实体执行该操作。为了防止这种情况,如果您为账户中的资源提供第三方(称为跨账户)或其他 AWS 服务(称为跨服务)的访问权限,则 AWS 会提供用于保护您账户的工具。
有时,您需要向第三方提供对您的 AWS 资源的访问权 (提供访问权)。举例来说,您决定聘请一家名为 Example Corp 的第三方公司来监控您的 AWS 账户并帮助优化成本。为跟踪您的日常开支,Example Corp 需要访问您的 AWS 资源。Example Corp 也可监控其他客户的很多其他 AWS 账户。您可使用 IAM 角色在您的 AWS 账户 和 Example Corp 账户之间建立信任关系。此方案的一个重要方面是外部 ID,外部 ID 是一个可选标识符,您可在 IAM 角色信任策略中使用该信息来指定谁能代入该角色。外部 ID 的主要功能是解决并防止混淆代理人问题。
某些 AWS 服务(呼叫服务)使用其 AWS 服务主体从其他 AWS 服务(被叫服务)访问 AWS 资源。在其中一些服务交互中,您可以将呼叫服务配置为与来自其他 AWS 账户中的被叫服务的资源进行通信。例如,配置 AWS CloudTrail 以写入位于不同 AWS 账户的中央 Amazon S3 存储桶。通过为 cloudtrail.amazonaws.com 添加允许声明,呼叫服务 CloudTrail 可以使用 s3 存储桶的策略访问您的 s3 存储桶。
当来自呼叫服务的 AWS 服务主体访问来自被叫服务的资源时,来自被叫服务的资源策略仅授权 AWS 服务主体,而不是配置呼叫服务的角色。例如,不附带任何条件地信任 CloudTrail 服务主体的 Amazon S3 存储桶可以从受信任的管理员配置的 AWS 账户接收 CloudTrail 日志,但如果他们知道 Amazon S3 存储桶的名称,也可以从其 AWS 账户中的未经授权角色那里接收 CloudTrail 日志。
当某个角色利用 AWS 服务主体的信任来获得对他们本来不打算访问的资源的访问权限时,就会出现混淆的代理问题。
跨账户混淆代理人预防
下图阐明了跨账户混淆代理人问题。

此场景假定:
-
AWS1 是您的 AWS 账户。
-
AWS1:ExampleRole 是您账户中的一个角色。该角色的信任策略通过将 Example Corp 的 AWS 账户指定为可担任该角色的账户来信任 Example Corp。
将发生以下情况:
-
在您开始使用 Example Corp 的服务时,您将向 Example Corp 提供 AWS1:ExampleRole 的 ARN。
-
Example Corp 使用该角色 ARN 获取临时安全凭证以访问您的 AWS 账户 中的资源。这样一来,您将信任 Example Corp 作为可代表您执行操作的“代理人”。
-
另一个 AWS 客户也开始使用 Example Corp 的服务,而且此客户还为 Example Corp 提供了 AWS1:ExampleRole 的 ARN 以供其使用。另一个客户可能已了解或猜到已不是机密信息的 AWS1:ExampleRole。
-
当另一个客户要求 Example Corp 访问(它声称的)其账户中的 AWS 资源时,Example Corp 使用 AWS1:ExampleRole 访问您的账户中的资源。
这就是其他客户可对您的资源进行未授权访问的方式。由于此客户能够诱使 Example Corp 无意中操作您的资源,因此 Example Corp 现在是一个“混淆代理人”。
Example Corp 可以通过在角色信任策略中加入 ExternalId
条件检查来解决混淆的代理问题。Example Corp 为每个客户生成唯一的 ExternalId
值,并在其请求中使用该值来承担该角色。在 Example Corp 的客户中,ExternalId
值必须是独一无二的,并由 Example Corp 而不是其客户控制。这就是您从 Example Corp 获取该 ID 且不能自行提供该 ID 的原因。这可以防止 Example Corp 成为一个混淆代理人,以及授予对另一个账户的 AWS 资源的访问权。
在我们的方案中,假设 Example Corp 为您提供的唯一标识符是 12345,而为另一个客户提供的标识符是 67890。这些标识符已针对此方案进行简化。通常,这些标识符为 GUID。假定这些标识符在 Example Corp 的客户之间是唯一的,它们将是用于外部 ID 的有意义的值。
Example Corp 将向您提供外部 ID 值 12345。然后,您必须将一个 Condition
元素添加到角色的信任策略,该策略要求 sts:ExternalId
值为 12345,如下所示:
{ "Version": "2012-10-17", "Statement": { "Effect": "Allow", "Principal": { "AWS": "
Example Corp's AWS Account ID
" }, "Action": "sts:AssumeRole", "Condition": { "StringEquals": { "sts:ExternalId": "12345" } } } }
此策略中的 Condition 元素允许 Example Corp 仅在 AssumeRole API 调用包括外部 ID 值 12345 时代入该角色。Example Corp 确保,只要它代表客户担任角色,就会始终在 AssumeRole 调用中包括客户的外部 ID。即使另一个客户向 Example Corp 提供您的 ARN,也无法控制 Example Corp 包括在其发送给 AWS 的请求中的外部 ID。这有助于防止未经授权的客户获取对您的资源的访问权限。
下图阐明了此过程。

-
和之前一样,在您开始使用 Example Corp 的服务时,您将向 Example Corp 提供 AWS1:ExampleRole 的 ARN。
-
在 Example Corp 使用该角色 ARN 来代入角色 AWS1:ExampleRole 时,Example Corp 将在 AssumeRole API 调用中包含您的外部 ID(12345)。该外部 ID 与角色的信任策略匹配,因此 AssumeRole API 调用将成功,并且 Example Corp 将获取用于访问您的 AWS 账户 中的资源的临时安全凭证。
-
另一个 AWS 客户也开始使用 Example Corp 的服务,而且如之前一样,此客户还为 Example Corp 提供了 AWS1:ExampleRole 的 ARN 以供其使用。
-
但这一次,在 Example Corp 尝试代入角色 AWS1:ExampleRole 时,它提供了与另一个客户关联的外部 ID(67890)。另一个客户无法更改此外部 ID。Example Corp 这样做是因为另一个客户请求使用该角色,因此 67890 表示 Example Corp 正在其中操作的环境。由于您已将具有您自己的外部 ID(12345)的条件添加到 AWS1:ExampleRole 的信任策略,因此 AssumeRole API 调用将失败。而且将阻止另一个客户对您账户中的资源进行未经授权的访问(由图中的红色“X”表示)。
外部 ID 有助于防止任何其他客户欺骗 Example Corp 不知不觉地访问您的资源。
防止跨服务混淆代理
下图使用 CloudTrail 和 Amazon S3 交互示例演示了跨服务的混淆代理问题,其中未经授权的角色将 CloudTrail 日志写入他们无权访问的 Amazon S3 存储桶。

为了帮助防止未经授权的角色利用 AWS 主体的信任来访问您的资源,AWS 服务主体会提供有关他们所代表的 AWS 资源、AWS 账户和 AWS 组织的信息。
此信息以全局条件键值的形式提供,这些键值可用于资源策略或 AWS 服务主体发出的请求的资源控制策略。建议在您的资源策略中使用 aws:SourceArn、aws:SourceAccount、aws:SourceAccount 或 aws:SourceOrgPaths,只要 AWS 服务主体被授予访问您其中一个资源的权限。这些条件键使您能够在资源策略或资源控制策略中测试访问您资源的 AWS 服务主体是否在代表您期望的 AWS 资源、AWS 账户或 AWS Organizations 这样做。
-
使用
aws:SourceArn
允许 AWS 服务主体代表特定资源(例如特定 AWS CloudTrail 跟踪或 AppStream 实例集)访问您的资源。 -
使用
aws:SourceAccount
允许 AWS 服务主体代表特定 AWS 账户访问您的资源。 -
使用
aws:SourceOrgID
允许 AWS 服务主体代表特定 AWS Organizations访问您的资源。 -
使用
aws:SourceOrgPaths
允许 AWS 服务主体代表特定 AWS Organizations 路径访问您的资源。
下图演示了跨服务的混淆代理场景,即使用 aws:SourceAccount
全局条件上下文键配置资源,而来自另一个账户的未经授权的角色试图访问他们本来不打算访问的 AWS 资源。

在策略中使用 aws:SourceArn
、aws:SourceAccount
、aws:SourceOrgID
和 aws:SourceOrgPaths
全局条件键可帮助您确保服务主体代表您访问您的资源。建议每当向 AWS 服务主体授予对其中一个资源的访问权限时,都使用这些条件键。
注意
某些 AWS 服务交互具有额外的控件,可帮助防止测试用户对资源访问的跨服务混淆代理问题。例如,当向 AWS 服务发放 KMS 密钥授予时,AWS KMS 会使用与资源关联的加密上下文以及密钥授予来帮助防止跨服务的混淆代理问题。
有关帮助避免跨服务的混淆代理风险的更多信息,以及是否支持 aws:SourceArn
、aws:SourceAccount
、aws:SourceOrgID
和 aws:SourceOrgPaths
,请参阅您使用是服务的文档。
使用基于资源的策略进行跨服务混淆代理保护
仅当服务主体代表 AWS 账户 111122223333 行事时,以下示例策略授予服务主体 cloudtrail.amazonaws.com
访问 Amazon S3 存储桶,arn:aws:s3:::amzn-s3-demo-bucket1 的权限。
{ "Version": "2012-10-17", "Statement": [ { "Sid": "CloudTrailAclCheck", "Effect": "Allow", "Principal": {"Service": "cloudtrail.amazonaws.com"}, "Action": "s3:GetBucketAcl", "Resource": "arn:aws:s3:::
amzn-s3-demo-bucket1
", "Condition": { "StringEquals": { "aws:SourceAccount": "111122223333" } } }, { "Sid": "AWSCloudTrailWrite", "Effect": "Allow", "Principal": {"Service": "cloudtrail.amazonaws.com"}, "Action": "s3:PutObject", "Resource": "arn:aws:s3:::amzn-s3-demo-bucket1/[optionalPrefix]/Logs/myAccountID/*
", "Condition": { "StringEquals": { "aws:SourceAccount": "111122223333" } } } ] }
此示例存储桶策略仅在服务主体 appstream.amazonaws.com
通过使用 aws:SourceArn
指定实例集 ARN 来代表指定的 Amazon AppStream 实例集行事时,才授予服务主体访问 s3://amzn-s3-demo-bucket2 中的 powershell 脚本 examplefile.psh 的权限。
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": [ "appstream.amazonaws.com" ] }, "Action": "s3:GetObject", "Resource": "arn:aws:s3:::
amzn-s3-demo-bucket2/examplefile.psh
", "Condition": { "ArnEquals": { "aws:SourceArn": "arn:aws:appstream:us-east-1:111122223333
:fleet/ExampleFleetName
" } } } ] }
使用资源控制策略进行跨服务混淆代理保护
您可以使用资源控制策略(RCP)将跨服务的混淆代理控制应用于支持的 AWS 服务的资源。RCP 允许您对资源集中应用跨服务的混淆代理控制。您可以将条件键(如 aws:SourceOrgId
和 aws:SourceOrgPaths
)与附加到您的 AWS Organizations 的 RCP、组织单位(OU)或组织中的 AWS 账户一起使用,而无需在基于资源的特定策略中添加声明。有关 RCP 和支持的服务更多信息,请参阅《AWS Organizations 用户指南》中的资源控制策略(RCP)。
以下示例 RCP 拒绝 AWS 服务主体在 aws:SourceOrgID
不等于 o-ExampleOrg 时访问您的成员账户中的 Amazon S3 存储桶。Amazon S3 存储桶的基于资源的策略中必须存在相应的允许,才能允许具有 SourceOrgID 的 AWS 服务主体等于 o-ExampleOrg.S
此策略仅对存在 aws:SourceAccount
密钥("Null": {"aws:SourceAccount":
"false"}
)的服务主体("Bool":
{"aws:PrincipalIsAWSService": "true"}
)进行的请求应用控制,因此不需要使用此条件键的服务集成和主体的调用不会受到影响。如果 aws:SourceAccount
条件键存在于请求上下文中,则 Null 条件将评估为 true,从而强制执行 aws:SourceOrgID
。您可以在 Null 条件运算符中使用 aws:SourceAccount
代替 aws:SourceOrgID
,因此,如果请求来自不属于组织的账户,则控制仍然适用。
{ "Version": "2012-10-17", "Statement": [ { "Sid": "RCPEnforceConfusedDeputyProtectionForS3", "Effect": "Deny", "Principal": "*", "Action": [ "s3:*" ], "Resource": "*", "Condition": { "StringNotEqualsIfExists": { "aws:SourceOrgID": "
o-ExampleOrg
" }, "Null": { "aws:SourceAccount": "false" }, "Bool": { "aws:PrincipalIsAWSService": "true" } } } ] }