【CloudFormation】CloudWatch Logs のログを Subscription Filterと Firehose で S3 に移行する
本記事では、CloudFormationによる、CloudWatch Logs のログを Subscription Filterと Firehose で S3 に移行する方法をコード付きで解説します。

前提
各リソースの名前は下記。
・CloudWatch Log Group:aws-waf-logs
・Subscription Filter:test-subscriptionfilter-aws-waf-logs
・Kinesis Firehose:test-firehose-aws–waf-logs
・S3:test-cluster:test-s3-logs-destination
説明
・今回は、WAFのログ(aws-waf-logs)をS3へ移行する。
・併せて、Log Groupの保持期間を任意の値にすることで、Log Groupからは指定の日数後に削除され、その後はS3で保管することが出来る。
・S3では90日でデータをGlacierへ移行、365日で削除するよう設定している。
・データの移動は下記のように行われる。
Log Group(WAFログ)→ Subscription Filter → Kinesis Firehose → S3
実際のコード
AWSTemplateFormatVersion: "2010-09-09"
Parameters:
System:
Type: String
Default: test
Resources:
# ------------------------------------------#
# IAM Policy, Role for Subscription Filter
# ------------------------------------------#
SubscriptionFilterRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub ${System}-subscription-filter-role
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: !Sub 'logs.${AWS::Region}.amazonaws.com'
Action:
- sts:AssumeRole
Path: /
Policies:
- PolicyName: !Sub ${System}-subscription-filter-policy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- firehose:PutRecord
- firehose:PutRecords
Resource: !Sub 'arn:aws:firehose:${AWS::Region}:${AWS::AccountId}:deliverystream/*' #エクスポート先firehoseへの許可
# ------------------------------#
# Subscription Filter
# ------------------------------#
SubscriptionFilter1:
Type: AWS::Logs::SubscriptionFilter
Properties:
DestinationArn: !GetAtt Log1Firehose.Arn
FilterName: !Sub ${System}-subscriptionfilter-aws-waf-logs
FilterPattern: ""
LogGroupName: aws-waf-logs #エクスポートしたいロググループ名
RoleArn: !GetAtt SubscriptionFilterRole.Arn
# ------------------------------#
# IAM Policy, Role for firehose
# ------------------------------#
LogFirehosePolicy:
Type: AWS::IAM::ManagedPolicy
Properties:
Description: "Allow Put Logs to Amazon S3"
ManagedPolicyName: !Sub ${System}-policy-logfirehose
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- "s3:AbortMultipartUpload"
- "s3:GetBucketLocation"
- "s3:GetObject"
- "s3:ListBucket"
- "s3:ListBucketMultipartUploads"
- "s3:PutObject"
- "logs:PutLogEvents"
Resource:
- !Sub arn:aws:s3:::${System}-s3-logs-destination #エクスポート先S3への許可
- !Sub arn:aws:s3:::${System}-s3-logs-destination/* #エクスポート先S3への許可
- !Sub "arn:aws:logs:*:${AWS::AccountId}:log-group:*:log-stream:*" #読み取り元ロググループ・ログストリームからの許可
LogFirehoseRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub ${System}-role-logfirehose
ManagedPolicyArns:
- !GetAtt LogFirehosePolicy.PolicyArn #上記ポリシーを参照
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action: sts:AssumeRole
Principal:
Service: firehose.amazonaws.com
# ------------------------------#
# Kinesis Firehose
# ------------------------------#
Log1Firehose:
Type: AWS::KinesisFirehose::DeliveryStream
Properties:
DeliveryStreamEncryptionConfigurationInput:
KeyType: AWS_OWNED_CMK #KMSキー暗号化
DeliveryStreamName: !Sub ${System}-firehose-aws--waf-logs
DeliveryStreamType: DirectPut
S3DestinationConfiguration:
BucketARN: !Sub arn:aws:s3:::${System}-s3-logs-destination
BufferingHints:
IntervalInSeconds: 900
SizeInMBs: 128
Prefix: firehose/aws-waf-logs/ #ログエクスポート先S3のプレフィックス
ErrorOutputPrefix: firehose/error/aws-waf-logs/ #失敗時のログエクスポート先S3のプレフィックス
CompressionFormat: UNCOMPRESSED
CloudWatchLoggingOptions:
Enabled: false
RoleARN: !GetAtt LogFirehoseRole.Arn
# ------------------------------#
# S3
# ------------------------------#
S3BucketForAWSResourceLogs:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub ${System}-s3-logs-destination
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
AccessControl: Private
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
LifecycleConfiguration:
Rules:
- Id: !Sub ${System}-s3-logs-destination-life-cycle
Status: "Enabled"
ExpirationInDays: 365 #365日後に削除
Transitions:
- StorageClass: GLACIER
TransitionInDays: 90 #90日後にGlacierへ移動