AWS CLI s3 复制失败并出现 403 错误,尝试管理用户上传的对象

AWS CLI s3 copy fails with 403 error, trying to administrate a user-uploaded object

正在尝试将文件从 S3 存储桶复制到我的本地计算机:

aws s3 cp s3://my-bucket-name/audio-0b7ea3d0-13ab-4c7c-ac66-1bec2e572c14.wav ./

fatal error: An error occurred (403) when calling the HeadObject operation: Forbidden 

我确认的事情:

存储桶策略旨在授予广泛开放的访问权限:

    {
        "Sid": "AdminAccess",
        "Effect": "Allow",
        "Principal": "*",
        "Action": [
            "s3:*"
        ],
        "Resource": [
            "arn:aws:s3:::my-bucket-name",
            "arn:aws:s3:::my-bucket-name/*"
        ]
    }

我是如何上传这个对象的?

我使用 AWS Signature v4 签名上传策略将此对象从客户端浏览器中的 Web 应用程序直接上传到 AWS。

即使出于安全原因文件不存在,AWS S3 也会 return 您禁止访问 (403)。 请确保您在下载时提供了正确的 s3 路径。

您可以阅读更多相关信息here

事实证明,查看对象属性,我可以看到对象的所有者是 "Anonymous," 并且 "Anonymous" 用户对该对象具有完全权限。

我相信这就是我无法访问此对象的原因(我已通过身份验证)。示例:由于 "Anonymous" 用户具有完全权限,我可以使用 Web 浏览器通过 GET 访问。这是按设计运行的。 S3 存储桶用于上传文件,然后可供 public 使用。

因此,当文件 POST 使用上传策略时,生成的所有者是 "Anonymous"。

在这种情况下,上传对象时应使用 acl=bucket-owner-full-control,以便存储桶拥有者可以控制该对象。 执行此操作后,所有者仍将是 "Anonymous",但是,它将授予存储桶所有者(我)完全权限,之后我应该能够通过 AWS CLI 访问该对象。

请注意,acl=ec2-bundle-read 是默认值,实际上已硬编码到最新的 AWS SDK 中。参见 https://github.com/aws/aws-sdk-java/blob/7844c64cf248aed889811bf2e871ad6b276a89ca/aws-java-sdk-ec2/src/main/java/com/amazonaws/services/ec2/util/S3UploadPolicy.java#L77

有必要将 S3UploadPolicy.java 复制到我自己的代码库中(它是一个完全可移植的小实用程序 class,事实证明)并在为了使用 acl=bucket-owner-full-control。而且我已经验证这提供了通过 AWS CLI 管理上传的对象。

我 运行 在尝试从 s3 下载我之前上传的内容时遇到了类似的权限问题。事实证明,它与 bucket 政策无关,而与上传时如何设置凭据以及上传时如何获得 运行t 访问权限有关.有关解决问题的几种方法的详细信息,请参阅

在我的例子中,当试图联系 S3 的机器系统时间与当前相差甚远时,出现了上述错误。设置正确的时间有帮助。

在我的例子中,我有 3 个帐户(A1A2A3)和 3 个规范用户(canonical_user_account_A1canonical_user_account_A2canonical_user_account_A3) 和 A3 中的 1 个 IAM 角色 (R1)。

文件在 A2 的存储桶中,文件所有者是 canonical_user_account_A1这是故意的)。当我尝试列出文件时,我没有收到任何错误,但是 当我尝试下载其中一个文件时,我得到了

fatal error: An error occurred (403) when calling the HeadObject operation: Forbidden

我在存储桶策略和角色权限中为 R1 添加了 ListGet 权限,在这种情况下,如果帐户是存储桶不是所有者,它不允许其他帐户的用户访问 get(下载)文件。所以我需要确保当我上传文件时我使用的是:

    access_control_policy = {
    'Grants': [
        {
            'Grantee': {
                'ID': canonical_user_account_A2,
                'Type': 'CanonicalUser'
            },
            'Permission': 'READ'
        },
        {
            'Grantee': {
                'ID': canonical_user_account_A3,
                'Type': 'CanonicalUser'
            },
            'Permission': 'READ'
        },
    ],
    'Owner': {
        'ID': canonical_user_account_A1
    }
}

upload_extra_args = {'ACL': 'bucket-owner-full-control'}

s3_client.upload_file(file_path, bucket_name, s3_file_path, ExtraArgs=upload_extra_args)

s3_client.put_object_acl(AccessControlPolicy=access_control_policy, Bucket=bucket_name, Key=s3_file_path)

这允许 canonical_user_account_A2canonical_user_account_A3 读取和下载文件。