Amazon Managed Grafana から別アカウントに存在する S3 バケットを Athena でクエリする

記事タイトルとURLをコピーする

こんにちは、末廣です。 皆様 Amazon Managed Grafana 使っていますでしょうか? 本ブログでは Amazon Managed Grafana から別アカウントに存在する CloudFront や ALB のログを Athena でクエリする方法を紹介します。

検証を行う環境と前提条件

  • アカウントA... ログバケットがあるアカウント
  • アカウントB... Grafana ワークスペース、Athena ワークグループがあるアカウント

として検証を行います。

また、アカウント A には CloudFront や ALB のログが出力されたバケットが、アカウント B に Grafana ワークスペースを構築済みであることを前提としています。

アカウントB での操作

Athena 実行ログバケットの作成と設定

完了していなければ実施します。

Athena クエリエディタの設定

マネジメントコンソールからクエリエディタで実行するときと同じですね。 バケット名をgrafana-athena-query-results-suehiroとして本ブログでは記載していきます。

ちなみにバケット名は grafana-athena-query-results-から始まっているとほんの少しだけ嬉しいかもしれません。

Amazon Managed Grafana のプラグイン管理を有効化

こちらはデフォルトでは無効になっているため、Grafana ワークスペースのマネジメントコンソールからワークスペース設定オプションタブを選び、プラグイン管理をオンにしましょう。

ワークスペース設定オプション

Grafana にアタッチされている IAM ロールに Athena の操作権限を記載したポリシーをアタッチ

Amazon Managed Grafana にはマネジメントコンソールからデータソースを追加するにあたって、AWS マネージドポリシーを付与することが出来ます。

データソースのポリシーの付与

しかし今回はクロスアカウントで S3 のログを操作するため、これを少し変更してカスタマーマネージドポリシーとして作成します。

以下が AWS マネージドポリシー AmazonGrafanaAthenaAccessの内容です。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "athena:GetDatabase",
                "athena:GetDataCatalog",
                "athena:GetTableMetadata",
                "athena:ListDatabases",
                "athena:ListDataCatalogs",
                "athena:ListTableMetadata",
                "athena:ListWorkGroups"
            ],
            "Resource": [
                "*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "athena:GetQueryExecution",
                "athena:GetQueryResults",
                "athena:GetWorkGroup",
                "athena:StartQueryExecution",
                "athena:StopQueryExecution"
            ],
            "Resource": [
                "*"
            ],
            "Condition": {
                "Null": {
                    "aws:ResourceTag/GrafanaDataSource": "false"
                }
            }
        },
        {
            "Effect": "Allow",
            "Action": [
                "glue:GetDatabase",
                "glue:GetDatabases",
                "glue:GetTable",
                "glue:GetTables",
                "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",
                "s3:PutBucketPublicAccessBlock"
            ],
            "Resource": [
                "arn:aws:s3:::grafana-athena-query-results-*"
            ]
        }
    ]
}

これを別アカウントの S3 にアクセスできるようバケット情報を追加し、カスタマーマネージドポリシーとします。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "athena:GetDatabase",
                "athena:GetDataCatalog",
                "athena:GetTableMetadata",
                "athena:ListDatabases",
                "athena:ListDataCatalogs",
                "athena:ListTableMetadata",
                "athena:ListWorkGroups"
            ],
            "Resource": [
                "*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "athena:GetQueryExecution",
                "athena:GetQueryResults",
                "athena:GetWorkGroup",
                "athena:StartQueryExecution",
                "athena:StopQueryExecution"
            ],
            "Resource": [
                "*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "glue:GetDatabase",
                "glue:GetDatabases",
                "glue:GetTable",
                "glue:GetTables",
                "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",
                "s3:PutBucketPublicAccessBlock"
            ],
            "Resource": [
                "arn:aws:s3:::grafana-athena-query-results-suehiro",
                "arn:aws:s3:::grafana-athena-query-results-suehiro/*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetObject",
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::account-a-no-alb-log",
                "arn:aws:s3:::account-a-no-alb-log/*"
            ]
        }
    ]
}

60 行目の Resource 句にはじめに作成した Athena 実行ログバケット名を入力します。上記でバケット名について「ほんの少しだけ嬉しいかもしれません」と書いたのは AWS マネージドポリシーの grafana-athena-query-results-*で記載しても問題なく通るからです。と話をするとお気づきかもしれませんが、AWS マネージドポリシーをそのまま利用する場合は Athena 実行ログバケット名を grafana-athena-query-results-*とする必要があるので注意です。

71 行目の Resource 句には アカウント A に存在する ALB や CloudFront のログバケット名を入力します。

つまずきポイント

AWS マネージドポリシーの 31 行目にある Condition 句を消して例としています。もちろんつけたままでも問題ありませんが、その場合は以下のように Athena のワークグループにリソースタグをつける必要がある点忘れないようにしましょう…ということは AWS マネージドポリシーをそのまま使う場合はこの操作は必須ということです。

リソースタグの付与

Athena でテーブルを作成

Grafana でクエリを実行する前に、Athena のクエリエディタでCloudFront や ALB のテーブルを作成します。

docs.aws.amazon.com

docs.aws.amazon.com

各公式ドキュメントを参考にテーブルを作成してください。

アカウントA での操作

ログが存在しているバケット(例ではバケット名 account-a-no-alb-log)にバケットポリシーを追加します。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Policy_GetObject",
            "Effect": "Allow",
            "Principal": {
                "AWS": [
                    "arn:aws:iam::xxxxxxxxxxxx:role/service-role/AmazonGrafanaServiceRole-xxx"
                ]
            },
            "Action": [
                "s3:GetObject",
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::account-a-no-alb-log",
                "arn:aws:s3:::account-a-no-alb-log/*"
            ]
        }
    ]
}

arn:aws:iam::xxxxxxxxxxxx:role/service-role/AmazonGrafanaServiceRole-xxxの部分へ Grafana にアタッチされている IAM ロールを入力します。

Grafana IAM ロール

ALB のログバケットの場合、ログの出力のために既にポリシーが記載されていると思うのでポリシーを追加する形で行いましょう。

Grafana での操作

データソースの追加

Add new connection から Athena をインストール、Add new data source を押下し、データソースを追加します。

Athena インストール

Athena データソース追加

上記でクエリエディタからテーブルを作成したデータベースの情報を入力し、一番下に Athena 実行ログバケット名を入力します。

データソース情報の入力

クエリの実行

ダッシュボードの編集からパネルを追加し、Grafana から Athena のクエリを実行することができました。

Grafana からクエリの実行

ログのタイムラグ

Grafana を挟んでいる分タイムラグが気になりますが、Athena のクエリ実行を行っているだけなので、マネジメントコンソールから Athena を実行する場合とタイムラグは変わらないと思います。 CloudFront の標準ログは 1 時間以内 に配信・最大で24 時間遅れる、 ALB のログは 5分に1回配信・5分程度のタイムラグが発生する点を注意してクエリの実行やグラフ化を実施しましょう。

おまけ Terraform

もしかしたら Amazon Managed Grafana を Terraform で管理されているかもしれません。 同じ IaC の CloudFormation であれば、PluginAdminEnabled パラメータを有効にすれば良いですが、Terraforma の場合は少し工夫が必要でしたので紹介します。

registry.terraform.io

Grafana Workspace の configuration の引数を使います。 Terraform ドキュメントには AWS ドキュメントのリンクを参考にしてと記載があります。試してみると、Amazon Managed Grafana API の部分をほとんどそのまま使えました。

resource "aws_grafana_workspace" "suehiro" {
  name                      = "AmazonManagedGrafana"
  grafana_version           = 10.4
  account_access_type       = "CURRENT_ACCOUNT"
  authentication_providers  = ["SAML"]
  data_sources              = ["CLOUDWATCH"]
  notification_destinations = []
  permission_type           = "SERVICE_MANAGED"
  role_arn                  = "arn:aws:iam::xxxxxxxxxxxx:role/service-role/AmazonGrafanaServiceRole"
  configuration             = "{ \"unifiedAlerting\": { \"enabled\": true }, \"plugins\": { \"pluginAdminEnabled\": true }}"
}

10 行目 configuration = を json の string 形式で指定する形になっています。これで Grafana アラート と Plugin 管理を明示的にしていすることができました。この部分を記載しないとデフォルトで両パラメータは無効になって作成されるため、Terraform で Grafana を管理されている方は明示的に有効化しましょう。

まとめ

本ブログでは、Amazon Managed Grafana から別アカウントに存在する CloudFront や ALB のログを Athena でクエリする方法を紹介しました。 「運用面のツールを一つに集約したい」といった要件等、AWS マネジメントコンソールを開くことなく Athena の実行ができ、さらにグラフにも落とし込める Grafana はもってこいだと思いました。

AWS マネージドポリシーにも少し落とし穴があるなどと、検証中もすこし戸惑うこともありましたが、Grafana ライフを過ごしている方に役立てれば幸いです。では、よい Grafana ライフを。

末廣 満希(執筆記事の一覧)

2022年新卒入社です。ここに何かかっこいい一言を書くことができるエンジニアになれるように頑張ります。