CloudWatch LogsをS3にエクスポートしてみた(EventBridge編)

2023.09.29

こんにちは、シマです。
皆さんはCloudWatch LogsのログをS3にエクスポートしていますか?CloudWatchLogsのログ保管コストはS3と比較して高いです。そのため、長期のログ保管を考えたとき、CloudWatch LogsのログをS3に転送することでより安価にログを保管することが可能です。しかし、CloudWatch Logs標準の機能として定期的な自動実行でS3へ移行することはできないため、他の機能を組み合わせて実施する必要があります。

今回は、一番容易で安価に自動化が可能なEventBridgeを使って実装してみました。

構成

今回の構成は以下です。

EventBridgeからCloudWatch LogsのCreateExportTaskAPIをコールし、S3にエクスポートします。

設定の流れ

S3バケット

AWS管理コンソールのS3の画面から、「バケット作成」を押下します。

任意のバケット名を入力し、エクスポートするCloudaWatch logsと同じリージョンを選択し、バケットを作成します。

バケットポリシーの設定をします。一覧から先ほど作成したバケットをクリックし、「アクセス許可」からバケットポリシーの「編集」を押下します。
編集画面で以下の内容を入力します。実際の環境に合わせて「【バケット名】,【リージョン】,【AWSアカウントID】」を修正してください。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "logs.【リージョン】.amazonaws.com"
            },
            "Action": "s3:GetBucketAcl",
            "Resource": "arn:aws:s3:::【バケット名】",
            "Condition": {
                "StringEquals": {
                    "aws:SourceAccount": "【AWSアカウントID】"
                },
                "ArnLike": {
                    "aws:SourceArn": "arn:aws:logs:【リージョン】:【AWSアカウントID】:log-group:*"
                }
            }
        },
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "logs.【リージョン】.amazonaws.com"
            },
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::【バケット名】/*",
            "Condition": {
                "StringEquals": {
                    "s3:x-amz-acl": "bucket-owner-full-control",
                    "aws:SourceAccount": "【AWSアカウントID】"
                },
                "ArnLike": {
                    "aws:SourceArn": "arn:aws:logs:【リージョン】:【AWSアカウントID】:log-group:*"
                }
            }
        }
    ]
}

IAMロール、ポリシー

AWS管理コンソールのIAMポリシーの画面から「ポリシーを作成」を押下します。

「JSON」を押下し、ポリシー入力欄に以下を入力します。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateExportTask",
                "logs:CancelExportTask",
                "logs:DescribeExportTasks",
                "logs:DescribeLogStreams",
                "logs:DescribeLogGroups"
            ],
            "Resource": "*"
        }
    ]
}

任意のポリシー名を入力し、ポリシーを作成します。

AWS管理コンソールのIAMロールの画面から「ロールを作成」を押下します。

「カスタム信頼ポリシー」を選択し、下部のポリシー入力欄に以下の内容を入力し、「次へ」を押下します。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "scheduler.amazonaws.com"
            },
            "Action": "sts:AssumeRole"
        }
    ]
}

追加ポリシーにて、先ほど作成したポリシーと「AmazonS3ReadOnlyAccess」をそれぞれ選択し、「次へ」を押下します。

任意のロール名を入力し、「ロールを作成」を押下します。

EventBridge

AWS管理コンソールのEventBridgeのスケジュール画面から「スケジュールを作成」を押下します。

任意のスケジュール名を入力し、スケジュールパターンを設定し、「次へ」を押下します。今回は約1か月毎のアクションを想定し、29日毎に実行するように設定します。
※詳細は後述します。

ターゲットの選択で「すべてのAPI」を選択し、「CloudWatch Logs」を選択します。続いて、「CreateExportTask」を選択します。

入力欄に以下の内容を入力します。実際の環境に合わせて「【バケット名】,【エクスポート対象ロググループ名】」を修正してください。

{
  "Destination": "【バケット名】",
  "DestinationPrefix": "<aws.scheduler.scheduled-time>",
  "From": 1672498800000,
  "LogGroupName": "【エクスポート対象ロググループ名】",
  "To": 4828172400000
}

※FromとToはUnixtime(ミリ秒)で入力する必要があり、上記では2023年1月1日0時~2123年1月1日0時とし、疑似的に全範囲を指定しています。

アクセス許可で先ほど作成したロールを指定し、「次へ」を押下し、「スケジュール作成」を押下します。

CloudWatch Logs

古いログを削除するために保持期間を設定します。AWS管理コンソールのCloudWatchのロググループ画面から、対象のロググループ名の保持期間をクリックします。表示された画面で、保持期間を設定します。今回は約1か月を想定して「1か月(30日)」を指定します。

考慮が必要なこと

CloudWatch Logsの削除とEventBridgeによるエクスポートが非同期

前述の手順の通り、CloudWatch Logsの保持期間は選択式で任意の期間を指定できません。また、EventBridgeによるエクスポートと非同期で実行されるため、ログのロストを防ぐためにエクスポートされるログの期間が重複するように指定する必要があります。例えば、毎月1日に実行されるようにEventBridgeを構成してしまうと、CloudWatch Logsの保持期間としては30日しか選択できないため、31日ある月のログが1日分ロストしてしまいます。

一方で、CloudWatch Logsの保持期間を60日とした場合は、毎月1日の実行でもログのロストは発生しませんが、毎月約1か月分のログは冗長にエクスポートしてしまうことになります。
そのため、今回の設定例では保持期間を30日、エクスポート間隔は29日とし、重複期間を短くしています。

バケット内の構成がシンプル

CreateExportTaskを利用するため、その仕様に基づいてエクスポートされます。そのため、S3のPrefixまでの指定は可能ですが、そこから先の細かい指定はできません。 例えば、Kinesis Data Firehoseを利用したケースでは下図のように年月日等で分解されて出力されますが、今回の方式ではそこまでの自由度はありません。

※上図の引用元の記事

最後に

今回は、EventBridgeを使ってCloudWatch Logsをエクスポートしてみました。柔軟性という観点ではやはりLambdaを利用する方が良いですが、開発なく設定するだけでサクッと実装できるのが良いところですね。

本記事がどなたかのお役に立てれば幸いです。