6
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Athenaで別アカウントのS3をクエリーする最短手順

Last updated at Posted at 2021-03-16

やりたいこと

別アカウントのS3バケットにあるデータをAthenaからクエリーしたい。
別アカウント側のGlueカタログ(Glueのクロスアカウントアクセス)は使わず、あくまで自アカウントのGlueカタログに別アカウントのS3バケットを登録して、検索を実行するのがゴール。

前提

  • アカウントA:読み取られる側
  • アカウントB:読み取る側

とする。
こんなイメージ。
スクリーンショット 2021-03-13 午前1.05.53.png

ステップバイステップ

アカウントAの準備

  • S3バケットを作成し、テストデータを置く。
    • バケット名はathena-crossaccount-20210310とする。
    • テストデータはこちらの記事で使用したものを再利用する。
  • クロスアカウントアクセスを許可するため、バケットポリシーを設定する。
    • アカウントBでこの後作成されるIAMロールに対してのみ許可する。ロール名はAthenaCrossAccountRoleと仮定。

(2021/6/2追記)
存在していないロールをバケットポリシーに入れることはできないので、この手順は正しくは「アカウントBの準備」でAthenaCrossAccountRoleを作成した後に実行するか、バケットポリシー保存直前で寸止めしておく必要があります。
(ご指摘いただいた@cols-wisteriaさん、ありがとうございました!)

バケットポリシー
{
    "Version": "2012-10-17",
    "Id": "Policy1495458089866",
    "Statement": [
        {
            "Sid": "Policy_GetObject",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::2XXXXXXXXXX2:role/AthenaCrossAccountRole"
            },
            "Action": [
                "s3:GetObject",
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::athena-crossaccount-20210310",
                "arn:aws:s3:::athena-crossaccount-20210310/*"
            ]
        }
    ]
}

アカウントBの準備

  • クエリー結果保管バケットを作り、Athenaワークグループ"primary"(デフォルト)にセットする。
    • ここではathena-query-result-4-sandboxとした。
  • Athenaでクエリーを実行するためのIAMポリシーAthenaCrossAccountAccessPolicy を作成する。
    • AmazonAthenaFullAccessというマネージドポリシーがあるので、これを参考に作る。
    • ちなみに上記のマネージドポリシーはs3:GetObject権限がチュートリアル用バケットと(デフォルト仕様の)クエリー結果保管バケットにしかないので、そのままでは現場で使えない。他にもせっかく絞ったs3:ListBucketが後段で全開放されてたりと若干つっこみどころの多いポリシーだが、ここでは細かいことは措いて先に進むことにする。
  • IAMロールAthenaCrossAccountRoleを作成し、上記ポリシーをアタッチする。
    • IAMロールではなくIAMユーザーにアタッチしてもよいが、今回は多少汎用性を高める必要があったのでロールとし、このロールにアカウントAからスイッチロールできるように設定(アカウントAをAssumeRoleの信頼元Principalに指定)した。
    • 実際には、ロールの信頼元をEC2やLambdaに指定して、プログラマティックにAthenaを呼び出すイメージ。
Athena用ポリシー
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "athena:*"
            ],
            "Resource": [
                "*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "glue:CreateDatabase",
                "glue:DeleteDatabase",
                "glue:GetDatabase",
                "glue:GetDatabases",
                "glue:UpdateDatabase",
                "glue:CreateTable",
                "glue:DeleteTable",
                "glue:BatchDeleteTable",
                "glue:UpdateTable",
                "glue:GetTable",
                "glue:GetTables",
                "glue:BatchCreatePartition",
                "glue:CreatePartition",
                "glue:DeletePartition",
                "glue:BatchDeletePartition",
                "glue:UpdatePartition",
                "glue:GetPartition",
                "glue:GetPartitions",
                "glue:BatchGetPartition"
            ],
            "Resource": [
                "*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetBucketLocation",
                "s3:GetObject",
                "s3:ListBucket",
                "s3:ListBucketMultipartUploads",
                "s3:ListMultipartUploadParts",
                "s3:AbortMultipartUpload",
                "s3:CreateBucket",
                "s3:PutObject"
            ],
            "Resource": [
                "arn:aws:s3:::athena-query-result-4-sandbox",
                "arn:aws:s3:::athena-query-result-4-sandbox/*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetObject",
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::athena-crossaccount-20210310",
                "arn:aws:s3:::athena-crossaccount-20210310/*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket",
                "s3:GetBucketLocation",
                "s3:ListAllMyBuckets"
            ],
            "Resource": [
                "*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "sns:ListTopics",
                "sns:GetTopicAttributes"
            ],
            "Resource": [
                "*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "cloudwatch:PutMetricAlarm",
                "cloudwatch:DescribeAlarms",
                "cloudwatch:DeleteAlarms"
            ],
            "Resource": [
                "*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "lakeformation:GetDataAccess"
            ],
            "Resource": [
                "*"
            ]
        }
    ]
}
  • Glueデータベースを作成する。
  • Glueデータベースは、Crawlerを使う場合もAthenaでDDLを実行する場合も、テーブルを格納するために等しく必要。
  • ここではathena_crossaccount_20210310とする。
  • DDLを実行する。
  • テーブルについては、CrawlerかDDL(あるいはCloudFormationか)のどちらかだけ必要。
  • JSONLであればCrawlerで自動認識されるスキーマでほぼほぼ無修正で行けるはずだが、ここではAthena単体でどういう権限が必要かを切り分けたいので、あえてDDLで作成する。
  • SerdeにはHiveとOpenXが選択可能だが、Glue Crawlerでは後者が使われていること、実際にクエリーしてみるとOpenXの方がエラーが少ないことから、ここではOpenXを選択。
CREATE EXTERNAL TABLE jsontest (
	id int,
	name string,
	age int
)
ROW FORMAT serde 'org.openx.data.jsonserde.JsonSerDe'
with serdeproperties ( 'paths'='age, id, name' )
LOCATION 's3://athena-crossaccount-20210310/';

クエリー実行

  • マネジメントコンソールで、アカウントAから、アカウントBのAthenaCrossAccountRoleにスイッチ。
  • Athenaでクエリーを実行。
  • 成功。
    スクリーンショット 2021-03-16 午後5.18.26.png

ハマリポイント

  • SerdeをHiveで作成すると、このデータセットではエラーとなった(nullが原因かも)。OpenXの方が融通利く模様。
  • Glueカタログを介して外部テーブルを読みに行く以上、Glueサービスロールにもクロスアカウント権限が必要か?とも思ったが、Glue CrawlerやGlue Jobを使わない限りはそもそもそのロール使わないので、今回試したロールのみバケットポリシーで許可すればOKだった。
  • 今回はAthena、というかAthenaの実行主体であるIAMロール(AthenaCrossAccountRole)は、クロスアカウントアクセスにassumeRoleを使ってない(あくまで検証上、アカウントBにスイッチする際にassumeRoleしているだけで、クロスアカウントのクエリー自体はS3のリソースベースポリシーを介して、ロールをスイッチすることなく実行されている)。assumeRoleを用いるパターンだと、sts:AssumeRoleの付与やリソース/プリンシパル縛りなど、これはこれで細々とした設定が必要になる。はず。
6
4
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?