CloudWatch Logs を定期的にS3 へ転送する
概要
- 今回は、CloudWatch Logsのサブスクリプションフィルターを使用して、CloudWatch Logs のログを定期的にS3 へ転送します。
- CloudWatch Logs のログをS3 へ転送する方法は、以前こちらで紹介したCloudWatch Logsのエクスポート機能を利用する方法もあります。しかし、エクスポート機能で実現する場合は、エクスポートのタスクを定期実行するために Lambdaが必要になること、そして、同時に複数のエクスポートタスクを実行できない仕様です。そのため、CloudWatch Logsのエクスポート機能に代わる方法が良いと思います。
- また、コストの観点であれば、CloudWatch Logs のデータ取り込み(例: 東京リージョン 0.76USD/GB)、S3 のPUT(例: 東京リージョン 0.0047USD/1,000リクエスト)にそれぞれ料金が掛かります。もちろん、データ取り込み以外に、保存期間に応じた料金も必要です。よって、コストの観点だけであれば、CloudWatch Logs をS3 に転送するのではなく、ログ管理をCloudWatch Logs or S3 のどちらか一方に限定する方が得策です。ログ管理の要件、ログの転送・保存に掛かるコストを踏まえた上でご検討ください。
- 以下、今回ご紹介する部分の構成図です。
CloudWatch Logs をS3 に転送するサブスクリプションフィルターの構築
手引き
- 今回は、下記AWSドキュメントを参考に構築を行います。ドキュメントと異なる手順は、CloudWatch Logs サブスクリプションフィルターの作成方法をCLI を使用せず、コンソールを使用している点となります。以前は、Kinesis Data Firehoseの CloudWatch Logs サブスクリプションフィルターはコンソールから作成できませんでした。最近のアップデートによって、コンソールを利用して、Kinesis Data Firehoseの CloudWatch Logs サブスクリプションフィルターを作成できるように変わりました。
準備
サブスクリプションフィルターを設定するロググループを確認する
- 今回、S3 へ転送する対象の CloudWatch Logs ロググループは下記となります。画面の表示通り、現在こちらのロググループには、サブスクリプションフィルターは設定されていません。
ログの転送先となるS3 バケットを準備する
- ログの転送先となるS3 を準備します。今回使用するバケット名は niikawa-test、Prefixは log-archive/niikawa-test-lambda/ となります。
Kinesis Data Firehose 用のロールを作成する
- S3 にデータを書くための権限をKinesis Data Firehose に付与するため、新規でロールを作成します。今回はAWSドキュメントに合わせて、ロールの作成にAWS CLI を使用します。
- 始めに、テキストエディタにて TrustPolicyForFirehose.json のjson ファイルを作成します。下記コードを利用する場合、「アカウントID」を環境に合わせて置き換えます。
- vi を利用する場合は、"set paste" を活用ください。
{
"Statement": {
"Effect": "Allow",
"Principal": { "Service": "firehose.amazonaws.com" },
"Action": "sts:AssumeRole",
"Condition": { "StringEquals": { "sts:ExternalId":"アカウントID" } }
}
}
- 以下のAWS CLI を実行し、Kinesis Data Firehose に付与するロールを作成します。
- ロール名(例:FirehosetoS3Role)は、環境に合わせて変更下さい。
aws iam create-role --role-name FirehosetoS3Role --assume-role-policy-document file://TrustPolicyForFirehose.json
- 作成されたロールにポリシーを追加するための json を作成します。テキストエディタにて、Action を定義した PermissionsForFirehose.json のjson ファイルを作成します。下記コードを利用する場合、「バケット名」を環境に合わせて置き換えます。
{
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:AbortMultipartUpload",
"s3:GetBucketLocation",
"s3:GetObject",
"s3:ListBucket",
"s3:ListBucketMultipartUploads",
"s3:PutObject" ],
"Resource": [
"arn:aws:s3:::バケット名",
"arn:aws:s3:::バケット名/*" ]
}
]
}
- ロールにポリシーを追加します。
aws iam put-role-policy --role-name FirehosetoS3Role --policy-name Permissions-Policy-For-Firehose --policy-document file://PermissionsForFirehose.json
Kinesis Data Firehose を作成する
- 次に、Kinesis のコンソールを開き、「Kinesis Data Firehose」にて「Create Delivery Stream」を押します。
- Delivery stream name を入力します。
- Source に、「Direct PUT or other sources」を選択します。「Next」を押します。
- ログのデータ変換を行う場合は、Data transformationにて「Enabled」を選択し、変換処理を行うためのLambda関数を選択します。データ変換を行わない場合は、「Disabled」を選択します。
- Record format conversionにて「Disabled」を選択します。「Next」を押します。
- Destination に「S3」を選択します。
- S3 bucketに転送先のバケットを指定します。
- S3 prefix およびS3 error prefix を指定します。「Next」を押します。
- 複数のサブスクリプションフィルターを設定する場合、ロググループ毎にS3 のフォルダが分かれた方が見やすいと思います。その様な場合は、ロググループ名が区別できる S3 prefix 良いでしょう。
- Buffer size、Buffer interval はデフォルト(Buffer size:5 MiB、Buffer interval:300 seconds)でも良いです。必要に応じて、Buffer size、Buffer interval を変更します。
- S3 compression に「Disabled」を選択します。CloudWatch Logs から Kinesis Data Firehose に送信されたデータは、すでに gzip(レベル6)で圧縮されているため、Kinesis Data Firehose 送信ストリーム内で圧縮する必要はありません。
- Error logging は「Enabled」を選択します。
- IAM role を選択します。前述の手順にて作成した「FirehosetoS3Role」を選択します。「Next」を押します。
- Reviewにて問題なければ、「Create delivery stream」を押します。
- Kinesis Data Firehose が作成されました。
CloudWatch Logs 用のロールを作成する
- 次は、Kinesis Data Firehose にデータを書くための権限を CloudWatch Logs に付与するため、新規でロールを作成します。今回はAWSドキュメントに合わせて、ロールの作成にAWS CLI を使用します。
- 始めに、テキストエディタにて TrustPolicyForCWL.json のjson ファイルを作成します。下記コードを利用する場合、リージョン名の「ap-northeast-1」を環境に合わせて置き換えます。
- vi を利用する場合は、"set paste" を活用ください。
{
"Statement": {
"Effect": "Allow",
"Principal": { "Service": "logs.ap-northeast-1.amazonaws.com" },
"Action": "sts:AssumeRole"
}
}
- 以下のAWS CLI を実行し、CloudWatch Logs に付与するロールを作成します。
- ロール名(例:CWLtoKinesisRole)は、環境に合わせて変更下さい。
aws iam create-role --role-name CWLtoKinesisRole --assume-role-policy-document file://TrustPolicyForCWL.json
- 作成されたロールにポリシーを追加するためのjson を作成します。テキストエディタにて、Action を定義した PermissionsForCWL.json のjson ファイルを作成します。下記コードを利用する場合、「アカウントID」を環境に合わせて置き換えます。
{
"Statement":[
{
"Effect":"Allow",
"Action":["firehose:*"],
"Resource":["arn:aws:firehose:ap-northeast-1:アカウントID:*"]
}
]
}
- ロールにポリシーを追加します。
aws iam put-role-policy --role-name CWLtoKinesisRole --policy-name Permissions-Policy-For-CWL --policy-document file://PermissionsForCWL.json
サブスクリプションフィルターを設定する
- 最後に、対象のロググループにサブスクリプションフィルターを設定します。
- 対象のロググループにて、「サブスクリプションフィルター」を選択し、「作成」→「Create Kinesis Firehose subscription filter」を押します。
- 先ず、Destination account を選択および Kinesis Firehose delivery stream にKinesis Data Firehose のリソース名を指定します。
- 次に、Select an existing role に前述の手順にて作成した「CWLtoKinesisRole」を選択します。
- 次に、ログの形式、サブスクリプションフィルターのパターン、サブスクリプションフィルター名を指定します。
- 最後に、「ストリーミングを開始」を押します。
- サブスクリプションフィルターが設定できました。
- ロググループの一覧からも 1つのサブスクリプションフィルターが設定されていることが確認できます。
- ログの転送先となるS3 に、ログファイルが転送されていることを確認します。ファイル名に拡張子は付いていませんが、gz圧縮されています。ご注意ください。
サブスクリプションフィルターのトラブルシューティング
ストリーミングを開始できない
症状
- サブスクリプションフィルター設定において、「ストリーミングを開始」を押すと以下のエラーが発生する。
- 以下は、コンソールから実行した場合のエラーメッセージです。
- Could not deliver test message to specified Firehose stream. Check if the given Firehose stream is in ACTIVE state.
- 以下は、AWS CLI から実行した場合のエラーメッセージです。
- An error occurred (InvalidParameterException) when calling the PutSubscriptionFilter operation: Could not deliver test message to specified Firehose stream. Check if the given Firehose stream is in ACTIVE state.
対処方法
- 私の経験では、CloudWatch Logs に付与するロールの権限定義に誤りがありました。ポリシーの記述を見直し後、「ストリーミングを開始」が成功しました。
S3 にログが転送されない
症状
- 「ストリーミングを開始」が成功したが、ログの転送先となるS3 に下記1行のみ出力され、他のログが記録されない。
{"messageType":"CONTROL_MESSAGE","owner":"CloudwatchLogs","logGroup":"","logStream":"","subscriptionFilters":[],"logEvents":[{"id":"","timestamp":1627966598067,"message":"CWL CONTROL MESSAGE: Checking health of destination Firehose."}]}
対処方法
- ログの形式、サブスクリプションフィルターのパターンを指定せず、デフォルトの値を使用後にログの転送が始まりました。ログの形式、サブスクリプションフィルターのパターンを見直す必要があります。
参考資料