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

拥有管理员权限的用户调用Boto3 ListObject时出现403 Forbidden错误

解决Lambda调用S3 HeadObject时的403 Forbidden问题

你遇到的这个403错误虽然提示是权限禁止,但实际原因可能不止IAM权限这一项,结合你的场景,我整理了几个排查和解决方向:

1. 确认Lambda执行角色的权限覆盖完整

虽然你提到已经配置了对应权限,但要确保策略包含HeadObject这个动作——因为download_file方法内部会自动调用HeadObject来获取对象元数据,很多人会忽略这个权限。

正确的权限策略应该包含以下动作和资源:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket",
                "s3:GetObject",
                "s3:HeadObject"
            ],
            "Resource": [
                "arn:aws:s3:::YOUR_BUCKET_NAME", // ListBucket需要桶级ARN
                "arn:aws:s3:::YOUR_BUCKET_NAME/*" // GetObject/HeadObject需要对象级ARN
            ]
        }
    ]
}

注意区分桶级和对象级的资源配置,这是很容易踩的坑。

2. 检查S3桶的Bucket Policy是否存在拒绝规则

IAM角色的允许权限可能会被桶策略的拒绝规则覆盖。你可以去S3控制台的「权限」-「桶策略」里检查:

  • 是否有针对该Lambda角色的Deny语句
  • 是否有IP限制、VPC限制、HTTPS强制等条件,导致Lambda的请求不符合要求

比如如果桶策略要求请求必须来自特定IP,而Lambda默认是公网IP,就会触发403。

3. 排查Lambda的VPC配置(如果启用了VPC)

如果你的Lambda配置了VPC,那它默认无法直接访问公网的S3服务,需要做以下配置之一:

  • 给VPC添加S3网关端点,让Lambda可以通过VPC内部访问S3
  • 确保Lambda所在的子网关联了NAT网关,能正常访问公网

如果没配置VPC,这一步可以跳过。

4. 修正代码中的潜在问题

你的代码还有几个可能导致异常的点,即使当前的403解决了,后续也会出问题:

  • 下载路径没有指向/tmp:Lambda只有/tmp目录有写入权限,你直接用s3_object作为目标路径会因权限不足失败
  • 没有处理list_objects的分页:如果桶内对象超过1000个,list_objects只会返回第一页,漏掉后续对象
  • 虚拟文件夹的处理:S3的文件夹是虚拟的,以/结尾的对象不需要创建本地目录,反而会导致路径混乱

修正后的代码示例:

import boto3
import os
import logging

logger = logging.getLogger()
logger.setLevel(logging.INFO)

def lambda_handler(event, context):
    s3_bucket = os.getenv('S3BUCKETNAME')
    s3_client = boto3.client('s3')

    # 用分页器处理超过1000个对象的情况
    paginator = s3_client.get_paginator('list_objects_v2')
    page_iterator = paginator.paginate(Bucket=s3_bucket)

    for page in page_iterator:
        if 'Contents' not in page:
            continue
        for s3_key in page['Contents']:
            s3_object_key = s3_key['Key']
            # 跳过S3的虚拟文件夹对象
            if s3_object_key.endswith("/"):
                continue
            # 把文件下载到/tmp目录下
            local_path = f"/tmp/{s3_object_key}"
            # 创建嵌套的本地目录(如果需要)
            local_dir = os.path.dirname(local_path)
            if not os.path.exists(local_dir):
                os.makedirs(local_dir)
            try:
                s3_client.download_file(s3_bucket, s3_object_key, local_path)
                logger.info(f"成功下载 {s3_object_key} 到 {local_path}")
            except Exception as e:
                logger.error(f"下载 {s3_object_key} 失败: {str(e)}")

5. 检查S3对象的加密配置

如果你的S3对象用了KMS加密,那Lambda角色还需要额外的kms:Decrypt权限,对应加密所用的KMS密钥ARN,否则会因无法解密对象触发403。

6. 从CloudWatch日志获取更详细的错误信息

CloudWatch日志里的完整错误信息通常会包含更具体的拒绝原因,比如缺少哪个权限、桶策略的哪条规则生效了,建议你仔细查看日志的细节部分,这能帮你快速定位问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 06:58:20