【问题标题】:How to test if S3 object does not exist AWS PHP SDK (Version 3)?如何测试 S3 对象是否不存在 AWS PHP SDK(版本 3)?
【发布时间】:2021-04-15 05:23:16
【问题描述】:

我为AWS SDK in PHP 编写了一个集成,用于发送S3 存储桶上文件的密钥并检索预签名的url,它或多或少地遵循this example。这工作得很好,除了我现在需要检查文件是否存在于 s3 上,如果不存在则返回空字符串。

我正在使用下面的代码执行此操作:

<?php

public function getUrl($key, $region, $version, $fileBucket): string
{
    $this->s3Client = new Aws\S3\S3Client([
        'region' => $region,
        'version' => $version,
    ]);

    if ($this->s3Client->doesObjectExist($fileBucket, $key) === false) {
       return '';
    }

    $cmd = $this->s3Client->getCommand('GetObject', [
        'Bucket' => $fileBucket,
        'Key' => $key
    ]);

    $request = $this->s3Client->createPresignedRequest($cmd, $preSignedExpiration);

    $preSignedUrl = (string) $request->getUri();

    return $preSignedUrl ?? '';
}

我的代码完美地返回了预签名的 url,直到我添加了 if 语句来检查方法 doesObjectExist()。 doesObjectExist() 为我在 S3 上的所有对象返回 false,而不仅仅是 S3 存储桶中不存在 $key 的对象。这样就排除了 S3 密钥、存储桶或 api 密钥无效,这是 answer I have come across 主要研究这个问题。

此外,如果您碰巧知道使用 $cmd 或 $request 中返回的内容来执行此操作的更好方法,而无需调用 dosObjectExist()(如果可能的话),这将简化我的代码。

编辑:

我通过其访问 AWS S3 API 的 IAM 用户的策略如下所示:

{    
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:GetObject",
                "s3:ListBucket",
                "s3:DeleteObject"
            ],
            "Resource": [
                "arn:aws:s3:::example-dev-us-east-1-111111111111",
                "arn:aws:s3:::example-dev-us-east-1-111111111111/*"
            ]
        }
    ]
}

s3 Bucket 策略如下所示:

       {
        "Sid": "dev-web-app-get-policy",
        "Effect": "Allow",
        "Principal": {
            "AWS": "arn:aws:iam::2222222222:role/example-dev-us-east-1-111111111111"
        },
        "Action": [
            "s3:GetObject",
            "s3:DeleteObject",
            "s3:ListBucket"
        ],
        "Resource": [
            "arn:aws:s3:::example-dev-us-east-1-111111111111",
            "arn:aws:s3:::example-dev-us-east-1-111111111111/*"
        ]
    }

看来我应该能够访问所需的资源。为了安全起见,我列出了虚假的存储桶名称。但我已经在控制台中检查了那些 mathc s3。

尝试像这样调用 HeadObject 的 api 时:

$this->s3Client->headObject([
    'Bucket' => $fileBucket,
    'Key' => $key
]);

我收到以下消息:

"Error executing \"HeadObject\" on \"https://example-dev-us-east-1-111111111111/54bf7350-a819-41dd-9da3-3710eb8b095a-Screenshot_2021-03-09_20-15-12.png\"; AWS HTTP error: Client error: `HEAD https://example-dev-us-east-1-111111111111/54bf7350-a819-41dd-9da3-3710eb8b095a-Screenshot_2021-03-09_20-15-12.png` resulted in a `403 Forbidden` response  (client): 403 Forbidden (Request-ID: XR6W77BB817407K2) - ",
"url": "/files.json"

不确定这是否有帮助。

谢谢!

【问题讨论】:

    标签: php amazon-web-services amazon-s3 aws-sdk


    【解决方案1】:

    您需要s3:GetObject 权限才能调用HeadObject API,这是您的代码调用doesObjectExist() 时PHP SDK 调用的API。

    如果您请求的对象不存在,Amazon S3 将返回错误 取决于你是否也有 s3:ListBucket 权限。

    • 如果您对存储桶拥有 s3:ListBucket 权限,Amazon S3 返回 HTTP 状态码 404(“没有这样的键”)错误。
    • 如果您不这样做 拥有 s3:ListBucket 权限,Amazon S3 返回 HTTP 状态 代码 403(“拒绝访问”)错误。

    所以,您可能有 s3:ListBucket 但没有 s3:GetObject。

    【讨论】:

    • 资源应该是 S3 ARN,而不是简单地以存储桶名称为前缀。他们是正确的吗?您是否尝试过使用带有这些凭据的 awscli 的 HeadObject 或 GetObject?仅供参考,这不是一个桶策略;这是一项 IAM 政策。
    • 仅供参考,您可以为任何对象创建预签名 URL,包括不存在的对象和您无权访问的对象。当您尝试访问实际对象时,稍后会出现失败,因此不要将任何内容读入您能够创建预签名 URL 的事实(无论权限如何,它几乎总是会成功)。
    • 根据我的回答,如果您在调用 HeadObject 时得到 404,那么您有 S3:ListBucket 但没有 S3:GetObject。如果你得到 403,那么你就没有 S3:ListBucket。
    • 我会检查 S3 存储桶没有冲突的策略。我会使用 awscli 为 HeadObject 和 GetObject 测试相同的凭据。
    • 您最初提到您使用的是 IAM 用户,但现在您显示的存储桶策略似乎暗示了跨账户角色权限。这是跨账户吗?是什么发出 S3 API 请求 - 是不同账户中的 IAM 用户还是不同账户中的 IAM 角色?
    猜你喜欢
    • 2018-03-18
    • 2018-11-23
    • 1970-01-01
    • 1970-01-01
    • 2012-11-10
    • 2020-10-18
    • 2022-07-22
    • 2013-07-04
    • 2015-05-24
    相关资源
    最近更新 更多