AthenaでクロスアカウントのGlue データカタログを参照する

これはなに?

Athenaを利用して別AWSアカウントにあるGlueデータカタログの参照を実施してみます。
通常別AWSアカウントのデータカタログはAthenaで利用できないのですが、2019年にリリースされたAthenaでの外部メタストアの参照機能を利用することで実現できます。

大まかな手順はAWS公式と同様ですが、そのままだとできない部分があったので追記&修正しています。
Amazon Athena を使用したクロスアカウントの AWS Glue データカタログ | Amazon Web Services ブログ

実現したいこと

f:id:ykoomaru:20201208224927p:plain

Account Aにあるデータカタログ及びデータソース(S3)の情報をAccount BのAthenaを使ってクエリする。 AWSがテンプレートを提供しているLambdaがプロキシとなることで、別AWSアカウントのデータカタログをAthenaで参照することができるようになるようです。

検証条件

以下の条件で検証を実施します。

【アカウント構成/リソース情報】
Account A [us-east-1]: Glueデータカタログ/データソース(S3)
Account B [us-east-1]: Athena実行

【ゴール】
Account BでAthenaを実行し、Account Aのデータカタログを使って、データソースの情報をクエリできること

手順

データカタログの作成及びAthenaの初期セットアップについては割愛しています。

1. Lambdaのデプロイ【Account B作業】

① 以下のCfnのテンプレートより、Lambdaをデプロイします
https://console.aws.amazon.com/cloudformation/home?region=us-east-1#/stacks/create/review?templateURL=https://aws-bigdata-blog.s3.amazonaws.com/artifacts/aws-blog-cross-account-athena/cross_account_athena_stack.yaml

<パラメータ値>

項目名
GlueDataCatalogAccountID Account AのAWSアカウントID
Region us-east-1
※固定
DatabaseName Account AのGlueデータカタログのデータベース名
TableName Account AのGlueデータカタログのテーブル名
※全てのテーブルの利用を許可する場合は、「*」

② Lambdaデプロイ後にCfnで出力されている「CrossAccountPrincipal」の値をメモします

f:id:ykoomaru:20201209091257p:plain

2. Glueデータカタログ アクセス権設定【Account A作業】

①以下のGlueのリソースポリシーを設定するコマンドを実行します

自身の環境に合わせて置換してください。

項目名
CrossAccountPrincipal 1.で取得したCrossAccountPrincipalの値
ACCOUNT_ID_A Account AのAWSアカウントID
database-name Account AのGlueデータカタログのデータベース名
aws glue put-resource-policy --policy-exists-condition NOT_EXIST --policy-in-json '{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "glue:GetDatabase",
        "glue:GetDatabases",
        "glue:GetPartition",
        "glue:GetPartitions",
        "glue:GetTable",
        "glue:GetTables"
      ],
      "Principal": {"AWS": [
        "<CrossAccountPrincipal>"
      ]},
      "Resource": [
        "arn:aws:glue:us-east-1:<ACCOUNT_ID_A>:catalog",
        "arn:aws:glue:us-east-1:<ACCOUNT_ID_A>:database/<database-name>",
        "arn:aws:glue:us-east-1:<ACCOUNT_ID_A>:table/<database-name>/*"
      ]
    }
  ]
}'

3. S3 バケットポリシー設定【Account A作業】

この手順を実施することで、クロスアカウントのAthena接続できるようになります。

①Account AのGlueデータカタログのソースとなっているS3のバケットポリシーを修正します

項目名
ACCOUNT_ID_B Account BのAWSアカウントID
s3_bucket Account AのS3 バケット名
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowCrossAccountAccess",
            "Effect": "Allow",
            "Principal": {
                "AWS": [
                    "arn:aws:iam::<ACCOUNT_ID_B>:root"
                ]
            },
            "Action": [
                "s3:GetBucketLocation",
                "s3:ListBucket",
                "s3:GetObject"
            ],
            "Resource": [
                "arn:aws:s3:::<s3_bucket>",
                "arn:aws:s3:::<s3_bucket>/*"
            ]
        }
    ]
}

4 . Athena データソース設定【Account B作業】

最後にAthenaのデータソースを設定します。

①AWSコンソールより、Athenaを開き、[データソースを接続する] をクリックします f:id:ykoomaru:20201209093655p:plain

②[Amazon S3でデータのクエリを実行する] 及び [Apache Hive メタストア] を選択します f:id:ykoomaru:20201209093701p:plain

③以下の項目を選択及び入力し、[接続] をクリックします

項目名
Lambda関数 1.で作成したLambda
カタログ名 任意
説明 任意

カタログ名はクエリ実行時に利用するのでメモしておいてください。

f:id:ykoomaru:20201209093707p:plain

以上で設定は完了です。

5. クロスアカウントでのクエリ実行 【Account B作業】

最後にAthenaでクエリを実行し、結果が返ってくればOKです。

項目名
catalog_name 4.で設定したカタログ名
database_name Account AのGlueデータカタログのデータベース名
table_name Account AのGlueデータカタログのテーブル名

<サンプルクエリ>

SELECT * FROM "<catalog_name>"."<database_name>"."<table_name>" limit 10

実行結果が数行のクエリの場合は、同一アカウントとクロスアカウントで実行時間に大差ありませんでした。

その他

2020年12月時点では、クエリをプロキシするLambdaはAWSから提供されているCfnから作成するのですが、「us-east-1」でしかデプロイできませんでした。AthenaからLambdaを呼び出す場合、同一リージョンのLambdaしか呼び出せないようなので、us-east-1以外のリージョンでこの機能を利用するためには、CfnでデプロイされているLambda相当を自身で用意する必要があります。

公式からLambdaのソースコードが404で取得できなかったのですが、以下のGithubからZIPを取得し、CfnでLambdaのソースを取得したZIPにすればus-east-1以外でもAthenaをクロスアカウントで実行できました。
https://github.com/neutiyoo/athena-cross-account-access/blob/master/function/functionv3.zip

非公式ですが、us-east-1以外で利用したい場合は検証してみてください。