如何使用假设角色将其他 AWS 账户中的 S3 对象放入您自己的账户 S3 存储桶中?

问题描述 投票:0回答:2

我有一个非常典型的用例,我在 AWS 帐户(1234567890 - 不受我的控制)中被授予一个角色,可以从其 S3 存储桶(“remote_bucket”)读取数据。我可以很好地从远程存储桶中读取数据,但我无法再将其转储到我自己的存储桶中,因为在另一个 AWS 账户中承担角色会“隐藏”对我自己账户上的资源的授权。最后一行因错误而失败。怎么解决这个问题?

import boto3

# Create IAM client and local session
sts = boto3.client('sts')
local_sess = boto3.Session()
s3_local = local_sess.resource('s3')

role_to_assume_arn='arn:aws:iam::1234567890:role/s3_role'
role_session_name='test'

# Assume role in another account to access their S3 bucket
response = sts.assume_role(
    RoleArn = role_to_assume_arn,
    RoleSessionName = 'test',
    ExternalId = 'ABCDEFG12345'
)

creds=response['Credentials']

# open session in another account:
assumed_sess = boto3.Session(
    aws_access_key_id=creds['AccessKeyId'],
    aws_secret_access_key=creds['SecretAccessKey'],
    aws_session_token=creds['SessionToken'],
)

remote_bucket = 'remote_bucket'
s3_assumed = assumed_sess.resource('s3')
bk_assumed = s3_assumed.Bucket(remote_bucket)

for o in bk_assumed.objects.filter(Prefix="prefix/"):
    print(o.key)
    in_object = s3_assumed.Object(remote_bucket, o.key)
    content = in_object.get()['Body'].read()
    s3_local.Object('my_account_bucket', o.key).put(Body=content)

错误:

botocore.exceptions.ClientError: An error occurred (AccessDenied) when calling the PutObject operation: Access Denied
amazon-web-services file amazon-s3 copy bucket
2个回答
2
投票

TL;DR 请参阅最后,了解比使用角色更容易配置权限的方法!)

在存储桶之间移动数据的最简单方法是使用

copy_object()
命令。该命令被发送到目标存储桶并从源存储桶“拉取”信息。

当涉及多个 AWS 账户时,情况会稍微复杂一些,因为同一组凭证需要源存储桶上的

GetObject
权限以及目标存储桶上的 PutObject 权限。

您的情况似乎是:

    GetObject
  • 已通过您可以承担的角色授予源存储桶权限
    但是,该角色对目标存储桶没有 
  • PutObject
  • 权限
    
    
    
  • 重要的是,如果角色还被分配了写入目标存储桶的权限。

为了测试这种情况,我做了以下操作:

    Bucket-A
  • (源存储桶)中创建了
    Account-A
    并上传了一些测试文件
  • Bucket-B
  • (目标存储桶)
    中创建 
    Account-B
  • Role-A
  • 中创建了
    Account-A
    ,指定可以被
    Account-B
    使用
    
    将此 IAM 策略分配给
  • Role-A
  • :
    
    
    
  • { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "s3:List*", "s3:Get*" ], "Resource": [ "arn:aws:s3:::bucket-a", "arn:aws:s3:::bucket-a/*" ] }, { "Effect": "Allow", "Action": [ "s3:Put*" ], "Resource": [ "arn:aws:s3:::bucket-b/*" ] } ] }
请注意,该角色还被授予写入 
Bucket-B

的权限。这可能不会出现在您的特定情况下,但这是必要的,否则

Account-A
将不允许角色调用
Bucket-B

澄清一下:

使用跨账户权限时,两个账户都需要授予权限。在这种情况下,Account-A 授予

Role-A
写入
Bucket-B
的权限,但
Account-B
还必须允许写入(请参阅下面的存储桶策略)。

    User-B
  • 中创建了
    Account-B
    ,并授予在
    AssumeRole
    中的
    Role-A
    上调用
    Account-A
    的权限:
    
    
    
  • { "Version": "2012-10-17", "Statement": [ { "Sid": "AssumeRoleA", "Effect": "Allow", "Action": "sts:AssumeRole", "Resource": "arn:aws:iam::111111111111:role/role-a" } ] }
    Bucket-B
  • 上创建了存储桶策略,允许
    Role-A
    将文件放入存储桶中。这很重要,因为
    Account-A
    无法访问
    Account-B
    中的资源,但此存储桶策略将允许
    Role-A
    使用该存储桶。
    
    
    
  • { "Version": "2012-10-17", "Statement": [ { "Action": [ "s3:PutObject", "s3:PutObjectAcl" ], "Effect": "Allow", "Resource": "arn:aws:s3:::bucket-b/*", "Principal": { "AWS": [ "arn:aws:iam::111111111111:role/role-a" ] } } ] }
更新了我的凭据文件以使用
    Role-A
  • 
    
    
  • [role-a] role_arn = arn:aws:iam::906972072995:role/role-a source_profile = user-b
确认我可以访问
    Bucket-A
  • :
    
    
    
  • aws s3 ls s3://bucket-a --profile role-a
确认我可以将对象从 
    Bucket-A
  • 复制到
    Bucket-B
    :
    
    
    
  • aws s3 cp s3://bucket-a/foo.txt s3://stack-bucket-b/ --profile role-a
这次成功了。

总结

上述过程可能看起来相当复杂,但可以很容易地分为源和目的地:

    来源:
  • 提供了Role-A,可以从
    Bucket-A
    读取,也有权限写入
    Bucket-B
  • 目的地:
  • Bucket-B 上的存储桶策略允许
    Role-A
    写入
    
    
    
  • 如果
Account-A

不愿意提供既可以读取

Bucket-A
又可以写入
Bucket-B
的角色权限,那么
还有另一个选择:

要求
    Account-A
  • 添加存储桶策略
    Bucket-A 允许
    User-B
    GetObject
    然后,
  • User-B
  • 可以使用正常 (
    User-B
    ) 权限从
    Bucket-A
     读取内容,无需 AssumeRole
    这显然比担任角色要容易得多

0
投票

object_res = self.s3_client.get_object(Bucket=bucket_name, Key=obj_key) obj_contents_encoded = object_res["Body"].read()

© www.soinside.com 2019 - 2024. All rights reserved.