0

我試圖實現的目標是將S3中的對象從一個帳戶(A1 - 不受我控制)複製到另一個帳戶中的S3(A2 - 受控由我)。 對於A1中的OPS,我提供了一個角色,我可以使用boto3庫。AWS提供從另一個帳戶訪問假定的角色以訪問我帳戶中的S3

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數據管道內運行,例如。

回答

1

要從一個S3桶對象複製到另一個S3桶,則需要使用一個組的兩個S3桶之間傳送數據可以訪問這兩個存儲桶的AWS憑證。

如果這些分組在不同的AWS帳號,你需要兩件事情:

  1. 憑據目標桶,並
  2. 水桶政策上的源桶允許讀取目標AWS帳戶。

單憑這些,您可以複製對象。您不需要源帳戶的憑據。

  1. 添加水桶政策,您桶允許讀取目標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。並將123456789012替換爲您的目標 AWS賬號。

  1. 爲您的目標使用憑據 AWS賬戶(目標存儲桶的所有者)執行復制。

其他注意事項:

您也可以通過顛倒兩個要求複製對象:

  1. 憑據源AWS賬戶,並
  2. 目標水桶的桶和政策允許編寫訪問源AWS賬戶。

但是,這樣做時,對象元數據不會被正確複製。我已經與AWS Support討論過這個問題,他們建議閱讀外部帳戶而不是寫入外部帳戶以避免此問題。

0

這是一個示例代碼來使用2個不同的AWS帳戶博託3.

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()