使用 S3 服务器访问日志和 亚马逊云科技 CloudTrail 中的信息禁用现有 Amazon S3 工作负载的 ACL

访问控制列表 (ACL) 是权限集,用于定义用户访问权限以及用户可以对特定资源执行的操作。 亚马逊 S3 于 2006 年推出,将 ACL 作为其首个授权机制。自 2011 年以来,Amazon S3 还支持用于 管理 S3 存储桶访问权限的 A WS 身份和访问管理 (IAM) 策略,并建议使用策略代替 ACL。尽管 S3 继续完全支持 ACL,但大多数用例不再需要它们。

2021 年,我们推出了 S3 对象所有权 ,它允许客户完全禁用 S3 存储桶的 ACL,并完全依赖策略进行访问控制。禁用 ACL 是 S3 安全最佳实践, 2023 年 4 月,我们默认禁用了所有新存储分区的 ACL 。 但是,对于现有工作负载,客户告诉我们,在切换到策略之前,他们需要了解其 ACL 的使用情况。他们希望确保此更改不会删除所需的权限,从而干扰他们的应用程序。

为了帮助您禁用 ACL,我们 在 S3 服务器访问日志 和 亚马逊云科技 CloudTrail 中添加了信息,以便您可以查看依赖于 ACL 访问 S3 中对象的请求。在这篇博客文章中,我们将展示如何使用这些信息自信地禁用 ACL。按照这些步骤,您将能够利用策略为管理资源访问提供的更高的可扩展性和灵活性。将特定对象的权限整合到一个策略中比多个 ACL 更易于审计和更新,尤其是在大规模时。

解决方案演练

以下是我们将在此博客文章中介绍的内容的简要概述:

  1. 为您的存储桶启用日志记录
  2. 使用 Amazon Athena 查询日志并识别依赖于 ACL 的 S3 请求
  3. 将 ACL 权限迁移到存储桶策略权限
  4. 验证您是否准备好禁用 ACL
  5. 禁用 ACL

我们将使用 亚马逊云科技 CloudTrail 演示步骤 1 和步骤 2,但您也可以启用和查询 S3 服务器访问日志,然后在这篇博客文章中继续执行步骤 3-5。

步骤 1:为您的存储桶启用日志记录

首先,您必须为存储桶启用 亚马逊云科技 CloudTrail 数据事件并创建亚马逊 Athena 表。如果您已经为存储桶启用了 CloudTrail 并创建了 Athena 表,则可以继续执行 步骤 2:使用 Amazon Athena 查询 日志。 否则,请完成以下步骤:

  1. 启用 亚马逊云科技 CloudTrail 数据事件
  2. 创建亚马逊 Athena 桌子

在继续执行以下步骤之前,您需要等待一段时间,具体取决于您的工作负载,以便记录您为 CloudTrail 配置的 S3 存储桶的数据事件。例如,如果您每天和每周都有工作负载访问存储桶中的数据,则可能需要等待至少一周才能收集所有访问模式。

如果您使用的是 S3 服务器访问日志,请参阅 有关 启用 S3 服务器访问日志的文档 。

第 2 步:使用 Amazon Athena 查询日志并识别依赖于 ACL 的 S3 请求

在本步骤中,我们将介绍如何在 亚马逊云科技 Cloudtrail 中记录与 ACL 相关的请求,以及如何使用 Amazon Athena 查询日志。

如何在 亚马逊云科技 CloudTrail 中记录依赖于 ACL 的请求

Amazon S3 服务器访问日志和 亚马逊云科技 CloudTrail 中新增的 ACL Require d 字段为您提供了每个 S3 请求的信息,以表明该请求是否需要 ACL 才能获得授权。在 亚马逊云科技 CloudTrail 中,它的值要么是 “是”,要么不是。此字段的目的是向您显示哪些请求需要修改存储桶策略或请求,然后才能禁用 ACL。以下是一些示例:

示例 1: 账户 222 向 111 拥有的对象发出的跨账户请求,其中存在允许访问 222 的 ACL。

如果没有允许访问账户 222 的存储桶策略声明,则请求将取决于 ACL 才能成功, ACL Required 为 “ 是” 。 以下是此示例的 亚马逊云科技 CloudTrail 日志示例。

"userIdentity": {
    "accountId": "222",
},
"eventTime": "2022-11-17T19:46:01Z",
"eventName": "GetObject",
"resources": [
  {
    "type": "AWS::S3::Object",
    "ARN": "arn:aws:s3:::DOC-EXAMPLE-BUCKET/example-object"
  },
  {
    "accountId": "111",
    "type": "AWS::S3::Bucket",
    "ARN": "arn:aws:s3:::DOC-EXAMPLE-BUCKET"
  }
],
...
"additionalEventData": {
  "aclRequired": "Yes"
}

如果存储桶策略确实允许访问账户 222,则删除 ACL 不会中断访问,并且 ACLrequired 不存在。

示例 2: 同账户请求(对象所有者和调用者位于同一 亚马逊云科技 账户中)

对于同账户读取操作(例如 Get、List),不使用 ACL 进行授权,因此没有 ACL Required。以下是此示例的 亚马逊云科技 CloudTrail 日志示例。

"userIdentity": {
    "accountId": "111",
},
"eventTime": "2022-11-17T19:46:01Z",
"eventName": "GetObject",
"resources": [
    {
        "type": "AWS::S3::Object",
        "ARN": "arn:aws:s3:::DOC-EXAMPLE-BUCKET/example-object"
    },
    {
        "accountId": "111",
        "type": "AWS::S3::Bucket",
        "ARN": "arn:aws:s3:::DOC-EXAMPLE-BUCKET"
    }
],
...

示例 3: 在对象上设置 ACL 的 同账户请求

对于未设置 ACL 或未设置存储桶所有者完全控制 ACL 的同账户 PUT,则不存在 ACLRequired。

在对象上设置 ACL 的所有其他 PUT 请求(例如 putobjectACL)都将显示 acl Required 为 “是”。 以下是此示例的 亚马逊云科技 CloudTrail 日志示例。

"userIdentity": {
    "accountId": "222",
},
"eventTime": "2022-11-17T19:46:01Z",
"eventName": "PutObjectACL",
"requestParameters": {
  "ObjectCannedACL": "BucketOwnerFullControl",
},
"resources": [
  {
    "type": "AWS::S3::Object",
    "ARN": "arn:aws:s3:::DOC-EXAMPLE-BUCKET/example-object"
  },
  {
    "accountId": "222",
    "type": "AWS::S3::Bucket",
    "ARN": "arn:aws:s3:::DOC-EXAMPLE-BUCKET"
  }
],
...
"additionalEventData": {
  "aclRequired": "Yes"
}

此字段中标有 “是” 的请求表示在禁用 ACL 之前您需要在哪里采取其他操作。接下来,我们将展示如何查询日志以识别这些请求。要更详细地了解操作与 CloudTrail 或服务器访问日志中的预期 ACL Required 值之间的映射,请参阅 此访问控制列表 (ACL) 概述 。

使用雅典娜查询 CloudTrail 日志

等待 CloudTrail 中记录数据事件后,您可以运行以下查询,查找您选择的时间段内所有与 ACL 相关的 S3 请求。如果您经常访问数据,我们建议您首先选择较短的时间段(例如几个小时)来测试此查询,以获取样本。在以下示例中,我们使用了 3 天的时间段,但您应该修改查询以适应至少一次将应用程序的所有工作负载捕获到存储桶的时间范围。此查询生成相关信息,例如事件名称、事件数量、请求者账户 ID 和存储桶名称。它仅检索从您启用存储桶登录时起以及在所有区域启动 ACL Require d 字段之后的信息(23 年 2 月 15 日)。

SELECT 
   eventName,
   COUNT(*) AS eventCount,
   userIdentity.accountId, 
   json_extract_scalar(requestParameters, '$.bucketName') as bucketName 
 FROM cloudtrail_table
 WHERE 
   json_extract_scalar(additionalEventData, '$.aclRequired') = 'Yes' 
   AND eventTime > to_iso8601(current_date - interval '3' day)
   AND errorCode IS NULL
GROUP BY 
   userIdentity.accountId, 
   eventName, 
   json_extract_scalar(requestParameters, '$.bucketName') 
ORDER BY userIdentity.accountId;

如果您想查看特定时间段内的 S3 请求,可以使用以下示例查询。

SELECT 
   eventName,
   COUNT(*) AS eventCount,
   userIdentity.accountId, 
   json_extract_scalar(requestParameters, '$.bucketName') as bucketName 
 FROM cloudtrail_table 
 WHERE 
   json_extract_scalar(additionalEventData, '$.aclRequired') = 'Yes' 
   AND eventTime > '2023-02-15T00:00:00Z' AND eventTime < '2023-02-18T00:00:00Z'
   AND errorCode IS NULL
GROUP BY 
   userIdentity.accountId, 
   eventname, 
   json_extract_scalar(requestParameters, '$.bucketName') 
ORDER BY userIdentity.accountId;

以下是此查询的示例输出:

Console Screenshot of athena query results

此查询的输出表明,来自账户 111122223333 的 putObject、getObject 和 ListBucket 请求依赖于 ACL 才能成功。为了能够遵循禁用 ACL 这一安全最佳实践,我们需要在存储桶策略中允许这些用户访问权限,并验证不再对请求设置 ACL,我们将在 步骤 3:将 ACL 权限迁移到存储桶策略 和 步骤 4:验证您是否准备好禁用 ACL 中会这样做。

你可能会从这个查询中得到一个空结果。这意味着,在这段时间内,如果禁用 ACL,任何请求都不会被拒绝。如果您的查询为空,则可以在不同的时间段内验证这是真的,或者继续执行 步骤 5:禁用 ACL。

使用 Athena 查询 S3 服务器访问日志

如果您已为存储桶启用服务器访问日志,请参阅 使用 Amazon S3 访问日志识别 对等效 Athena 查询的请求 。

步骤 3:将 ACL 权限迁移到存储桶策略

使用 Athena 查询的输出,我们现在可以编写存储桶策略声明,使这些 ACL 不再需要授权。

在步骤 2 中,我们确定了账户 111122223333 对存储桶 “DOC-EXAMPLE-BUCKET” 进行的三项操作 putObject、getObject 和 ListBucket。 这些操作必须转换为存储桶策略的 操作 元素中的操作,并指定相应的 资源 , 如以下存储桶策略所示:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "111122223333"
            },
            "Action": [
                "s3:GetObject",
                "s3:PutObject",
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::DOC-EXAMPLE-BUCKET/*",
                "arn:aws:s3:::DOC-EXAMPLE-BUCKET"
            ]
        }
    ]
}

为了编写此政策,我们将查询结果中的每项操作映射到相应的 IAM 操作和资源。下表列出了一些常见的 S3 操作及其等效的存储桶策略操作和资源类型。要更详细地了解操作与存储桶策略操作和资源之间的映射,请参阅有关 亚马逊云科技 服务的 操作、资源和条件键的文档。

Operation name in 亚马逊云科技 CloudTrail Operation name in Amazon S3 server access logs Bucket policy action Bucket policy resource type
GetObject REST.GET.OBJECT s3:GetObject Object
PutObject REST.PUT.OBJECT s3:PutObject or n/a Object or n/a
ListObjects REST.GET.BUCKET s3:ListBucket Bucket
DeleteObject REST.DELETE.OBJECT s3:DeleteObject Object
PutObjectACL REST.PUT.ACL n/a n/a
PutBucketACL REST.PUT.ACL n/a n/a

注意:具有 n/a 存储桶策略操作的操作必须停止设置 ACL。参见步骤 4。

通过此存储桶策略,我们向账户 111122223333 授予了对存储桶中所有对象的访问权限。虽然这涵盖了我们已知的访问模式,但如果你知道账户 111122223333 实际上只需要访问 样本前缀/* 下的数据,你可以写一份更具体的政策声明 ,只允许访问特定的前缀。有关上述 存储桶策略 声明的细化示例,请参阅存储桶策略示例。

步骤 4:验证您是否准备好禁用 ACL

禁用 ACL 后,所有 PutBucketAcl 和 PutObjectACL 以及设置的访问控制权限不是存储桶所有者完全控制 ACL 的 API 都将失败并出现 400 个错误。为了解决这个问题,必须删除所有 PutBucketACL 和 PutobJectACL 请求,所有其他指定 ACL 的 API 都应从请求中删除 ACL 参数。以下是这些更改的示例。

// Removing custom ACL from PutObject Request
final PutObjectRequest putObjectRequest = PutObjectRequest.builder()
        .bucket(bucketName)
        .key(objectName)
        .grantRead(aclString)
        .build();
// Removing canned ACL from PutObject Request
final PutObjectRequest putObjectRequest = PutObjectRequest.builder()
        .bucket(bucketName)
        .key(objectName)
        .acl(aclString)
        .build();

验证是否不再需要 ACL

对存储桶策略以及需要时对客户端应用程序进行了必要的更改后,您应该等待一段时间以允许记录后续请求。就像 步骤 1:为存储桶启用日志记录 一样 ,等待此分析的适当时间可能是几天或几周,具体取决于您的工作负载。接下来,您可以使用查询来重新评估日志,例如下面的查询,该查询自更新以来会查询日志,以确保您现在没有依赖于 ACL 的工作负载。如果查询从应用存储桶策略之日起返回零结果,则可以在不中断现有工作负载的情况下禁用 ACL。

SELECT 
   eventName,
   COUNT(*) AS eventCount,
   userIdentity.accountId, 
   json_extract_scalar(requestParameters, '$.bucketName') as bucketName 
 FROM cloudtrail_table
 WHERE 
   json_extract_scalar(additionalEventData, '$.aclRequired') = 'Yes' 
   AND eventTime > '2023-02-15T00:00:00Z'
GROUP BY 
   userIdentity.accountId, 
   eventName, 
   json_extract_scalar(requestParameters, '$.bucketName') 
ORDER BY userIdentity.accountId;

Query to view results

putObject、getObject 和 ListObjects 操作不再出现在查询结果中,这验证了存储桶策略是否允许这些权限,请求未设置 ACL。如果您看到任何结果,则必须添加存储桶策略未考虑的其他与 ACL 相关的请求,否则仍在设置 ACL。如果是这种情况,请重复 步骤 3:将 ACL 权限迁移到存储桶策略 和 步骤 4:验证您是否准备好禁用 ACL 。

步骤 5:禁用 ACL

现在,依赖于 ACL 的权限已添加到您的存储桶策略中,并且您的日志中不再有表明需要 ACL 的请求,您可以放心地在 S3 存储桶上禁用 ACL,确保不会中断现有工作负载。

要禁用存储桶及其中的对象的 ACL,您首先需要删除所有现有的存储桶 ACL。您可以通过在 S3 控制台中转到存储桶的详细信息页面来执行此操作。在 权限 选项卡中,编辑 访问控制列表 (ACL) 以删除除您自己(存储桶所有者)之外的所有被授权者的存储桶 ACL。请勿更改对象 ACL。

删除所有存储桶 ACL 后(保留在 “ 权限 ” 选项卡中),您可以通过编辑 对象所有权 并将其设置为禁用 ACL 来禁用存储分区上的 AC L。 此步骤是可逆的,因此,如果您出于任何原因需要重新启用 ACL,则会立即恢复之前使用的对象 ACL。

console screenshot edit object ownership with ACLs disabled selected

现在,您已成功将依赖于 ACL 的请求的权限迁移到存储桶策略,并在存储桶上禁用了 ACL!展望未来,对数据的访问将基于策略,包括 S3 存储桶策略和 IAM 策略。

正在清理

总结一下,在清理过程中完成以下可选步骤:

  1. 禁用 亚马逊云科技 CloudTrail 数据事件和/或 Amazon S3 服务器访问日志。如果您不需要登录存储桶,则建议使用此方法。
  2. 删除相应的 Amazon Athena 表,除非您想将其保留以备将来参考。

大多数客户可以在这里停下来。如果出于任何原因您不想禁用 ACL,例如您只是在运行测试,则可以完成以下步骤来重新启用 ACL:

  1. 通过将 对象所有权 编辑为 启用的 ACL 并恢复存储桶策略的删除 ,恢复在存储桶的 权限 选项卡中所做的更改。
  2. 恢复对设置 ACL 的 API 的删除。
  3. 恢复对存储桶策略所做的更改。

结论

在这篇博客中,我们演示了如何使用 Amazon S3 服务器访问日志和 亚马逊云科技 CloudTrail 中的新 ACLRequired 字段来识别依赖 ACL 来访问数据的现有应用程序或访问模式。这篇文章中介绍的方法将允许您放心地将这些依赖于 ACL 的权限迁移到等效的存储桶策略,从而允许您禁用 ACL。

我们推荐的另一种最佳做法是启用 “阻止公共访问”。此功能允许您限制对 S3 存储桶的公共访问。有关 BPA 的更多信息,请参阅 阻止公众访问您的 Amazon S3 存储 。

感谢您阅读这篇博客文章。如果您有任何意见或疑问,请随时在评论部分发表评论。

其他资源

  • 注意:Amazon S3 安全变更将于 2023 年 4 月发布 (默认启用 S3 区块公共访问权限,默认情况下,新 存储桶禁用 ACL)
  • 新增 — 简化 Amazon S3 中存储数据的访问管理 (S3 对象所有权可禁用 ACL)
Iris Sheu

Iris Sheu

Iris 是亚马逊网络服务的产品经理。她喜欢科技、人和商业的交汇点。周末,你可以看到她在探索农贸市场,边听播客边跑步,练习书法。

Daniyal Khan

Daniyal Khan

Daniyal 是亚马逊 Simple Storage Service(亚马逊 S3)的软件开发工程师。他热衷于构建技术解决方案以改善客户体验。在业余时间,他喜欢运动和烹饪。

Mohammad Khalaf

穆罕默德·哈拉夫·

穆罕默德是一名开发亚马逊 S3 的软件开发工程师。他喜欢在全球范围内为 S3 用户构建解决方案的快感。在空闲时间,他喜欢步行、骑自行车和乘飞机环游世界。

Subhojoy Dey

Subhojoy Dey

Subhojoy 是亚马逊 S3 的系统开发工程师。他喜欢构建和学习新事物,并利用这些知识来设计解决方案,让客户的生活更轻松。在业余时间,他喜欢弹吉他和摇腿。

Teddy Franceschi

泰迪·弗朗切斯基

·泰迪是一名开发亚马逊 S3 的软件开发工程师。他喜欢开发S3规模的非常规解决方案。当不在电脑前时,他喜欢背包旅行、公路旅行和阅读。


*前述特定亚马逊云科技生成式人工智能相关的服务仅在亚马逊云科技海外区域可用,亚马逊云科技中国仅为帮助您发展海外业务和/或了解行业前沿技术选择推荐该服务。