У меня большой исторический набор данных в учетной записи A . Этот набор данных находится в формате CSV и разделен на year/month/day/hour/
. Моя цель - преобразовать эти данные в паркет с помощью дополнительных шагов нормализации и дополнительного уровня разделения, например, year/month/day/hour/product/
, и запишите его обратно в ту же корзину аккаунта A в processed/
«директории». Так что дерево "каталогов" будет выглядеть как
S3_bucket_Account_A
dataset
|
├── raw
│ ├── year=2017
| │ ├── month=01
| | │ ├── day=01
| │ | | ├── hour=00
| │ | | └── hour=01
|
├── processed
│ ├── year=2017
| │ ├── month=01
| | │ ├── day=01
| | | │ ├── hour=00
| | │ | | ├── product=A
| | │ | | └── product=B
| | | │ ├── hour=01
| | │ | | ├── product=A
| | │ | | └── product=B
Для этого я отправляю операторы запросов CTAS в Афину с помощью API boto3. Мне известно о ограничениях запросов CTAS , например, можно записать до 100 разделов в одном запросе, местоположение результата запроса CTAS должно быть пустым / уникальным. Итак, я обрабатываю один необработанный раздел за раз, и содержимое запроса CTAS генерируется на лету с учетом этих ограничений.
Поскольку я использую учетную запись B для выполнения этих запросов CTAS, но результат этих запросов должен быть записан в корзину S3 , принадлежащую учетной записи A . Мне были предоставлены следующие разрешения, указанные на уровне политики Bucket учетной записи A.
{
"Effect": "Allow",
"Principal": {
"AWS": "__ARN_OF_ACCOUNT_B__"
},
"Action": [
"s3:*"
],
"Resource": [
"arn:aws:s3:::dataset",
"arn:aws:s3:::dataset/*"
]
}
Проблема в том, что учетная запись A (владелец корзины) не имеет доступа к файлам, которые были записаны в результате запроса CTAS, выполненного Athena учетной записи B .
Как я понимаю, для учетной записи A существует возможность создания роли IAM для меня, и тогда я выполняю эту задачу, как если бы я была учетной записью A. Но, к сожалению, об этих параметрах не может быть и речи.
Я нашел способы передачи прав собственности / изменения ACL для объектов S3. Один из способов - вывести результат запроса CTAS в корзину S3 учетной записи B, а затем скопировать эти файлы в корзину учетной записи A ( первоисточник )
aws s3 cp s3://source_awsexamplebucket/ s3://destination_awsexamplebucket/ --acl bucket-owner-full-control --recursive
Другим способом является рекурсивное обновление acl с помощью чего-то вроде ( оригинальный источник )
aws s3 ls s3://bucket/path/ --recursive | awk '{cmd="aws s3api put-object-acl --acl bucket-owner-full-control --bucket bucket --key "$4; system(cmd)}'
Но эти два варианта потребуют дополнительных GET
и PUT
запросов к S3, таким образом, больше денег для оплаты AWS. Но что более важно, я обновляю таблицу AWS Glue (таблица назначения) учетной записи A с разделами из созданной таблицы после успешного выполнения запроса CTAS. Таким образом, пользователи IAM в учетной записи A могут сразу же начать запрашивать преобразованные данные. Вот общее представление о том, как я обновляю destination_table
response = glue_client.get_partitions(
CatalogId="__ACCOUNT_B_ID__",
DatabaseName="some_database_in_account_B",
TableName="ctas_table"
)
for partition in response["Partitions"]:
for key in ["DatabaseName", "TableName", "CreationTime"]:
partition.pop(key)
glue_client.batch_create_partition(
CatalogId="__ACCOUNT_A_ID__",
DatabaseName="some_database_in_account_A",
TableName="destination_table",
PartitionInputList=response["Partitions"]
)
Я делаю это таким образом вместо MSCK REPAIR TABLE destination_table
, потому что последний по какой-то причине занимает много времени. Итак, как вы можете видеть, если я выберу aws s3 cp
, мне также нужно будет это учитывать при копировании мета-информации о разделах
Итак, мой реальный вопрос: как я могу предоставить полный контроль владельцу корзины в запросе CTAS, выполненном другой учетной записью?
Обновление 2019-06-25:
Только что нашел аналогичный пост , но похоже, что они используют роль IAM, которая не подходит для моего случая
Обновление 2019-06-27
Я обнаружил, что: 1) Невозможно изменить ACL в запросе CTAS. Вместо этого объект S3 можно скопировать на себя (благодаря комментариям Джона Ротенштейна и Тео ) с новым владельцем.
Обновление 2019-06-30
Просто подведу итог. Я запускаю запрос CTAS из account B
, но результат сохраняется в корзине, принадлежащей account A
. Вот как выглядит заголовок запроса CTAS:
CREATE TABLE some_database_in_account_B.ctas_table
WITH (
format = 'PARQUET',
external_location = 's3://__destination_bucket_in_Account_A__/__CTAS_prefix__/',
partitioned_by = ARRAY['year', 'month', 'day', 'hour', 'product']
) AS (
...
...
)
Поскольку я использую boto3
для отправки запросов CTAS и знаю __destination_bucket_in_Account_A__
вместе с __CTAS_prefix__
, то вместо успешного копирования файлов на себя с помощью aws cp
я могу напрямую изменить их ACL в том же скрипте Python после успешного выполнения. запроса CTAS.
s3_resource = aws_session.resource('s3')
destination_bucket = s3_resource.Bucket(name="__destination_bucket_in_Account_A__")
for obj in destination_bucket.objects.filter(Prefix="__CTAS_prefix__"):
object_acl = s3_resource.ObjectAcl(destination_bucket.name, obj.key)
object_acl.put(
ACL='bucket-owner-full-control'
)
Примечание , поскольку мне нужно отправить число запросов CTAS, превышающее ограничение AWS Athena, я уже реализовал логику, которая автоматически отправляет новые запросы и выполняет некоторые дополнительные действия, например, Обновление пункта назначения Клеевая таблица и регистрация. Поэтому включить эти строки кода довольно просто.