CloudFront のオリジンに EC2 を置いてアクセスログを Athena で分析してみた②

CloudFront のオリジンに EC2 を置いてアクセスログを Athena で分析するまでをやってみました。今回は Lambda 〜 Athenaを動かすまでとなります。
2022.01.14

買ったばかりの Nintendo Switch を持て余している Funa です。
さて前回は CloudFront のオリジンに EC2 を置いてアクセスログを取得するところまでを記事にしました。

今回は Lambda で S3 オブジェクトの配置を整えて Athena を使って分析するところまでを書いていきたいと思います。 先人の素晴らしい記事が既に出ていますので、そちらを参考に設定を行います(ありがとうございます)。

CloudFront

前回の記事で CloudFront のログ記録を有効化しました。そのログプレフィックスの箇所にディストリビューションドメイン名を入力します。

CloudFrontログPrefix

IAM

Lambda 関数で使用するための IAM ロールを作成します。
IAM コンソールに移動して「ロールを作成」を選択します。

IAMロール作成

信頼されたエンティティの種類を選択で「AWS サービス」、ユースケースの選択で「Lambda」を選択します。

Lambdaを信頼されたエンティティに

ポリシー選択とタグ追加をスキップして、ロール名を付けて「ロールの作成」をクリックします。

IAMロールのレビュー

作成したロール名をクリックしてロールの詳細ページに飛びます。そして「インラインポリシーの追加」をクリックします。

インラインポリシーの追加

JSON のタブを選択し、以下のポリシーを設定します。
【CloudFrontのログを出力するS3バケット名】の部分は自身の S3 バケット名に変更してください。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": "arn:aws:logs:*:*:*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket",
                "s3:GetObject",
                "s3:PutObject",
                "s3:DeleteObject"
            ],
            "Resource": [
                "arn:aws:s3:::【CloudFrontのログを出力するS3バケット名】",
                "arn:aws:s3:::【CloudFrontのログを出力するS3バケット名】/*"
            ]
        }
    ]
}

IAM ポリシーの名前を入力し、「ポリシーの作成」をクリックします。

IAMポリシーの確認

作成した IAM ロールにインラインポリシーがアタッチできていれば OK です。

Lambda

Lambda 関数の作成

ログ保存先の S3 バケットがオレゴンリージョンに存在するため、Lambda も同じくオレゴンで作成していきます。まずは「関数の作成」をクリックします。

Lambda関数の作成

「一から作成」を選択し、関数名をつけます。ランタイムは Python 3.6 を選択します。

Lambda関数の作成2

アクセス権限の下の「デフォルトの実行ロールの変更」をクリックし、「既存のロールを使用する」を選択します。先ほど作成した IAM ロールをここで選択します。そして「関数の作成」をクリックします。

既存ロール

弊社ブログ記事に記載のコードをエディタにペーストします。そして「Deploy」をクリックします。

デプロイ

Lambda 設定の変更

設定タブを開いて左側のナビゲーションより「環境変数」を選択して「編集」をクリックします。

環境変数

ORIGIN_BUCKET_NAME に S3 ログバケット名
ORIGIN_BUCKET_KEY に S3 ログバケットのプレフィックス
TARGET_BUCKET_NAME に S3 ログバケット名
TARGET_BUCKET_KEY に archive/
を環境変数として設定して保存します。

環境変数の編集

次に左側のナビゲーションより「トリガー」を選択して「トリガーを追加」をクリックします。

トリガーの追加

トリガーに「S3」を選択します。バケットはログ保存先のバケット名を指定します。
イベントタイプは「PUT」を指定し、プレフィックスは S3 ログバケットのプレフィックスを指定します。

トリガーの追加2

再帰呼び出しについての忠告にチェックマークを入れ、「追加」を選択します。

S3

まずは CloudFront のドメイン名をブラウザで叩いてアクセスログが作成されるようにします。

CloudFrontからのテスト

対象の S3 バケットを開いて、オブジェクトの配置が変わっていることを確認します。
無事に日付ごとの配置に変わっておりました!

構成変更確認

構成変わりました

Athena

ようやく Athena の出番となります!
Athena のコンソールを開いて「クエリエディタを詳しく確認する」を選択します。

クエリエディタを開く

まだ一度も Athena を使用したことがないと、クエリ結果の保存先となる S3 バケットを設定する必要があります。「設定を表示」をクリックします。

クエリ結果の場所の設定

クエリ結果保存先となる S3 バケットを作成しておいたので、そのバケット名をここで指定します。
これを保存すれば準備は完了です。

クエリ結果用バケットを指定

CloudFront のログ用のテーブルを作成するため、以下のステートメントをクエリエディタに貼り付けて実行をクリックします。
「cloudfront_logs20220107」の部分がテーブル名になりますので、任意の名前に変更してください。
また、CloudFront のログを出力する S3 バケット名の箇所についても同様です。

CREATE EXTERNAL TABLE IF NOT EXISTS default.cloudfront_logs20220107 (
  `date` DATE,
  time STRING,
  location STRING,
  bytes BIGINT,
  request_ip STRING,
  method STRING,
  host STRING,
  uri STRING,
  status INT,
  referrer STRING,
  user_agent STRING,
  query_string STRING,
  cookie STRING,
  result_type STRING,
  request_id STRING,
  host_header STRING,
  request_protocol STRING,
  request_bytes BIGINT,
  time_taken FLOAT,
  xforwarded_for STRING,
  ssl_protocol STRING,
  ssl_cipher STRING,
  response_result_type STRING,
  http_version STRING,
  fle_status STRING,
  fle_encrypted_fields INT,
  c_port INT,
  time_to_first_byte FLOAT,
  x_edge_detailed_result_type STRING,
  sc_content_type STRING,
  sc_content_len BIGINT,
  sc_range_start BIGINT,
  sc_range_end BIGINT
)
PARTITIONED BY ( `year` string, `month` string, `day` string )
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
LOCATION 's3://【CloudFrontのログを出力するS3バケット名】/'
TBLPROPERTIES ( 'skip.header.line.count'='2' )

テーブルの作成が完了すると、以下のようになります。

athenaのテーブル作成

次にパーティションを手動で追加しますので以下のクエリをエディタに貼り付けて実行します。
上で設定したパーティションに合わせて年、月、日を入れ込みました。location の後に記載するパスは S3 オブジェクトの配置変更後のものとします。

ALTER TABLE cloudfront_logs20220107 ADD PARTITION (year='2022',month='01',day='07') location 's3://2022-0102-ore-cloudfront-logs/archive/2022/01/07/'

2022年1月7日 のデータが追加されているデータを抽出するため、以下のクエリを実行します。

SELECT * FROM default."cloudfront_logs20220107" WHERE year = '2022' and month ='01' and day ='07' limit 10

無事に 2022年1月7日 のデータのみを抽出できました!

クエリ結果

最後に

Athena をちゃんと使ったことがなかったので、とても勉強になりました。
同じような初心者の方の手助けになりましたら幸いです。

参照