如何使用承担角色将S3对象从另一个AWS账户放入您自己的账户S3存储桶中?

时间:2019-06-21 23:11:41

标签: amazon-web-services file amazon-s3 copy bucket

我有一个非常典型的用例,其中我在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

1 个答案:

答案 0 :(得分:0)

TL; DR 请参见结尾,以了解一种比使用角色更容易配置权限的方法!)

在存储桶之间移动数据的最简单方法是使用copy_object()命令。此命令将发送到目标存储桶,并从源存储桶“拉”信息。

当涉及多个AWS账户时,这会变得稍微复杂一些,因为同一组凭据需要对源存储桶具有GetObject权限,而对目标存储桶则具有{em> {em} 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,并授予在AssumeRoleRole-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-BGetObject
  • 然后,
  • User-B可以使用普通(User-B)权限从Bucket-A 读取内容,而无需使用AssumeRole
  • 显然,这比承担角色要容易得多