🚀

CloudWatch LogsをS3に転送するためにEventBridge Schedulerを使用する

2023/09/10に公開

はじめに

昨年 Amazon EventBridge Schedulerという機能が公開されました。今回はこれを利用して、Amazon CloudWatch LogsをAmazon S3に転送してみます。

設定方法

EventBridge Schedulerは多数のAWSサービスのAPIをターゲットに指定できます。この中にはCloudWatch Logsの CreateExportTask も含まれており、これはLog GroupからS3バケットにエクスポートするタスクを作成します。今回はこのAPIを利用して、CloudWatch LogsからS3バケットへのエクスポートを定期的に実行することを目指します。

https://docs.aws.amazon.com/scheduler/latest/UserGuide/managing-targets-universal.html

EventBridge Scheduer用のIAMロール作成

EventBridge SchedulerからCloudWatch Logsに対する操作権限を付与します。今回は横着して CloudWatchLogsFullAccess というマネージドポリシーを付与しました。

ログ保存用のS3バケットの作成

CloudWatch Logsのエクスポート先とするS3バケット (名称: cw-s3-20230820) を作成します。ここでは以下のようなバケットポリシーを付与しています。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "logs.ap-northeast-1.amazonaws.com"
            },
            "Action": "s3:GetBucketAcl",
            "Resource": "arn:aws:s3:::cw-s3-20230820"
        },
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "logs.ap-northeast-1.amazonaws.com"
            },
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::cw-s3-20230820/*",
            "Condition": {
                "StringEquals": {
                    "s3:x-amz-acl": "bucket-owner-full-control"
                }
            }
        }
    ]
}

CloudWatch Logsの設定

今回は過去に取得していたCloudWatch Logsを利用しましたが、必要に応じて設定をします。

EventBridge Schedulerの設定

ここからEventBridge Schedulerの設定をします。

マネジメントコンソールから設定する場合は以下の項目を入力します

1. スケジュールの詳細の指定

スケジュール名、スケジュールグループに加え、スケジュールのパターンを入力します。

2. ターゲットの選択

ターゲットとなるAPIを選択します。ここでは すべてのAPI からCloudWatch Logsを検索し、 CreateExportTask を選択します。

続いて CreateExportTask APIへのインプット情報をJson形式で渡します。今回は以下のようなデータを渡しました。

{
  "Destination": "cw-s3-20230820",
  "DestinationPrefix": "<aws.scheduler.scheduled-time>",
  "From": 1692351040000,
  "LogGroupName": "messages",
  "To": 1694192262000
}

いくつか補足します。

  • From To: Unix timestampで、取得するログの期間を指定します。
  • DestinationPrefix: 保存先のS3バケット名を指定します。
  • LogGroupName: 取得する対象のCloudWatch LogGroupを指定します。
  • DestinationPrefix: エクスポートされるオブジェクトのキーの先頭として使用されるPrefixを指定します。デフォルトは exportedlogs となりますが、ここではEventBridge Schedulerで利用できるキーワードを利用します (後述)。

https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_CreateExportTask.html

3. 設定

スケジュール完了後のアクションや再試行ポリシー、暗号化などの設定を行います。ここでは使用するIAMロールを指定します。

4. スケジュールの確認と作成

設定情報を確認して作成します。

補足: EventBridge Schedulerで利用できるキーワードについて

3. 設定 で指定した DestinationPrefix は、デフォルトでは exportedlogs が指定されます。この場合、指定したS3バケットに exportedlogs というフォルダが作成され、そこに <タスクID> / <Logストリーム> / 000000.gz という形式でログが保存されます。

ここで EventBridge Scheduler特有のキーワードである <aws.scheduler.scheduled-time> を利用します。これはSchedulerが実行された時間を指定するキーワードであり、これを DestinationPrefix に指定することで、 Schedulerの実行時間ごとにフォルダが分かれます。こうするとエクスポートされたログのファイルが一定周期ごとに分けて保存され、特に定期的にCloudWatch Logsからエクスポートする場合は見分けやすくなるのではないかと思います。

https://docs.aws.amazon.com/scheduler/latest/UserGuide/managing-schedule-context-attributes.html

動作確認

今回設定したSchedulerは以下の通りです。ここでは10分ごとにタスクを実行するようにしています。

設定後、スケジュールした時間が経過したのちにS3バケットを見てみると、以下のようにスケジュール実行時間ごとにフォルダが分かれている様子が確認できます (何度か実行しているので上記スケジュール以外のものも保存されています)。

なお保存時の時刻はUTCに変換されるようです。

今回指定したLogGroupにはEC2インスタンスからのログを保存しており、インスタンスごとにLogストリームが分かれていますが、それらが保存されていることも確認できました。

CloudFormationによる作成

CloudFormationでの作成は、以下のようなファイルを使用します。なお、Schedulerの開始・終了時刻を指定する StartDate EndDate というパラメータがあるのですが、こちらで指定するフォーマットが作成時点ではよくわからなかったため、空欄にしています。

CloudFormationファイル
AWSTemplateFormatVersion: "2010-09-09"
Parameters:
  BucketName:
    Type: String
  ScheduleExpression:
    Type: String
    Default: "rate(10 minutes)"
  ScheduleExpressionTimezone:
    Type: String
    Default: "Asia/Tokyo"
  LogGroupName:
    Type: String
  FromTimestamp:
    Type: Number
    Default: 1693540800000 # 2023-09-01T13:00:00
  ToTimestamp:
    Type: Number
    Default: 1694318400000 # 2023-09-10T13:00:00
  #StartDate:
  #  Type: String
  #EndDate:
  #  Type: String

Resources:
  S3BucketForCWLogs:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Ref BucketName
  BucketPolicy:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: !Ref S3BucketForCWLogs
      PolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              Service: logs.ap-northeast-1.amazonaws.com
            Action: s3:GetBucketAcl
            Resource: !Sub arn:aws:s3:::${S3BucketForCWLogs}
          - Effect: Allow
            Principal:
              Service: logs.ap-northeast-1.amazonaws.com
            Action: s3:PutObject
            Resource: !Sub arn:aws:s3:::${S3BucketForCWLogs}/*
            Condition:
              StringEquals:
                s3:x-amz-acl: bucket-owner-full-control
  IAMRoleForEventBridgeScheduler:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - scheduler.amazonaws.com
            Action:
              - sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/CloudWatchLogsFullAccess
  EventBridgeScheduler:
    Type: AWS::Scheduler::Schedule
    Properties: 
      FlexibleTimeWindow: 
        Mode: "FLEXIBLE"
        MaximumWindowInMinutes: 15
      Name: !Ref S3BucketForCWLogs
      ScheduleExpression: !Ref ScheduleExpression
      ScheduleExpressionTimezone: !Ref ScheduleExpressionTimezone
      State: "ENABLED"
      #StartDate: !Ref StartDate
      #EndDate: !Ref EndDate
      Target: 
        Arn: arn:aws:scheduler:::aws-sdk:cloudwatchlogs:createExportTask
        Input: !Sub |-
          {
            "Destination": "${S3BucketForCWLogs}",
            "DestinationPrefix": "<aws.scheduler.scheduled-time>",
            "From": ${FromTimestamp},
            "LogGroupName": "${LogGroupName}",
            "To": ${ToTimestamp}
          }
        RoleArn: !GetAtt IAMRoleForEventBridgeScheduler.Arn

https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-scheduler-schedule.html

最後に

これまでCloudWatch LogsをS3に定期的に転送する方法は、主に2通りありました。

  • EventBridgeでスケジュール実行を設定、Lambdaで create_export_task を実行
  • CloudWatchLogsのサブスクリプションフィルターでKinesis Data Firehoseを指定、Kinesis Data FirehoseはターゲットにS3バケットを指定

https://qiita.com/Regryp/items/031141f8930c94378d5f

これらの方法と比べ、EventBridge Schedulerは、より気軽にCloudWatch Logsをエクスポートする手段として使えそうです。柔軟性には欠けますが、選択肢の1つとして覚えておこうと思います。

Discussion