发布于: Jul 29, 2022

在 Amazon IAM 服务发布后,S3 ACL 权限管理机制逐渐与 IAM 服务进行了映射和融合,形成了今天的两种访问控制功能并行的状态

 

Amazon S3 ACL(Bucket ACL/Object ACL)属于旧有的 Amazon S3 访问控制机制,随着 Amazon S3 服务的诞生而诞生。在 Amazon IAM 服务发布后,S3 ACL 权限管理机制逐渐与 IAM 服务进行了映射和融合,形成了今天的两种访问控制功能并行的状态。

其中,Bucket ACL 功能适用的场景很少,在此不做赘述。典型场景比如为本账号中负责存储 S3 Server Access Log 的 S3 存储桶设置 Bucket ACL 以允许 S3 LogDelivery 服务来写入日志。

Object ACL 与 Bucket Policy 功能似乎类似,都可以实现对 S3 文件的权限管控。那么两者有什么不同,又应该如何选择?

对于绝大多数场景来说,S3 存储桶的拥有者(Bucket Owner)也是存储桶里文件的拥有者(Object Owner)。在这种情况下,推荐采用 Bucket Policy 来管理访问权限, 而无需考虑 ACL 设置。主要的原因是 Object ACL 所赋予权限的对象是 Amazon Web Services - Canonical - ID,该 ID 对应的是某个 Amazon Web Services 账号,可以理解为 Object ACL 所赋权的主体是单个 Amazon Web Services 账号;而 Bucket Policy 采用的是 IAM 授权机制,赋权的主体可以细化到单个 Amazon Web Services 账号的单个 IAM 实体,且支持大量针对请求上下文信息的权限管控(source IP,tag,访问协议等),相比 Object ACL 来说,Bucket Policy 实现的访问控制场景更灵活。不过,Object ACL 可以针对单个文件设置访问权限,对于某些罕见的场景下,比如存在大量跨账号访问的权限要求都不一样的文件,使用 Bucket Policy 对各个文件单独赋权变得难以操作(Bucket Policy 会冗长而难以管理),则可以考虑使用 Object ACL。

值得再次强调的是,我们在谈到 Bucket Owner 和 Object Owner 时,两者都指的是 Amazon Web Services 账号,而不是 IAM 实体,这一点对于理解 ACL 的概念很重要。可以简单的认为,ACL 机制所规范的主体对象是 Amazon Web Services 账号,而 IAM 机制所规范的主体对象是 IAM 实体(user, role等)。Amazon S3 在设计上是允许 Bucket Owner 和 Object Owner 是不同的 Amazon Web Services 账号,这也是自 2006 年以来 S3 沿用至今的一种机制。Bucket Owner 可以赋予 Object Owner 写入、读取桶的权限(无论是通过早期的 ACL 机制,还是通过现在的 IAM 跨账号赋权机制)。在默认情况下,Object Owner 上传文件后,Bucket Owner 对该文件是无读写权限的,除非 Object Owner 在上传时明确赋予了 Bucket Owner 相应的权限。

以下的例子说明了一种真实场景:公司 A 提供某种平台服务,允许业内众多公司采用自己的 Amazon Web Services 账号上传文件到公司 A 的 S3 存储桶中,同时上传后的文件的权限仍由上传者账号来管理。在这种情况下,某个上传文件的公司 B 使用 Object ACL 来管理文件权限是比较恰当的选择。而从公司 A 的角度,采用 Bucket Policy 由于只能管控到自己所拥有的文件,默认是管不到桶里由其他 Amazon Web Services 账号 Own 的文件权限的(这里的‘管不到’更多指的是读写权限,其实 Bucket Owner 可以编写 Bucket Policy 来拒绝外部对存储桶中任何对象的访问,也可以删除存储桶内的任何对象,无论这些对象是否属于他。这里的设计逻辑是,由于账单由存储桶拥有者来支付,为了保障自己的利益,存储桶拥有者需要有这样的权限)。当然,公司 B 也可以选择将 full control 权限赋予 Bucket Owner(公司 A),使得公司 A 不仅能够访问文件,而且能够管理文件的权限。具体来说,公司 B 可在调用 S3 PutObject API 写入文件时指定 ‘x-amz-acl’ 字段为 ‘bucket-owner-full-control’ 的方式来操作。

而如果站在 bucket owner 的角度,希望强制 Object Owner 在上传文件时赋予自己完全控制权限,否则不允许文件上传,则可以通过以下方式来实现:利用 Bucket Policy 中的 Condition 字段来给某个文件上传者设置相应的限制条件,

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "statement1",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::AccountB-ID:user/bob"
      },
      "Action": "s3:PutObject",
      "Resource": "arn:aws:s3:::awsexamplebucket1/*",
      "Condition": {
        "StringEquals": {
          "s3:x-amz-grant-full-control": "id=AccountA-CanonicalUserID"
        }
      }
    }
  ]
}

在现代架构设计中,往往由 Bucket Owner 统一管理权限的设计更常见,典型场景比如企业数据湖核心的 S3 权限管理。在数据湖架构中,来自于不同 Amazon Web Services 账号、不同应用、不同形态的生产数据会通过不同的数据注入技术传入 S3 存储桶,在数据注入的过程中,其权限控制往往交由数据湖账号来统一管理,以便最终结合 Bucket Policy、IAM Policy、Lake Formation 服务、应用层认证授权等机制形成多层级的数据湖访问控制,实现企业对数据保护和访问控制的需求。如本节上面内容所揭示的,在跨账号的数据注入过程中有两种方式可以实现 S3 数据湖账号对数据文件拥有完全控制权限:

  1. 使用跨账号的 IAM 实体来写入文件,文件写入者需要在请求中指定 ‘x-amz-acl’ 字段为 ‘bucket-owner-full-control’。同时存储桶的 S3 Object Ownership 需设置为 ‘Bucket Owner Preferred’。当然,为了让跨账号 IAM 实体具有写入权限,需要在 IAM Policy 及 S3 Bucket Policy 层面同时确保显式的允许。
  2. 跨账号 IAM 实体可通过 assumerole 的方式获取存储桶所在账号下的某个 role 的权限(具备写入本账号下存储桶的权限),利用该 role 的权限完成数据的写入。同样,这个操作的前提是两方分别给予了对方 assumerole/被对方 assume 的权限。关于这个场景的详细配置,我将在第二篇博客中为读者提供示例。

随着 Amazon S3 服务的日益普及和用户使用上的深入,很多客户发现,对于某些共享访问的 S3 存储桶,单纯使用 Bucket Policy 来进行资源侧的权限控制变得越来越难。例如某一个 S3 存储桶存有企业各部门的共享数据,前端十几个应用都需要访问该存储桶的数据,需要确保每个应用具有不同 prefix 不同条件的读写权限,如果仅采用一套冗长的 Bucket Policy 来管理,一旦新增应用或者涉及到现有应用权限的变更,很难保证 Bucket Policy 能被正确的配置,以及确认更改后的策略是否对其他应用造成影响。而且存储桶策略也面临总大小不能超过 20KB 的限制等。

在这种情况下,引入 S3 接入点可以为客户提供很好的权限控制结构,就像将原来粗放式的大水管改造成一个个水龙头,每个水龙头对应一家用户(需要访问该 S3 桶的应用),可以对每个水龙头施加不一样的管控策略,而不影响到其他水龙头。类似的,您可以针对每个 S3 接入点设置不同的 IAM Policy(甚至限制请求来自于哪个网络),当用户、应用通过该接入点访问 S3 存储桶的数据时,会受到接入点的 IAM policy 的管控,同时也会受到 S3 存储桶的 bucket policy 的管控。所以应用 S3 接入点的一种最佳实践是,在 Bucket Policy 层面,对所有 IAM 实体放开权限,仅仅实现‘必须通过 S3 接入点的请求才被允许’,而将具体的权限管控策略部署在每个接入点上。以下展示了一个示例 Bucket Policy 的写法,可以实现上述这一点:

{
    "Version": "2012-10-17",
    "Statement" : [
    {
        "Effect": "Allow",
        "Principal" : { "AWS": "*" },
        "Action" : "*",
        "Resource" : [ "arn:aws-cn:s3:::somebucket", " arn:aws-cn:s3:::somebucket/*"],
        "Condition": {
            "StringEquals" : { "s3:DataAccessPointAccount" : "123123123123" }
        }
    }
  ]
}

相应地,在某个接入点侧可以附加如下示例的 IAM Policy 做实际的权限控制:

{
    "Version":"2012-10-17",
    "Statement": [
    {
        "Effect": "Allow",
        "Principal": {
            "AWS": "arn:aws:iam::123123123123:user/Bob"
        },
        "Action": ["s3:GetObject", "s3:PutObject"],
        "Resource": "arn:aws-cn:s3:cn-north-1: 123123123123:accesspoint/my-access-point/Bob/*"
    }
  ]
}

这样最终实现的效果是,IAM user Bob 只能通过访问 my-access-point 的访问点才能读取和写入自己的 prefix 下的文件,直接访问存储桶的请求则会被 Bucket Policy 拒绝。

相关文章