Amazon CloudWatch Logsのバックアップを目的としてKinesis Data Firehoseを経由し、S3に保存する方法を解説します。
CreateExportTaskのAPIを利用しS3にエクスポートすることも可能ですがこちらのAPIはアカウント内で並列実行出来ないという制限があるのでスケールアウトも難しく、リアルタイム処理も行いにくいです。対して、Kinesis Data Firehoseを利用するとストリーミングデータとして逐次S3へ保存していくことが可能です。
今回はサンプルとしてAWS LambdaのロググループをS3に転送してみます。構築にはAWS SAMを利用します。
注意点
・転送可能なリクエスト、転送量には制限があります。
実際に本番運用する場合は転送ログのボリュームをしっかり見積もりしましょう。
Amazon Kinesis Data Firehoseのクォータ
・S3に保存されるログはCloudWatchログそのままでは無くメタデータが付与れています。
ログの保存先S3バケットとサンプルログを出力するLambdaを作成
以下内容のAWS SAMです。
・サブスクリプションフィルターを設定するためにLambdaのロググループを明示的に構築
・ロググループはS3にバックアップする事を想定し、保存期間を30日に設定
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
kinesis-firehose-sample
Resources:
# ログを出力するサンプルLambda
HelloFunc:
Type: AWS::Serverless::Function
Properties:
FunctionName: HelloFunc
CodeUri: hello/
Handler: app.lambda_handler
Runtime: python3.8
Events:
LogOutputFuncEvent:
Type: Api
Properties:
Path: /hello
Method: get
# Lambdaロググループ
HelloFuncLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub /aws/lambda/${HelloFunc}
# he number of days to retain the log events in the specified log group.
# Possible values are: 1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731, 1827, and 3653
RetentionInDays: 30
# ログの保存先バケット
LogBackupBucket:
Type: "AWS::S3::Bucket"
Properties:
BucketName: "2021-12-10-logbuckup-bucket"
AccessControl: Private
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
Kinesis Data Firehoseの作成
上記で作成したS3を宛先とするFirehoseの定義と必要なIAMポリシー、ロールを作成します。
Firehoseに送られたデータはバッファリングされ、指定したデータサイズ、または指定の秒数が経過した時点でS3に出力されます。
# S3ログ出力用のFirehoseストリーム
LogDeliveryStream:
Type: AWS::KinesisFirehose::DeliveryStream
Properties:
DeliveryStreamName: "cloudwatchlogs-backup-stream"
DeliveryStreamType: DirectPut
S3DestinationConfiguration:
BucketARN: !Sub '${LogBackupBucket.Arn}'
# バッファリング設定
BufferingHints:
# バッファリングサイズ。単位はMB(1-128)
SizeInMBs: 1
# バッファリングする時間の長さ。単位は秒数(60-900)
IntervalInSeconds: 60
CloudWatchLoggingOptions:
Enabled: true
LogGroupName: !Sub '/aws/kinesisfirehose/cludwatchlogs-backup-${AWS::StackName}'
LogStreamName: LogDeliveryToS3
# 圧縮形式
# CloudWatch Logs から Kinesis Data Firehose に送信されたデータは、
# すでに gzip(レベル6)で圧縮されているため圧縮不要。
CompressionFormat: UNCOMPRESSED
# 暗号化設定
EncryptionConfiguration:
NoEncryptionConfig: NoEncryption
ErrorOutputPrefix: 'log-delivery-error-'
# S3バケットに配信するファイルに追加するプレフィックス
Prefix: 'log-deliverry-'
RoleARN: !Sub '${FirehoseDeliveryRole.Arn}'
# Firehose用ロール
FirehoseDeliveryRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Sid: ''
Effect: Allow
Principal:
Service: firehose.amazonaws.com
Action: sts:AssumeRole
Condition:
StringEquals:
sts:ExternalId: !Ref 'AWS::AccountId'
# Firehose用ポリシー
FirehoseDeliveryPolicy:
Type: AWS::IAM::Policy
Properties:
PolicyName: firehose-log-delivery-policy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- s3:AbortMultipartUpload
- s3:GetBucketLocation
- s3:GetObject
- s3:ListBucket
- s3:ListBucketMultipartUploads
- s3:PutObject
Resource:
- !Sub 'arn:aws:s3:::${LogBackupBucket}'
- !Sub 'arn:aws:s3:::${LogBackupBucket}*'
Roles:
- !Ref 'FirehoseDeliveryRole'
Lambdaロググループにサブスクリプションフィルターを設定
Lambdaのロググループにサブスクリプションフィルターを設定します。
宛先には上記で作成したFirehoseを指定します。
# HelloFuncのロググループ用サブスクリプションフィルター
CWLSubscriptionFilterForHelloFunc:
Type: AWS::Logs::SubscriptionFilter
Properties:
# 宛先にFirehoseを指定
DestinationArn: !GetAtt 'LogDeliveryStream.Arn'
FilterPattern: " "
LogGroupName: !Ref 'HelloFuncLogGroup'
RoleArn: !GetAtt 'SubscriptionFilterLogsRole.Arn'
# サブスクリプションフィルター用ロール
# Firehoseの操作権限を付与する
SubscriptionFilterLogsRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: !Sub 'logs.${AWS::Region}.amazonaws.com'
Action:
- sts:AssumeRole
Path: /
Policies:
- PolicyName: root
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- firehose:*
Resource: !GetAtt 'LogDeliveryStream.Arn'
以上