You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

AWS S3跨账号复制触发HeadObject 403 Forbidden错误求助

排查跨账号S3复制HeadObject 403 Forbidden错误

首先,你的核心问题出现在几个关键点上,结合你的配置和代码逐一分析:

1. 源桶Bucket Policy缺失Principal(最关键问题)

你提供的源桶Bucket Policy没有指定Principal字段,这意味着这个策略没有授予任何实体访问权限——即使你的Lambda角色有对应的IAM权限,源桶也会拒绝访问请求。Bucket Policy必须明确指定允许的账号、角色或用户ARN才能生效。

修复方案:在源桶Policy的Statement中添加目标账号的Lambda角色ARN作为Principal,或者直接允许整个目标账号(更推荐前者,更安全):

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowCrossAccountLambdaAccess",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::目标账号ID:role/LambdaRole"
            },
            "Action": ["s3:Get*", "s3:List*"],
            "Resource": [
                "arn:aws:s3:::source_bucket",
                "arn:aws:s3:::source_bucket/FBI/*"
            ]
        }
    ]
}

2. 代码中手动获取凭证的逻辑冗余且易出错

你的get_credscreate_connection函数手动提取当前会话的凭证并传给boto3客户端,这完全不必要——Lambda运行时会自动为执行角色注入临时凭证,直接使用默认的boto3客户端即可,手动传递凭证可能导致权限上下文错误(比如STS token的权限范围问题)。

同时原代码中copy_to_prefix错误地包含了目标桶名,copy方法的第二个参数已经是桶名,第三个参数只需传桶内的路径即可。

修复后的代码

import boto3
from botocore.config import Config
from datetime import date

def lambda_handler(event, context):
    src_bucket = 'source_bucket'
    dest_bucket = 'destination_bucket'
    # 修正前缀:不需要包含目标桶名
    date_prefix = date.today().strftime("%Y/%m/%d")
    
    # 直接使用默认boto3客户端,自动继承Lambda角色权限
    my_config = Config(region_name='us-east-1', signature_version='s3v4')
    s3_client = boto3.client('s3', config=my_config)
    
    # 列出源桶对象(带分页逻辑优化)
    keys = []
    next_token = None
    while True:
        list_kwargs = {
            'Bucket': src_bucket,
            'Prefix': 'FBI/'
        }
        if next_token:
            list_kwargs['ContinuationToken'] = next_token
        
        results = s3_client.list_objects_v2(**list_kwargs)
        contents = results.get('Contents', [])
        for item in contents:
            keys.append(item['Key'])
        
        next_token = results.get('NextContinuationToken')
        if not next_token:
            break
    
    # 执行对象复制
    for key in keys:
        copy_source = {'Bucket': src_bucket, 'Key': key}
        dest_key = f"{date_prefix}/{key.split('/', 1)[1]}"
        extra_args = {'ACL': 'bucket-owner-full-control'}
        
        s3_client.copy(copy_source, dest_bucket, dest_key, ExtraArgs=extra_args)

3. 确认Lambda角色的信任策略正确

确保目标账号的LambdaRole角色的信任策略允许Lambda服务assume这个角色,否则Lambda无法获取该角色的权限:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "lambda.amazonaws.com"
            },
            "Action": "sts:AssumeRole"
        }
    ]
}

4. 检查源桶的Block Public Access设置

如果源桶开启了Block Public Access中的Block public access to buckets and objects granted through any access control lists (ACLs)或其他相关选项,可能会干扰跨账号访问,确保这些设置没有阻止你的策略生效。

5. 验证当前使用的角色身份

可以在Lambda中添加临时代码,打印当前调用者的身份,确认正在使用的是正确的LambdaRole:

sts_client = boto3.client('sts')
print(sts_client.get_caller_identity())

查看CloudWatch日志中的输出,确认Arn字段是你的LambdaRole的ARN,排除角色切换错误的可能。


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

火山引擎 最新活动