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

使用Boto3通过预签名URL上传文件至S3时遇AccessDenied问题求助

使用Boto3预签名POST URL上传S3时遇AccessDenied,需明确所需最小权限

问题背景

通过Boto3调用generate_presigned_post生成预签名URL上传文件到S3存储桶时,持续出现AccessDenied错误。已尝试复制官方示例代码、添加CORS规则、配置桶策略、关闭公共访问阻止等操作,均未解决。使用管理员权限角色执行则可成功,现需明确完成该上传操作所需的具体IAM权限。

存储桶配置:默认设置(无CORS、开启阻止公共访问、默认加密)

相关代码

import logging
import boto3
from botocore.exceptions import ClientError
from botocore.config import Config
import requests    
from pprint import pprint

config = Config(signature_version="v4")
s3_client = boto3.client('s3', config=config)


def create_presigned_post(bucket_name, object_name,
                          fields=None, conditions=None, expiration=3600):
    """Generate a presigned URL S3 POST request to upload a file

    :param bucket_name: string
    :param object_name: string
    :param fields: Dictionary of prefilled form fields
    :param conditions: List of conditions to include in the policy
    :param expiration: Time in seconds for the presigned URL to remain valid
    :return: Dictionary with the following keys:
        url: URL to post to
        fields: Dictionary of form fields and values to submit with the POST
    :return: None if error.
    """

    # Generate a presigned S3 POST URL
    s3_client = boto3.client('s3')
    try:
        response = s3_client.generate_presigned_post(bucket_name,
                                                     object_name,
                                                     Fields=fields,
                                                     Conditions=conditions,
                                                     ExpiresIn=expiration)
    except ClientError as e:
        logging.error(e)
        return None

    # The response contains the presigned URL and required fields
    return response


def create_bucket(s3_bucket_name):
    response = s3_client.create_bucket(Bucket=s3_bucket_name, CreateBucketConfiguration={
        'LocationConstraint': 'eu-west-2'})
    pprint(response)


key_name = 'italian_spiderman.jpg'
bucket_name='italian-spiderman-bucket'
# create_bucket(bucket_name)

response = create_presigned_post(bucket_name, key_name)
print(response)
if response is None:
    exit(1)

# Demonstrate how another Python program can use the presigned URL to upload a file
with open(key_name, 'rb') as f:
    files = {'file': (key_name, f)}
    http_response = requests.post(response['url'], data=response['fields'], files=files)
    print(http_response)
    pprint(http_response.text)
# If successful, returns HTTP status code 204
logging.info(f'File upload HTTP status code: {http_response.status_code}')

所需具体权限

完成预签名POST上传S3的操作,角色需要以下最小权限:

  • 核心权限:s3:PutObject,需指定目标存储桶及对象路径作为资源,示例IAM策略如下:
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::italian-spiderman-bucket/*"
        }
    ]
}
  • 额外权限(若适用):如果存储桶启用了SSE-KMS加密,还需为角色添加kms:GenerateDataKey权限(针对所用KMS密钥);若使用SSE-S3默认加密,则无需额外权限。

补充说明

  1. 无需配置s3:*这类宽泛权限,遵循最小权限原则即可避免权限冗余问题。
  2. 若之前配置了s3:*仍报错,需排查:角色的信任策略是否允许当前实体(如EC2、Lambda、本地环境)扮演该角色;是否存在权限边界、组织SCP等限制策略影响权限生效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 04:10:47