S3 存储桶策略 - 隐式允许 GET

S3 Bucket Policy - GET Implicitly Allowed

当使用以下存储桶策略时,我看到它按预期限制了 PUT 访问 - 但是在创建的对象上允许 GET,即使没有任何东西应该允许此操作。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowPut",
            "Effect": "Allow",
            "Principal": {
                "AWS": "*"
            },
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::<BUCKET>/*",
            "Condition": {
                "IpAddress": {
                    "aws:SourceIp": [
                        "<IP ADDRESS>"
                    ]
                }
            }
        }
    ]
}

我可以使用 curl 将文件从 <IP ADDRESS> 放入 <BUCKET>,如下所示:

curl https://<BUCKET>.s3-<REGION>.amazonaws.com/ --upload-file test.txt

文件上传成功,并出现在S3控制台中。由于某种原因,我现在能够从互联网上的任何地方获取文件。

curl https://<BUCKET>.s3-<REGION>.amazonaws.com/test.txt -XGET

这仅适用于使用上述方法上传的文件。在 S3 Web 控制台中上传文件时,我无法使用 curl 获取它(访问被拒绝)。所以我假设这是一个对象级别的权限问题。虽然我不明白为什么存储桶策略不会隐式拒绝此访问。

在控制台中查看对象级别权限时,通过控制台上传的文件(方法 1)与从允许的 <IP ADDRESS>(方法 2)上传的文件之间的唯一区别是文件方法 2 中没有 'Owner'、权限或元数据 - 而方法 1 文件具有所有这些。

此外 - 当尝试使用 Lambda 脚本 (boto3 download_file()) 获取对象时,该脚本承担了对存储桶具有完全访问权限的角色,对于使用方法 2 上传的对象,它失败了。尽管对于对象成功了使用方法 1 上传。

问题总结

问题总结:

  • 您的策略允许从给定源 IP 地址匿名上传对象
  • 这些对象将无法被您的经过身份验证的用户读取(特别是您的 lambda 函数采用的 Iam 角色)
  • 未经身份验证的用户可以从任何 IP 读取这些对象

其他观察结果

  • 未经身份验证的用户无法删除对象

期望的结果是:

  • 未经身份验证的用户可以从已知 IP 地址上传对象
  • 未经身份验证的用户无法从任何 IP 地址下载对象
  • 对象可由经过身份验证的 Iam 用户检索

根本原因

这是正在发生的事情:

  1. 匿名用户上传对象

    1. 匿名用户成为对象所有者
    2. 可通过检索对象 acl 进行验证(使用查询字符串 ?acl 对对象执行 GET 请求)- 您将收到:

      <?xml version="1.0" encoding="UTF-8"?>
      <AccessControlPolicy xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
          <Owner>
              <ID>65a011a29cdf8ec533ec3d1ccaae921c</ID>
          </Owner>
          <AccessControlList>
              <Grant>
                  <Grantee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="CanonicalUser"><ID>65a011a29cdf8ec533ec3d1ccaae921c</ID></Grantee>
                  <Permission>FULL_CONTROL</Permission>
              </Grant>
          </AccessControlList>
      </AccessControlPolicy>
      

      Owner ID 是匿名用户的通用 ID - 我在一些 AWS 论坛讨论中看到引用了相同的 ID。

  2. 成为对象所有者具有以下影响:
    1. 匿名用户有 FULL_CONTROL(见上面的 acl)
    2. 匿名用户无法删除 - 这似乎是无法更改的 AWS 一揽子规则 - 永远不允许匿名用户删除任何内容,即使他们有 FULL_CONTROL
    3. 但是,由于 FULL_CONTROL
    4. ,匿名用户能够在现有对象之上放置一个空对象
  3. 当存储桶包含不属于存储桶帐户的用户所拥有的对象时:
    1. 存储桶拥有者对该对象没有权限(未在 acl 中引用)
    2. 桶拥有者无法读取对象
    3. 由于存储桶 acl,存储桶拥有者能够在存储桶列表操作中看到对象
    4. 存储桶所有者 能够删除对象 - 这是一条无法更改的总括规则 - 作为买单的人,您始终保留删除对象的权利- 即使你看不懂

分辨率

有一种方法可以实现您想要的结果 - 不幸的是,您必须引用您希望能够读取存储桶 acl 中的对象的特定 Iam 实体(用户、角色、组)的 arn。

解决方案的关键要素是:

  • 要求匿名用户授予存储桶拥有者完全访问权限
    • 这确保存储桶所有者和所有者帐户 Iam 用户不会被对象 acl 拒绝访问
  • 明确拒绝非您指定的所有用户的所有非 PUT 访问 user/role
    • 这确保匿名用户无法读取对象

示例策略:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "allow-anonymous-put",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::<BUCKETNAME>/*",
            "Condition": {
                "IpAddress": {
                    "aws:SourceIp": "<IPADDRESS>"
                },
                "StringEquals": {
                    "s3:x-amz-acl": "bucket-owner-full-control"
                }
            }

        },
        {
            "Sid": "deny-not-my-user-everything-else",
            "Effect": "Deny",
            "NotPrincipal": {
                "AWS": "arn:aws:iam::<ACCOUNTNUMBER>:role/<ROLENAME>"
            },
            "NotAction": [
                "s3:PutObject",
                "s3:PutObjectAcl"
            ],
            "Resource": "arn:aws:s3:::<BUCKETNAME>/*"
        }
    ]
}

第二个语句的关键是NotPrincipalNotAction的使用。

我已经在本地对此进行了测试,但仅在授予常规 Iam 用户访问权限的情况下,而不是在担任角色的 Lamba 函数的情况下 - 但主体应该持有。祝你好运!

以下文章有助于理解正在发生的事情 - 它们各自呈现了一个与您的相似但不完全相同的场景,但是他们用来解决场景的方法引领了潮流: