AWS提供对其他帐户的假定角色的访问权限,以访问我帐户中的S3

时间:2016-08-05 12:47:20

标签: amazon-web-services amazon-s3 amazon-iam amazon-data-pipeline

我想要实现的是将一个帐户中的S3(A1 - 不受我控制)中的对象复制到另一个帐户中的S3(A2 - 由我控制)。 因为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中运行此脚本,例如。

2 个答案:

答案 0 :(得分:2)

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

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

  1. 目标存储桶的凭据和
  2. 源存储桶上的存储桶策略,允许对目标AWS账户进行读访问。
  3. 单独使用这些,您可以复制对象。您不需要源帐户的凭据。

    1. 向您的来源存储桶添加存储桶策略,允许对目标AWS账户进行读取访问。
    2. 以下是一个示例政策:

      {
          "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。并将123456789012替换为目标 AWS账号。

      1. 使用目标 AWS账户(目标存储桶的所有者)的凭据,执行复制。
      2. 附加说明:

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

        1. 源AWS账户的凭据和
        2. 目标存储桶上的存储桶策略,允许写入访问源AWS账户。
        3. 但是,这样做时,对象元数据不会被正确复制。我已经通过AWS Support讨论了这个问题,他们建议您从国外帐户读取而不是写入国外帐户以避免此问题。

答案 1 :(得分:1)

这是使用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()