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

跨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请求的权限校验失败。

修复步骤

  1. 更新源桶策略的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/*"
        }
      }
      
  2. 验证权限覆盖
    确认copy-role的s3:Get*权限确实覆盖目标对象:当前配置的source-bucket/source-prefix/*已经包含source-prefix/someobject,这部分无需修改,核心还是会话身份的授权问题。

  3. 可选:使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 17:28:41