/ #Terraform #S3 

CloudWatchのログをS3に吐くLambdaで発生したエラーの原因を解説

もくじ

こんにちはししぃです 😊

今回は Lambda で発生したエラーの対策です!

今回やろうとしていたことは、 CloudWatch のログを S3 にエクスポートする Lambda を作ろうとしていました。
がエラーに躓きまして、その原因とかをつらつら書いていきます!

解説

エラーが発生する Lambda のコード

エラーを出すために下記の python3.8 で下記のような Lambda を作成しました。

import boto3

def lambda_handler(event, context):

    client = boto3.client("logs")
    response = client.create_export_task(
        logGroupName="/aws/lambda/my-lambda", # ログ保存元のグループネーム
        fromTime=1593129600000,               # UTC(ミリ秒) 2020-06-26 00:00.00
        to=1593215999000,                     # UTC(ミリ秒) 2020-06-27 08:59:59
        destination="my-s3-bucket",           # ログの保存先bucket名
        destinationPrefix="my-lambda",        # 保存先のプレフィックス
    )
    return response

説明不要なほどシンプルなコードですね 😅
補足するとcreate_export_taskメソッドは CloudWatch のログをエクスポートする関数です。

詳細は このへん を確認してください!

上記の lambda を作りなんの設定も行わないで Lambda を実行すると下記のエラーが発生します。

エラー 1 つ目

エラーメッセージは一部 XXXXXX で上書きしてます 😅

An error occurred (AccessDeniedException) when calling the CreateExportTask operation: User: arn:aws:sts::XXXXXXXXXXX:assumed-role/xxxxxxxxxxxxxx is not authorized to perform: logs:CreateExportTask on resource: arn:aws:logs:ap-northeast-1:xxxxxxxxxxxxx:log-group:/xxxxxxxxxxxxxxx

訳すと、

CreateExportTask を実行しようとしたらエラーだよ。
Lambda の実行ロール(arn:aws:sts::XXXXXXXXXXX:assumed-role/xxxxxxxxxxxxxx)はリソース(arn:aws:aws:logs:ap-northeast-1:xxxxx:log-group:xxxxxx)に対する権限(logs:CreateExportTask)がないよ。

絵にするとこんな感じです。

なので Lambda の実行ロールへ足りない権限を付与してあげます。
今回は下記をインラインポリシーへ追加しました。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "logs:CreateExportTask",
            "Resource": "arn:aws:aws:logs:ap-northeast-1:xxxxx:log-group:xxxxxx"
        }
    ]
}

Resources は適宜、吐き出したいロググループの arn を設定して上げてください。

arn がよく分からなければ、最悪下記でも。。。

"Resource": "*"

さてこれで権限は完了したので、もう一度 Lambda を叩きます。

エラー2つ目

An error occurred (InvalidParameterException) when calling the CreateExportTask operation: GetBucketAcl call on the given bucket failed. Please check if CloudWatch Logs has been granted permission to perform this operation.

これが2つ目のエラーです。

訳すと

CreateExportTask でエラーが発生したよ。
指定したバケットで GetBucketAcl 呼び出しに失敗したよ。
CloudWatch Logs がこの操作を実行する権限を与えられているかどうかを確認してね。

1つ目のエラーと比べて、固有名詞がゼロなエラーが帰ってきましたが、
絵にするとこんなことを言ってます。

S3 のバケットポリシーに 下記のようなポリシーを追加します。

CloudWatch が GetBucketAcl を叩きにきても OK!!

AWS っぽく言うと
プリンシパルが CloudWatch(logs.ap-northeast-1.amazonaws.com)のときに
s3:GetBucketAcl を許可します。

バケットポリシーに下記を追加します。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "logs.ap-northeast-1.amazonaws.com"
            },
            "Action": "s3:GetBucketAcl",
            "Resource": "arn:aws:s3:::xxxxxxxxxx"
        }
    ]
}

リソースは実際はバケットの arn を指定しておきましょう。

"Resources": "*"とかやると

Policy has invalid resource. (ポリシーが無効なリソース持ってる!!)

と AWS に怒られます。

Lambda を実行してみましょう!

エラー 3 つ目

An error occurred (InvalidParameterException) when calling the CreateExportTask operation: PutObject call on the given bucket failed. Please check if CloudWatch Logs has been granted permission to perform this operation.

2 つ目のエラーとほぼ一緒です。

こんなことを言ってます。

CreateExportTask でエラーが発生したよ。
指定したバケットで PutObject で S3 呼び出しに失敗したよ。
CloudWatch Logs がこの操作を実行する権限を与えられているかどうかを確認してね。

バケットポリシーを更新します。
具体的にはプリンシパルが CloudWatch のときに
指定したバケット内をリソースに PutObject を許可します。

バケットポリシーは下記のような感じになります 😊

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "logs.ap-northeast-1.amazonaws.com"
            },
            "Action": "s3:GetBucketAcl",
            "Resource": "arn:aws:s3:::xxxxxxxxxxxxx"
        },
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "logs.ap-northeast-1.amazonaws.com"
            },
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::xxxxxxxxxxxxx/*"
        }
    ]
}

さて、ここで Lambda を実行すると、、、

無事成功することができました!!

まとめ

Lambda で CloudWatch のログを S3 へ出力しようとしました。

そのためには Lambda のポリシーと、CloudWatch が S3 にアクセスできるようにバケットポリシーを追加して上げる必要がありました!

以上でした!😊

Author

Sisii

インフラが好きなエンジニアぶってるなにか