AWS 提供从另一个账户访问代入角色以访问我账户中的 S3

AWS Providing access to assumed role from another account to access S3 in my account

我想要实现的是将一个帐户(A1 - 不受我控制)中的 S3 中的对象复制到另一个帐户(A2 - 由我控制)中的 S3 中。 因为来自 A1 的 OPS 为我提供了一个我可以承担的角色,使用 boto3 库。

session = boto3.Session()
sts_client = session.client('sts')

assumed_role = sts_client.assume_role(
    RoleArn="arn:aws:iam::1234567890123:role/organization",
    RoleSessionName="blahblahblah"
)

这部分还可以。 问题是从 S3 到 S3 的直接复制失败,因为该假定角色无法访问我的 S3。

s3 = boto3.resource('s3')
copy_source = {
    'Bucket': a1_bucket_name,
    'Key': key_name
}

bucket = s3.Bucket(a2_bucket_name)
bucket.copy(copy_source, hardcoded_key)

结果我得到

botocore.exceptions.ClientError: An error occurred (403) when calling the HeadObject operation: Forbidden

在这行代码中:

bucket.copy(copy_source, hardcoded_key)

有什么方法可以授予该假定角色访问我的 S3 的权限? 我真的很想直接从 S3 复制到 S3,而无需在本地下载文件,然后再重新上传。

请告知是否有比这更好的方法。

例如,我的想法是每天将此脚本 运行 放入 AWS Data Pipeline 中。

这是使用 boto 3 在具有 2 个不同 AWS 帐户的两个 S3 存储桶之间传输数据的示例代码。

from boto.s3.connection import S3Connection
from boto.s3.key import Key
from Queue import LifoQueue
import threading

source_aws_key = '*******************'
source_aws_secret_key = '*******************'
dest_aws_key = '*******************'
dest_aws_secret_key = '*******************'
srcBucketName = '*******************'
dstBucketName = '*******************'

class Worker(threading.Thread):
    def __init__(self, queue):
        threading.Thread.__init__(self)
        self.source_conn = S3Connection(source_aws_key, source_aws_secret_key)
        self.dest_conn = S3Connection(dest_aws_key, dest_aws_secret_key)
        self.srcBucket = self.source_conn.get_bucket(srcBucketName)
        self.dstBucket = self.dest_conn.get_bucket(dstBucketName)
        self.queue = queue

    def run(self):
        while True:
            key_name = self.queue.get()
            k = Key(self.srcBucket, key_name)
            dist_key = Key(self.dstBucket, k.key)
            if not dist_key.exists() or k.etag != dist_key.etag:
                print 'copy: ' + k.key
                self.dstBucket.copy_key(k.key, srcBucketName, k.key, storage_class=k.storage_class)
            else:
                print 'exists and etag matches: ' + k.key

            self.queue.task_done()

def copyBucket(maxKeys = 1000):
    print 'start'

    s_conn = S3Connection(source_aws_key, source_aws_secret_key)
    srcBucket = s_conn.get_bucket(srcBucketName)

    resultMarker = ''
    q = LifoQueue(maxsize=5000)

    for i in range(10):
        print 'adding worker'
        t = Worker(q)
        t.daemon = True
        t.start()

    while True:
        print 'fetch next 1000, backlog currently at %i' % q.qsize()
        keys = srcBucket.get_all_keys(max_keys = maxKeys, marker = resultMarker)
        for k in keys:
            q.put(k.key)
        if len(keys) < maxKeys:
            print 'Done'
            break
        resultMarker = keys[maxKeys - 1].key

    q.join()
    print 'done'

if __name__ == "__main__":
    copyBucket()

要将对象从一个 S3 存储桶复制到另一个 S3 存储桶,您需要使用一组可以访问两个存储桶的 AWS 凭证。

如果这些存储桶位于不同的 AWS 账户中,您需要两件事:

  1. 目标 存储桶的凭据,以及
  2. 源存储桶上的存储桶策略允许对目标 AWS 账户进行读取访问。

仅凭这些,您就可以复制对象。您不需要源帐户的凭据。

  1. 将存储桶策略添加到您的 source 存储桶,允许对目标 AWS 账户进行读取访问。

这是一个示例政策:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "DelegateS3Access",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::123456789012:root"
            },
            "Action": "s3:*",
            "Resource": [
                "arn:aws:s3:::BUCKET_NAME",
                "arn:aws:s3:::BUCKET_NAME/*"
            ]
        }
    ]
}

请务必将 BUCKET_NAME 替换为您的 source 存储桶名称。并将 123456789012 替换为您的 target AWS 帐号。

  1. 使用您的目标 AWS 账户(目标存储桶的所有者)的凭据,执行复制。

补充说明:

你也可以通过颠倒两个要求来复制对象:

  1. 源 AWS 账户的凭证,以及
  2. 目标存储桶上的存储桶策略允许 写入 访问源 AWS 账户。

但是,以这种方式完成后,对象元数据无法正确复制。我已经和AWS Support讨论过这个问题,他们建议从国外账户读取而不是写入国外账户来避免这个问题。