このページはなに
表題通りとなりますが、Lambda関数を使用してCloudWatch LogsにあるログをS3に転送する仕組みを実装します。
参考にさせていただいたURL
背景
AWSサービスの中でファイルの配置の料金が一番安いのはS3です。
なので、例えばCloudWatch Logsに格納しているログについては7日保管にして、S3には1年間保管のような仕組みをつくりたいと考えました。
仕組み(構成図)
作業手順
IAMロール(ポリシー)の作成
以下、IAMポリシーを作成してIAMロールにアタッチしてLambdaに紐づけてください。
(LambdaがS3バケットへの操作の権限が必要なため)
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:ListBucket" # S3バケット内のリスト表示に必要(最初に接続確認をするため)
],
"Resource": "arn:aws:s3:::S3バケット名"
},
{
"Effect": "Allow",
"Action": [
"s3:GetObject", # S3バケットにログを配置する前にS3バケット内のファイルの存在を確認するための権限
"s3:PutObject" # S3バケットにログを配置するための権限
],
"Resource": "arn:aws:s3:::S3バケット名/*"
}
]
}
S3バケットポリシーの設定
・吐き出す先のS3バケットポリシーに、以下のバケットポリシーを設定してください。
・補足:この設定は、CloudWatch LogsからS3バケットにログを配置するために必要なバケットポリシーになります。
(CloudWatch LogsにIAMロールは紐づけられないので、S3のバケットポリシーで制御します。)
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "logs.対象リージョン.amazonaws.com"
},
"Action": "s3:GetBucketAcl", # CloudWatch Logsから S3バケットのアクセス(s3apiコール)制御のポリシー
"Resource": "arn:aws:s3:::S3バケット名"
},
{
"Effect": "Allow",
"Principal": {
"Service": "logs.対象リージョン.amazonaws.com"
},
"Action": "s3:PutObject", # CloudWatch Logsから S3バケットへログ配置するためのS3バケットポリシー
"Resource": "arn:aws:s3:::S3バケット名/*",
"Condition": {
"StringEquals": {
"s3:x-amz-acl": "bucket-owner-full-control"
}
}
}
]
}
Lambda関数の作成
・使用言語は、python3。バージョンは、3.7です。
コード
コードは「参考にさせていただいたサイト」に記載してある内容とほぼ同じです。
コード内に記載されているコメントアウト部分を、環境ごとに適宜編集していく形になります。
import datetime
import time
import boto3
log_group_name = 'ロググループ名' #CloudWatchLogsのロググループ名
s3_bucket_name = 'S3バケット名' #保存先S3バケット名
s3_string_prefix = 'S3内のプレフィックス' #S3内のプレフィックス(文字列)を定義
s3_date_prefix = '/%s' % (datetime.date.today() - datetime.timedelta(days = 1)) #S3内のプレフィックス(日付)を定義
def get_from_timestamp():
today = datetime.date.today()
yesterday = datetime.datetime.combine(today - datetime.timedelta(days = 1), datetime.time(0, 0, 0))
timestamp = time.mktime(yesterday.timetuple())
return int(timestamp)
def get_to_timestamp(from_ts):
return from_ts + (60 * 60 * 24) - 1
def lambda_handler(event, context):
from_ts = get_from_timestamp()
to_ts = get_to_timestamp(from_ts)
print('Timestamp: from_ts %s, to_ts %s' % (from_ts, to_ts))
client = boto3.client('logs')
response = client.create_export_task(
logGroupName = log_group_name, #取得するCloudWatchロググループ名
fromTime = from_ts * 1000,
to = to_ts * 1000,
destination = s3_bucket_name, #保存先S3バケット名
destinationPrefix = s3_string_prefix + s3_date_prefix #保存先S3バケット名配下の任意のサブフォルダ名(プレフィックス名)
)
return response
CloudWatch Eventの作成
毎日AM4:00にイベント発生する場合、CloudWatch Eventに以下のcron設定をすればおkです。
(時間がUTC形式のため、UTCから+9時間することを忘れずに。)
0 19 * * ? *
悩んだこと
S3に吐き出したときのファイル名が「000000.gz」になってしまうので、ファイル名を変える方法を調べましたが、boto3のapiの仕様で「000000」で吐き出されてしまうようです(ファイル名を別ネームで保存したい場合は、別途仕組みを実装する必要あり)。
boto3_URL