Как поместить объекты S3 из другой учетной записи AWS в корзину S3 своей учетной записи, используя роль «Взять на себя»? - PullRequest
0 голосов
/ 22 июня 2019

У меня довольно типичный случай использования, когда мне предоставлена ​​роль в учетной записи 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 голосов
/ 22 июня 2019

( TL; DR В самом конце описан способ настройки разрешений, более простой, чем использование ролей!)

Самый простой способ перемещения данных между сегментами - использовать copy_object() команда.Эта команда отправляется в целевое хранилище и «извлекает» информацию из исходного хранилища.

Это немного усложняется, когда задействованы несколько учетных записей AWS, поскольку один и тот же набор учетных данных требует GetObject разрешение на исходную корзину AND 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 также должен разрешить запись (см. Ниже Bucket Policy).

  • Created 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 Policy на 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
  • Это, очевидно, намного проще, чем взять на себя роль
...