亚马逊AWS官方博客

S3 跨账户访问与 ACL:解决存储桶访问受限问题

在 AWS 多账户环境中,跨账户访问 S3 存储桶是一个常见需求,尤其是在集中式日志管理、共享数据仓库等场景下。而当 S3 存储桶启用了访问控制列表(ACL)时,跨账户访问可能会遇到复杂的权限问题。本文将以一个真实的客户场景为例,深入探讨在存储桶所有者和对象所有者不同的情况下,如何解决 S3 存储桶的跨账号访问问题。

关于 S3 安全机制的一些概念介绍

AWS S3 提供了全面而精细的权限管理能力,让用户能够安全地控制对存储桶和对象的访问,比较常用的有以下 3 种:

  1. IAM 策略:这是一种基于身份的权限管理策略,需要将 IAM 策略附加到用户、组或者角色,来定义哪些身份可以对特定的 S3 资源执行哪些操作。
  2. 存储桶策略:这是一种基于资源的权限管理策略,需要在 S3 的存储桶策略中定义清楚谁可以对该存储桶及其中的对象执行哪些操作。
  3. ACL 方式:ACL 是与资源关联的一系列授权,定义了哪些 AWS 账户或预定义组有权访问资源以及允许的访问类型。

作为上一代的权限管理方式,ACL 无法支持非常精细的权限控制,也无法与亚马逊云科技的其他服务完美集成,现在已经不推荐使用了。至于是需要使用 IAM 策略,还是存储桶策略,您可以根据实际需求做选择,例如账号内同一身份需要多种资源的访问权限时,IAM 策略就比较合适;需要授予其他 AWS 账户访问您的存储桶时,存储桶策略就比较合适,当然也有复杂的场景可能需要二者结合使用。

当前的 Amazon S3 服务在新建存储桶时,我们会看到有一个关于 Object Ownership 的选项,默认和推荐选项是“ACLs Disabled”,然后使用存储桶策略或者 IAM 策略都可以实现灵活安全的权限管理能力。而上一代的权限管理方式,则主要是使用 ACL 实现的,它能够支持对象粒度的权限控制,但在跨账户场景下容易出现权限问题,当对象所有者与存储桶所有者不同时,存储桶拥有者可能无法控制其他账户上传的对象。本文就主要是为了解决这类 ACL 产生的历史遗留问题。

在 Amazon S3 中,存储桶所有者和对象所有者是两个不同的概念,特别在启用 ACL 的场景下,这种区别尤为重要:

存储桶所有者(Bucket Owner)

  • 创建 S3 存储桶的 AWS 账户
  • 负责支付存储桶的存储和数据传输费用
  • 可以配置存储桶级别的设置(策略、生命周期规则等)
  • 可以删除整个存储桶及其内容

对象所有者(Object Owner)

  • 上传对象到存储桶的 AWS 账户
  • 默认情况下拥有该对象的完全控制权
  • 可以设置对象级别的 ACL 权限
  • 可以删除或修改自己拥有的对象

ACL 场景下的关键挑战:

  1. 所有权分离:当其他 AWS 账户将对象上传到您的存储桶时,默认情况下他们成为对象所有者,而非存储桶所有者。
  2. 权限限制:存储桶所有者对其他账户上传的对象可能只有有限权限,通常只能列出和删除。
  3. 跨账户挑战:这种所有权分离在跨账户访问场景中尤为棘手,可能导致“可列出但无法下载”的情况。

而本次客户遇到的问题就是“可列出但无法下载”的情况。

客户案例分析

问题背景

我们的客户面临的正是典型的“可列出但无法下载”问题,涉及三个 AWS 账户:

  • Account A:在 EKS 集群上运行 Flink 应用的大数据引擎的账号,需要访问 CloudTrail Event 日志进行安全分析。
  • Account B:集中日志存储账户,S3 存储桶所在位置。
  • Account C:CloudTrail 服务账户,将日志写入 Account B 的 S3 存储桶 (客户实际场景中,有多个和 Account C 同样角色的 Account 需要将 CloudTrail 日志写入 Account B 的 S3 存储桶中,这里仅以 Account C 为代表进行说明)。

Account A 尝试下载 Account B 中的对象时,遇到了“可列出但无法下载”的情况,导致日志分析无法正常进行。

经确认,客户的 Account B S3 日志存储桶 Bucket Policy 中已有关于 Account A 跨账户访问的配置,且在 Account A 中为 EKS 服务角色添加了正确的 IAM 策略。

问题根源

经过分析,我们发现:

  1. Account B 中的 S3 存储桶创建于 2022 年,当时的存储桶默认启用了 ACL,对应与当前服务设计中的 Object writer。
  2. 存在所有权分离:S3 存储桶的所有者是 Account B,但对象由 Account C 的 CloudTrail 写入,因此对象所有者是 Account C。
  3. 虽然通过 Account B 的存储桶策略授予了 Account A 访问权限,但由于对象所有者是 Account C,Account A 仍然无法下载这些对象。

解决方案

针对这个问题,我们提供两种解决方案:

方案一:禁用 ACL(推荐)

前期准备

在禁用 ACL 之前,需要进行以下准备工作:

1. 识别依赖 ACL 的访问模式,首先在控制台上可以看到存储桶级别的 ACL

2. 然后确认对象级别的 ACL

  • 开启 S3 服务器访问日志
  • 分析日志中的 aclRequired 字段,该字段指示请求是否需要 ACL 进行授权
  • 如果值为”Yes”,表示有请求依赖 ACL;如果为”-“,则不依赖 ACL
  • 确认没有关键访问依赖 ACL 后,才能安全地禁用 ACL

3. 评估现有工作流程

  • 确认是否有应用程序依赖特定的 ACL 设置
  • 准备替代的存储桶策略,确保现有访问不受影响

实施步骤

在 Account B 中,修改对象所有权设置:

1. 登录 AWS 管理控制台,导航至 S3 服务

2. 选择目标存储桶,点击“权限”选项卡

3. 在“对象所有权”部分,选择“编辑”

4. 选择“ACL 已禁用”选项并保存更改

效果分析

  • 更改配置之前上传对象归属不发生变化,对象所有者依然是 Account C,更改配置之后上传的对象都会自动归属于存储桶所有者(Account B)。
  • 但是,Account B 可以通过存储桶策略授予 Account A 对于所有新老对象的访问权限(具体操作见存储桶策略与 IAM 配置详解)。

方案二:保持 ACL 启用,调整配置

如果由于某些原因无法禁用 ACL,可以采用以下方案:

1. 将对象所有权设置为“存储桶拥有者首选”(Bucket owner preferred)

2. 确保 CloudTrail 配置使用 bucket-owner-full-control ACL 上传对象(可参考:Amazon S3 bucket policy for CloudTrail – AWS CloudTrail),这样新上传的对象将由 Account B 拥有,可以通过存储桶策略授权给 Account A 进行下载(具体操作见存储桶策略与 IAM 配置详解)。

这里需要特别注意,在更改 ACL 配置前上传的对象,object owner 还是 Account C,且无法通过更新存储桶策略与 IAM 配置实现 Account A 的下载。

更改后上传的对象,object owner 是 Account B,可以通过更新存储桶策略与 IAM 配置实现 Account A 的下载。

存储桶策略与 IAM 配置详解

无论采用哪种方案,都需要正确配置存储桶策略和 IAM 权限:

1. 在 Account B 中配置 S3 存储桶策略

首先,需要在 Account B 中为 S3 存储桶添加策略,允许 Account A 中的 EKS 角色访问:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowCrossAccountAccess",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::ACCOUNT-A-ID:role/EKS-SERVICE-ROLE-NAME"
            },
            "Action": [
                "s3:GetObject",
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::BUCKET-NAME",
                "arn:aws:s3:::BUCKET-NAME/*"
            ]
        }
    ]
}

请替换:

  • ACCOUNT-A-ID:Account A 的 AWS 账户 ID
  • EKS-SERVICE-ROLE-NAME:EKS 服务角色的名称
  • BUCKET-NAME:Account B 中的 S3 存储桶名称

2. 在 Account A 中为 EKS 服务角色添加 IAM 策略

在 Account A 中,为 EKS 服务角色添加允许访问 Account B 中 S3 存储桶的策略:

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

3. 通过 AWS CLI 附加策略

aws iam put-role-policy --role-name EKS-SERVICE-ROLE-NAME --policy-name S3CrossAccountAccess --policy-document file://s3-cross-account-policy.json —profile account-a-profile

参数说明:

  • --role-name EKS-SERVICE-ROLE-NAME:指定要添加策略的 IAM 角色名称
  • --policy-name S3CrossAccountAccess:为内联策略指定名称
  • --policy-document file://s3-cross-account-policy.json:指定包含策略 JSON 的本地文件路径
  • --profile account-a-profile:指定使用哪个 AWS 配置文件的凭证,需要替换为您的 AWS 配置文件名称,如果使用默认配置文件,可以完全删除此参数

4. 验证权限

在 EKS Pod 中测试访问权限:

列出存储桶内容

aws s3 ls s3://BUCKET-NAME/

下载对象

aws s3 cp s3://BUCKET-NAME/path/to/object local-file

总结

S3 跨账户访问在启用 ACL 的环境中确实面临独特的权限挑战,尤其当对象所有者与存储桶所有者不同时。本文通过分析实际客户案例,为您揭示了“可列出但无法下载”问题的根本原因,并提供了清晰的解决路径。

我们详细阐述了两种有效的解决方案:禁用 ACL 或优化 ACL 配置,并提供了完整的存储桶策略和 IAM 配置指南。对于大多数现代应用场景,我们推荐采用禁用 ACL 的方案,这不仅符合 AWS 的最新最佳实践,还能显著简化权限管理并增强安全性。

值得一提的是,您也可以采用传统的 IAM policy 结合 assume role 的方式实现跨账号访问。由于 AWS 官方文档和其他博客已有详细介绍,本文不再赘述这一方法。通过合理选择和实施这些策略,您可以轻松克服 S3 跨账户访问中的权限障碍,构建更加高效、安全的多账户 AWS 环境。

本篇作者

戴逸洋

亚马逊云科技数据存储资深架构师,致力于推广存储技术在云上的各种最佳实践。

任田田

亚马逊云科技解决方案架构师,负责基于亚马逊云科技云计算方案架构的咨询和设计,推广亚马逊云科技云技术和各种解决方案。

王泽耀

亚马逊云科技解决方案架构师,面向国内大型企业品牌出海,致力于亚马逊云科技云服务在国内的应用及推广。曾就职于 IBM,服务国内不同行业企业客户。

张凯

亚马逊云科技解决方案架构师,主要负责基于亚马逊云科技的解决方案架构设计和方案咨询。具有多年的架构设计、项目管理经验。