🔐

RedashからAthenaへ接続する際にIAM Access Keyを発行せずに接続する

2023/09/15に公開

スターフェスティバル株式会社 の バックエンドエンジニアの @ikkitang です。

今回、Athena上に構築したテーブルに対して、それをRedashから参照出来るように環境構築をしました。
RedashからAthenaに接続するのは、公式からサポートがあってシュッと実現することが出来るのですが、以下の画像のように IAM を構築した上でAWS Access KeyとAWS Secret Keyを指定する必要があります。

RedashからAthenaへの接続設定の画面の画像 AWS Access KeyとAWS Secret Keyの入力フィールドがある

Access Keyを指定することで接続出来ることは楽である反面、漏洩によるリスクなどを鑑みるなら取りたくない手段だと考えており、他に方法が無いかを模索しておりました。

ググる中で以下の記事を発見し、試してみた所、これにより実現することが出来ました!
https://dev.classmethod.jp/articles/redash-datasource-with-athena-by-assumerole/

本記事は、RedashからAthenaへ接続するタスクを進める際にハマったこと、またSwitchするIAM Roleについて最小限の権限を与えたい時に指定する権限についてまとめておきます。

RedashからAthenaへ接続する設定をする

ATHENA_ASSUME_ROLE を着けた際には、設定画面が以下のように変化します。Access KeyやSecret Keyが指定されていた所はIAM role to assumeと変化しました。

ATHENA_ASSUME_ROLEをつけたときのRedashからAthenaへの接続設定画面

SwtichするためのRoleを定義する / それらを接続設定の画面に登録する という2つをやるとやりたいことが実現出来そうです。

RedashからAthenaへ接続する際にSwitchするRoleを定義する

実行にあたっては、この辺りの記事を参考にさせていただきました。

https://dev.classmethod.jp/articles/query-and-visualize-data-from-amazon-athena-with-redash/
https://repost.aws/ja/knowledge-center/access-denied-athena

取り敢えず、Athena辺りの権限、S3の権限が必要そうということがわかります。

権限を絞っていくにあたって、必要な権限に検討を着けていきます。今回のAthenaの構成としては以下のような構成になっておりまして、今回権限が必要なのは分析レイヤーのRedash -> Athenaの部分です。

全体のアーキテクチャ像

Redashはデータ活用をしたい方々(主にAthenaについて詳しく無い人)が使うことを想定しているので、基本はRead Onlyのクエリのみを投げる想定なので、Write権限的なものはいらないという点を考慮する必要がありそうです。

ということで作成したものはこのような IAM 権限でした。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "athena:ListEngineVersions",
                "athena:ListDataCatalogs"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "athena:GetTableMetadata",
                "athena:GetQueryResults",
                "athena:GetQueryExecution",
                "athena:GetDatabase",
                "athena:GetDataCatalog",
                "athena:GetQueryResultsStream",
                "athena:ListDatabases",
                "athena:ListTableMetadata",
                "athena:ListQueryExecutions",
                "athena:StartQueryExecution",
                "athena:StopQueryExecution",
                "glue:BatchGetPartition",
                "glue:GetTables",
                "glue:GetDatabases",
                "glue:GetTable",
                "glue:GetDatabase",
                "glue:GetPartition",
                "glue:GetPartitions",
                "s3:ListBucket",
                "s3:PutObject",
                "s3:GetObject",
                "s3:GetBucketLocation",
                "s3:AbortMultipartUpload",
                "s3:ListMultipartUploadParts",
                "s3:ListBucketMultipartUploads"
            ],
            "Resource": [
                "arn:aws:s3:::athena-query-log-bucket/*",
                "arn:aws:s3:::athena-query-log-bucket",
                "arn:aws:athena:ap-northeast-1:999999999999:datacatalog/app-logs",
                "arn:aws:athena:ap-northeast-1:999999999999:workgroup/*",
                "arn:aws:glue:ap-northeast-1:999999999999:table/app-logs/*",
                "arn:aws:glue:ap-northeast-1:999999999999:database/app-logs",
                "arn:aws:glue:ap-northeast-1:999999999999:catalog"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetObject",
                "s3:ListBucket",
                "s3:GetBucketLocation"
            ],
            "Resource": [
                "arn:aws:s3:::log_保存_bucket",
                "arn:aws:s3:::log_保存_bucket/*"
            ]
        }
    ]
}

リソースを指定している部分は以下です。

  • S3
    • arn:aws:s3:::log_保存_bucket: Athenaが集計の対象とするS3Bucket
    • arn:aws:s3:::athena-query-log-bucket: Athenaのクエリログを保存するS3Bucket
  • Glue
    • arn:aws:glue:ap-northeast-1:999999999999:catalog:自身のAWSアカウントで管理しているデータベース・テーブルのメタデータ
    • arn:aws:glue:ap-northeast-1:999999999999:database/app-logs:今回のログの集計を管理するデータベース名
    • arn:aws:glue:ap-northeast-1:999999999999:table/app-logs/*:今回のログの集計を管理するデータベース内のテーブルリスト
  • Athena
    • arn:aws:athena:ap-northeast-1:999999999999:datacatalog/app-logs: 今回のログの集計を管理するデータベース名(AthenaのData CatalogはGlue Databaseと一致する)
    • arn:aws:athena:ap-northeast-1:999999999999:workgroup/*:今回は primary しか準備しませんが、Athenaのクエリ実行環境の分割単位です

消して、Redashからリクエストして怒られたらつけ直すみたいなトライ&エラーをしたのですが、大分絞ることが出来ました。

ハマり所として、参考にしたブログをちゃんと読めば書いてあるんですが、S3の権限でAthenaが集計の対象とするS3Bucketとクエリログを保存するS3Bucket、それぞれに対して権限を設定する必要がありました。 最初、クエリログを保存するS3Bucketにしか権限を付与してなかったので、全バケットに対して権限付与だと通るのにクエリログを保存するBucketに限定したらコケるという現象でハマってました。

Athena上のクエリエディタから実行する時は特にS3への参照権限などの設定はしなかったので、おそらく、クエリ実行のAPIを実行する際のロールによってこの辺りの権限が決まるのだろうな、と思います。 ログインユーザーはS3への書き込み権限の許可がされているので特に許可無く通ったように見えるけど、Redashがクエリ実行のAPIを実行する際には何も指定しないとS3の書き込み権限が無いので、コケるということかと。

ということで上記のポリシーを redash-athena-execution-role などとして登録されている状態にします。

Redashを動かしているECSのタスクロールでSwitch Roleの権限を付与する

RedashのAssume Role Arnに登録を進めたいのですが、そのままやるとSwitch Role権限が無くて、接続に失敗しました。これを解消するために、ECSのタスクロールにSwitch Role権限をつけていきます。説明の都合上、ECSのタスクロールを redash-execution-task-role とします。

やることは https://blog.serverworks.co.jp/switch-role#スイッチロールの手順 辺りを参考にしました。

まずは、スイッチ先のロール redash-athena-execution-role 側の修正です。信頼されたエンティティに以下のようにRedashのタスクロールがSwitch出来る権限を付与します。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "その他の権限があれば"
            },
            "Action": "sts:AssumeRole"
        }
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::99999:role/redash-execution-task-role"
            },
            "Action": "sts:AssumeRole"
        }
    ]
}

続いて、スイッチ元の redash-execution-task-role です。Switch Role権限をもらったので、それを使用しても良い権限を与えます。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "sts:AssumeRole",
            "Resource": "arn:aws:iam::99999:role/redash-athena-execution-role"
        }
    ]
}

これで準備が整いました。(デプロイしなおして、ロールを切り替えます)

RedashのData SourceにAthenaを追加して集計を開始する

大体全部設定が終わったのでいよいよ設定にうつっていきます。

RedashのNew Data Sourceの設定画面から、AthenaのData Sourceを選択し、以下のように入力します。

設定の画面、全ての情報が入力された状態

ハマりどころも書いておきます。
設定していて ✅ というマークでバリデーションが通っているように見えますが、実際にはRedashが想定している正しい入力ではないパターンがよくありました。

  • IAM role to assume
    • ARN で設定する必要がありました。 最初ロール名で指定してたので、何故かうまくいかなくてハマりました。
  • S3 Query Result Bucket Path
    • s3://athena-query-log-bucket/redash の形式で書く必要がありました。
    • 最初 バケット名だけ指定してたので、うまくいかなくてハマりました。(よくみたら、バケットパス って書いてますね)

ということで保存し、Test Connectionもパス出来たのでめでたしでした。

まとめ

小一時間ハマったのですが、なんとか達成出来てよかったです。
結構調べていく中で情報が古かったり、これで正しいんだっけ?みたいな不安があったので、一度まとめてみました!
何かの参考になれば幸いです。

スタフェステックブログ

Discussion