跨AWS账号S3复制时HeadObject报403 Forbidden问题求助
源存储桶与目标存储桶位于同一区域但分属不同AWS账号,执行以下S3复制代码时失败:
import boto3 from datetime import datetime assumed_role = boto3.client('sts').assume_role( RoleArn='arn:aws:iam::DESTACCT:role/copy-role', RoleSessionName='RoleSessionName' + datetime.now().strftime('%Y%M%d%H%m%s')) args = { 'aws_access_key_id': assumed_role['Credentials']['AccessKeyId'], 'aws_secret_access_key': assumed_role['Credentials']['SecretAccessKey'], 'aws_session_token': assumed_role['Credentials']['SessionToken']} session = boto3.Session(**args) dest_bucket = session.resource('s3').Bucket('dest-bucket') copy_source = {'Key': 'source-prefix/someobject', 'Bucket': 'source-bucket'} dest_bucket.copy(CopySource=copy_source, Key='dest-prefix/someobject')
报错信息:
botocore.exceptions.ClientError: An error occurred (403) when calling the HeadObject operation: Forbidden
copy-role的权限配置:
{ "Action": "s3:Put*", "Effect": "Allow", "Resource": "arn:aws:s3:::dest-bucket/dest-prefix/*" } { "Action": ["s3:List*","s3:Get*"], "Effect": "Allow", "Resource": [ "arn:aws:s3:::source-bucket/source-prefix/*", "arn:aws:s3:::source-bucket/source-prefix" ] }
source-bucket的桶策略规则:
{ "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::DESTACCT:role/copy-role" }, "Action": "s3:List*", "Resource": "arn:aws:s3:::source-bucket" }, { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::DESTACCT:role/copy-role" }, "Action": [ "s3:List*", "s3:Get*" ], "Resource": [ "arn:aws:s3:::source-bucket/source-prefix/*", "arn:aws:s3:::source-bucket/source-prefix" ] }
根据copy()文档说明:
SourceClient (botocore or boto3 Client) – 用于处理源对象相关操作的客户端,例如用于执行head_object以确定复制对象的大小。若未指定,则使用当前客户端处理源对象操作。
已确认copy-role拥有source-bucket/source-prefix的s3:Get*和s3:List*权限,且日志显示失败的HEAD请求针对源存储桶:
HEAD /source-prefix/someobject HTTP/1.1 Host: source-bucket.s3.amazonaws.com
为何仍出现HeadObject 403 Forbidden错误?
核心问题:角色会话身份未被授权
当使用sts:assume_role获取临时凭证后,实际发起请求的身份是角色会话ARN(格式为arn:aws:sts::DESTACCT:assumed-role/copy-role/RoleSessionNameXXX),而非原角色的ARNarn:aws:iam::DESTACCT:role/copy-role。但你配置的源桶策略中,Principal仅指定了原角色ARN,S3不会自动将权限扩展到该角色的会话身份,导致HeadObject请求的权限校验失败。
修复步骤
更新源桶策略的Principal范围
修改源桶策略,让Principal覆盖角色的所有会话身份,有两种方式:- 直接使用角色ARN加通配符:
"Principal": { "AWS": "arn:aws:iam::DESTACCT:role/copy-role/*" } - 保留原角色ARN,添加条件允许其会话身份:
"Principal": { "AWS": "arn:aws:iam::DESTACCT:role/copy-role" }, "Condition": { "StringLike": { "aws:PrincipalArn": "arn:aws:sts::DESTACCT:assumed-role/copy-role/*" } }
- 直接使用角色ARN加通配符:
验证权限覆盖
确认copy-role的s3:Get*权限确实覆盖目标对象:当前配置的source-bucket/source-prefix/*已经包含source-prefix/someobject,这部分无需修改,核心还是会话身份的授权问题。可选:使用SourceClient分离源/目标权限
如果不想修改源桶策略,可以在代码中创建两个S3客户端:一个用目标角色凭证处理写入操作,另一个用源账号的IAM凭证(需拥有源桶读取权限)处理源对象操作,调用copy()时传入源客户端:# 源账号会话(替换为源账号的有效凭证) source_session = boto3.Session( aws_access_key_id='SOURCE_ACCESS_KEY', aws_secret_access_key='SOURCE_SECRET_KEY' ) source_client = source_session.client('s3') # 传入SourceClient执行复制 dest_bucket.copy(CopySource=copy_source, Key='dest-prefix/someobject', SourceClient=source_client)
内容的提问来源于stack exchange,提问作者jph

