AWS Athena: перекрестная запись результатов запроса CTAS - PullRequest
1 голос
/ 25 июня 2019

У меня большой исторический набор данных в учетной записи 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, я уже реализовал логику, которая автоматически отправляет новые запросы и выполняет некоторые дополнительные действия, например, Обновление пункта назначения Клеевая таблица и регистрация. Поэтому включить эти строки кода довольно просто.

Ответы [ 2 ]

0 голосов
/ 26 июня 2019

В настоящее время единственный способ сделать это чисто - это использовать роль IAM в учетной записи A с политикой доверия, которая позволяет учетной записи B принять эту роль. Вы упоминаете, что это невозможно для вашего случая, что вызывает сожаление. Причина, по которой в настоящее время это невозможно каким-либо другим способом, заключается в том, что Athena не будет записывать файлы с параметром «bucket-owner-full-control», поэтому учетная запись A никогда не будет полностью владеть файлами, созданными действием, инициированным ролью в учетной записи B .

Поскольку политика, предоставленная вами в целевом контейнере, разрешает все, одну вещь, которую вы можете сделать, это запустить задачу после завершения операции CTAS, которая перечисляет созданные объекты и копирует каждый в себя (одинаковые ключи источника и назначения) с опция ACL "ведро-владелец-полный контроль". Подобное копирование объекта является обычным способом изменения свойств хранилища и ACL объектов S3. Это, как вы говорите, повлечет за собой дополнительные расходы, но они будут незначительными по сравнению с расходами CTAS и расходами, связанными с будущими запросами к данным.

Настоящим недостатком является то, что нужно написать что-то для запуска после операции CTAS и координировать это. Я предлагаю рассмотреть пошаговые функции, чтобы сделать это, и вы можете создать довольно приятные рабочие процессы, автоматизирующие Athena, и запуск которых обходится совсем недорого. У меня есть приложения, которые более или менее точно выполняют то, что вы пытаетесь сделать, используя пошаговые функции, лямбду и Афину, и стоите копейки (хотя я использую роли IAM для работы с несколькими учетными записями).

0 голосов
/ 26 июня 2019

Я бы порекомендовал вам выполнить копию.

«Дополнительные запросы GET и PUT» будут незначительными:

  • GET составляет $ 0,0004 за 1000 запросов
  • PUT составляет $ 0,005 за 1000 запросов

В качестве альтернативы вы запускаете команду aws s3 cp --recursive из учетной записи B, чтобы скопировать файлы себе (да!) Со сменой владельца (это также требует другого изменения, например, настройки метаданных, которые будут приняты в качестве команды копирования). Это похоже на то, что вы предлагали с put-object-acl.

...