You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

EC2实例中Flask应用调用S3 PutObject时出现AccessDenied权限问题

EC2上Flask应用使用boto3上传S3报AccessDenied问题

在EC2实例运行的Flask应用中,使用boto3向AWS S3上传图片时触发AccessDenied错误,但本地运行完全正常。已为EC2实例角色附加了S3相关权限策略,具体信息如下:

已附加的IAM实例角色策略

{
  "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:::*/*"
      ]
    }
  ]
}

报错信息

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

上传用Flask代码

from flask import current_app
from werkzeug.datastructures import FileStorage
import boto3

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操作,尤其是针对该EC2实例角色的访问。
  • 验证实例角色信任关系:确保信任关系文档中包含ec2.amazonaws.com作为Principal,允许EC2服务承担该角色。
  • 确认S3阻止公共访问配置:代码中使用public-read ACL,若桶开启了阻止公共访问的相关选项,设置公共ACL会被拒绝,进而导致PutObject失败。可在S3控制台关闭对应选项,或修改ACL为private等非公共权限。
  • 检查EC2实例角色关联状态:在EC2控制台确认实例已正确附加目标IAM角色,也可在实例内执行以下命令验证凭证是否有效:
    # 获取角色名称
    curl http://169.254.169.254/latest/meta-data/iam/security-credentials/
    # 获取临时凭证详情
    curl http://169.254.169.254/latest/meta-data/iam/security-credentials/[角色名称]
    
  • 排查实例内AWS凭证优先级:若EC2实例环境变量中配置了AWS_ACCESS_KEY_ID和AWS_SECRET_ACCESS_KEY,会覆盖实例角色凭证,导致使用错误权限执行上传。需确保实例未配置此类环境变量。

内容的提问来源于stack exchange,提问作者George Udosen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 18:52:38