繁体   English   中英

调用 PutObject 操作时发生错误 (AccessDenied):Access Denied 但在我的系统上有效

[英]An error occurred (AccessDenied) when calling the PutObject operation: Access Denied but works on my system

我坚持尝试使用我的 flask 应用程序中的 boto3 库将图像上传到 aws s3,该应用程序运行在 ec2 实例上,实例角色附加了以下 s3 策略:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "s3:GetBucketTagging",
                "s3:ListBucket",
                "s3:GetBucketAcl",
                "s3:GetBucketPolicy",
                "s3:PutObject",
                "s3:GetObjectAcl",
                "s3:GetObject",
                "s3:PutObjectVersionAcl",
                "s3:GetObjectVersionAcl",
                "s3:PutBucketAcl",
                "s3:PutBucketPolicy",
                "s3:DeleteObject",
                "s3:GetBucketLocation",
                "s3:PutObjectAcl",
                "s3:AbortMultipartUpload",
                "s3:ListBucketMultipartUploads",
                "s3:AbortMultipartUpload",
                "s3:ListMultipartUploadParts"
            ],
            "Resource": [
                "arn:aws:s3:::bucket-name",
                "arn:aws:s3:::bucket-name/*",
                "arn:aws:s3:::bucket-name/users/*",
                "arn:aws:s3:::*/*"
            ]
        }
    ]
}

这在我的计算机上有效,但在上传到 ec2 实例上运行的 flask 应用程序时失败。 我收到以下错误:

An error occurred (AccessDenied) when calling the PutObject operation: Access Denied

这是用于执行此上传的 flask 代码:

class S3ImageBucketManagement:
    S3_LOCATION = 'http://{}.s3.amazonaws.com/'.format('bucket-name')

    def __init__(self, bucket_name: str, bucket_region: str, _id: str, image_type: str, acl: str = "public-read"):
        self._client = self.__s3_resource().Bucket(bucket_name)
        self._image_type = image_type
        self._bucket_name = bucket_name
        self._bucket_region = bucket_region
        self._id = _id
        self._acl = acl

    def __s3_resource(self):
        """
        Creates the boto3 client
        :return: boto3.client
        """
        session = boto3.Session()
        res = None
        try:
            res = session.resource(
                service_name='s3',
                region_name='eu-west-2'
            )
        except Exception as e:
            print(f'Error: {e}')
        return res

    def upload_file_to_s3(self, file: FileStorage, upload_folder: str):
        try:
            res = self._client
            res.put_object(
                Body=file,
                Bucket=self._bucket_name,
                Key=f"{self._image_type}/{file.filename}",
                ACL=self._acl,
                ContentType=file.content_type,
            )

            # res.upload_file(
            #     Filename=f"/tmp/{file.filename}",
            #     Key=f"{self._image_type}/{file.filename}",
            #     ExtraArgs={
            #         "ACL": self._acl,
            #         "ContentType": file.content_type
            #     }
            # )
         except Exception as e:
            current_app.logger.error(f'upload_file_to_s3 function error: {e}')
            return False, 'File upload failed', 500
         return True, "{}{}/{}".format(self.S3_LOCATION, self._image_type, file.filename), 200

我不知道我在权限中缺少什么,以及为什么这在我的系统上有效但在服务器上无效。

你的保单看起来不错。 您已完成两项必需的操作

s3:PutObject
s3:PutObjectACL

并以正确的方式列出桶。 但是,python的实现有点问题。 AWS python SDK 提供了两个接口:一个client和一个resource

客户端接口非常接近 API,如果操作返回一个,您会收到一个 json 作为响应。

资源接口是 pythonic 的,它是更高级别的并返回一个你可以使用的 object。

在上面的代码中,您从 Session 启动资源

res = session.resource(
            service_name='s3',
            region_name='eu-west-2'
        )

但是,在尝试上传时,语法使用的是客户端语法而不是资源语法。 如果你想使用客户端的put_object方法,那么你应该从session发起一个客户端。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM