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

FastAPI集成S3时用boto3删除对象遇Access Denied错误求助

AWS S3 DeleteObject Access Denied 问题排查与修复

问题描述

将AWS S3集成到FastAPI项目中,已成功配置IAM权限和S3桶权限实现图片上传,但执行删除图片操作时反复出现Access Denied错误,已排查桶名/密钥拼写、版本控制、对象存在性等问题,仍未解决。

报错详情

INFO:     127.0.0.1:56293 - "DELETE /api/feed/delete/5 HTTP/1.1" 500 Internal Server Error
ERROR:    Exception in ASGI application
Traceback (most recent call last):
  File "/opt/homebrew/lib/python3.11/site-packages/uvicorn/protocols/http/h11_impl.py", line 408, in run_asgi
    result = await app(  # type: ignore[func-returns-value]
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/lib/python3.11/site-packages/uvicorn/middleware/proxy_headers.py", line 84, in __call__
    return await self.app(scope, receive, send)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/lib/python3.11/site-packages/fastapi/applications.py", line 292, in __call__
    await super().__call__(scope, receive, send)
  File "/opt/homebrew/lib/python3.11/site-packages/starlette/applications.py", line 122, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/opt/homebrew/lib/python3.11/site-packages/starlette/middleware/errors.py", line 184, in __call__
    raise exc
  File "/opt/homebrew/lib/python3.11/site-packages/starlette/middleware/errors.py", line 162, in __call__
    await self.app(scope, receive, _send)
  File "/opt/homebrew/lib/python3.11/site-packages/starlette/middleware/exceptions.py", line 79, in __call__
    raise exc
  File "/opt/homebrew/lib/python3.11/site-packages/starlette/middleware/exceptions.py", line 68, in __call__
    await self.app(scope, receive, sender)
  File "/opt/homebrew/lib/python3.11/site-packages/fastapi/middleware/asyncexitstack.py", line 20, in __call__
    raise e
  File "/opt/homebrew/lib/python3.11/site-packages/fastapi/middleware/asyncexitstack.py", line 17, in __call__
    await self.app(scope, receive, send)
  File "/opt/homebrew/lib/python3.11/site-packages/starlette/routing.py", line 718, in __call__
    await route.handle(scope, receive, send)
  File "/opt/homebrew/lib/python3.11/site-packages/starlette/routing.py", line 276, in handle
    await self.app(scope, receive, send)
  File "/opt/homebrew/lib/python3.11/site-packages/starlette/routing.py", line 66, in app
    response = await func(request)
               ^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/lib/python3.11/site-packages/fastapi/routing.py", line 273, in app
    raw_response = await run_endpoint_function(
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/lib/python3.11/site-packages/fastapi/routing.py", line 192, in run_endpoint_function
    return await run_in_threadpool(dependant.call, **values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/lib/python3.11/site-packages/starlette/concurrency.py", line 41, in run_in_threadpool
    return await anyio.to_thread.run_sync(func, *args)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/lib/python3.11/site-packages/anyio/to_thread.py", line 33, in run_sync
    return await get_asynclib().run_sync_in_worker_thread(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/lib/python3.11/site-packages/anyio/_backends/_asyncio.py", line 877, in run_sync_in_worker_thread
    return await future
           ^^^^^^^^^^^^
  File "/opt/homebrew/lib/python3.11/site-packages/anyio/_backends/_asyncio.py", line 807, in run
    result = context.run(func, *args)
             ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/gnimom/Documents/Personal/FastAPI_SQLAlchemy_Pydantic/FastAPI_SQLAlchemy_Pydantic/routers/feed_router.py", line 70, in delete
    feed_service.delete_feed(db, feed_id, email)
  File "/Users/gnimom/Documents/Personal/FastAPI_SQLAlchemy_Pydantic/FastAPI_SQLAlchemy_Pydantic/services/feed_service.py", line 161, in delete_feed
    delete_image_from_s3(image_url)
  File "/Users/gnimom/Documents/Personal/FastAPI_SQLAlchemy_Pydantic/FastAPI_SQLAlchemy_Pydantic/services/feed_service.py", line 190, in delete_image_from_s3
    s3_client.delete_object(Bucket=settings.S3_BUCKET, Key=image_name)
  File "/opt/homebrew/lib/python3.11/site-packages/botocore/client.py", line 535, in _api_call
    return self._make_api_call(operation_name, kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/lib/python3.11/site-packages/botocore/client.py", line 980, in _make_api_call
    raise error_class(parsed_response, operation_name)
botocore.exceptions.ClientError: An error occurred (AccessDenied) when calling the DeleteObject operation: Access Denied

当前配置

S3桶策略

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Statement1",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:*",
            "Resource": [
                "arn:aws:s3:::my-fastapi",
                "arn:aws:s3:::my-fastapi/*"
            ]
        }
    ]
}

IAM与客户端代码

S3客户端初始化

import boto3
from config import settings

s3_client = boto3.client(
    "s3",
    aws_access_key_id=settings.S3_ACCESS_KEY,
    aws_secret_access_key=settings.S3_SECRET_KEY,
    region_name="ap-northeast-2",
)

删除图片函数

def delete_image_from_s3(image_url: str):
    image_name = image_url.split("/")[-1]
    bucket_name = settings.S3_BUCKET

    logging.debug(f"Deleting from Bucket: {bucket_name}, Key: {image_name}")

    s3_client.delete_object(Bucket=settings.S3_BUCKET, Key=image_name)

排查与修复方案

  • 验证对象Key的完整性:image_url.split("/")[-1]可能丢失对象的前缀路径(比如上传时Key是uploads/xxx.jpg,但拆分后仅得到xxx.jpg),导致请求的对象不存在,S3会返回Access Denied混淆问题。打印完整的Key,对比S3控制台中的对象实际路径确认。
  • 检查桶的Block Public Access设置:即使桶策略开放全权限,Block Public Access中的Block public access to buckets and objects granted through any access control lists (ACLs)等选项可能覆盖权限配置,需确认该设置未限制删除操作。
  • 确认IAM用户的权限边界:若IAM用户附加了权限边界,即使配置了S3FullAccess,权限边界可能限制DeleteObject操作,需检查权限边界策略是否包含该操作。
  • 检查S3 Object Lock状态:若桶启用了Object Lock,对象处于Retention或Legal Hold锁定状态时无法删除,需在控制台查看对象的锁定配置。
  • 用AWS CLI验证权限:使用对应IAM凭证执行命令aws s3 rm s3://my-fastapi/[完整对象Key] --region ap-northeast-2,直接测试删除操作,排除代码层面的问题。
  • 确认桶区域匹配:确保代码中指定的ap-northeast-2与S3桶实际创建的区域一致,区域不匹配会导致请求被拒绝。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 06:42:05