AWS 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_creds和create_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




