📝

Lambda 実行時にログストリームは作成されるのにログが出力されない時の解決策

2023/07/18に公開

Lambda 実行時にログストリームは作成されるもののログが出力されない事象について、面白い挙動があったので紹介します。

結論

  • ロググループから KMS CMK へのアクセス権限がないことが原因
  • KMS のキーポリシーでロググループからのアクセスを許可すれば解決

背景

Lambda のログを KMS で暗号化する方法に関するドキュメントを読んでいる時に、ロググループから KMS へのアクセス権がない場合の挙動が気になったことがきっかけでした。

検証内容

  • デフォルト設定で Lambda 関数を作成
    • ログ出力できることを確認
  • KMS CMK を作成
  • CMK をロググループに関連付ける
    • ログ出力できることを確認
  • CMK のキーポリシーを変更
    • ログ出力できないことを確認
  • CMK のキーポリシーを元に戻す
    • ログ出力できることを確認
    • ログ出力できなかった期間のログも出力されることを確認

デフォルト設定で Lambda 関数を作成

まずはテスト用にデフォルト設定で Lambda 関数を作成します。

コードや IAM ロールの権限は変更していません。
ちなみにデフォルトの IAM ロールの権限には CloudWatch Logs にログを出力するための権限が自動的に付与されています。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "logs:CreateLogGroup",
            "Resource": "arn:aws:logs:ap-northeast-1:012345678901:*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": [
                "arn:aws:logs:ap-northeast-1:012345678901:log-group:/aws/lambda/test:*"
            ]
        }
    ]
}

ログ出力できることを確認

Lambda をテスト実行してログ出力できることを確認します。

ロググループ /aws/lambda/test にログが出力されていることを確認できました。

KMS CMK を作成

ドキュメントに記載されている通り、ロググループのデータは常に暗号化されます。デフォルトではサーバー側の暗号化を実施しているのでユーザー側での暗号化設定は不要ですが、KMS CMK で暗号化することも可能です。

AWS Key Management Service を使用して CloudWatch Logs のログデータを暗号化する - Amazon CloudWatch Logs

ロググループのデータは常に CloudWatch Logs で暗号化されます。デフォルトでは、CloudWatch Logs は保管中のログデータに対してサーバー側の暗号化を使用します。別の方法として、この暗号化には AWS Key Management Service を使用できます。その場合、暗号化は AWS KMS カスタマーマネージドキーを使用して行われます。AWS KMS を使用した暗号化は、ロググループの作成時または作成後に、キーとロググループを関連付けることにより、ロググループレベルで有効になります。

Lambda の実行によって自動的に作成されたロググループを確認すると、「KMS キー ID」の項目があります。
この時点では CMK を関連付けていないためキー ID は表示されていません。

上記ドキュメントに沿って CMK の作成も CloudShell から AWS CLI で実施します。

CMK を作成します。

aws kms create-key

{
    "KeyMetadata": {
        "AWSAccountId": "012345678901",
        "KeyId": "ca8ef4df-4d3c-4fc5-98aa-cd088e22cf77",
        "Arn": "arn:aws:kms:ap-northeast-1:012345678901:key/ca8ef4df-4d3c-4fc5-98aa-cd088e22cf77",
        "CreationDate": "2023-07-18T09:45:41.649000+00:00",
        "Enabled": true,
        "Description": "",
        "KeyUsage": "ENCRYPT_DECRYPT",
        "KeyState": "Enabled",
        "Origin": "AWS_KMS",
        "KeyManager": "CUSTOMER",
        "CustomerMasterKeySpec": "SYMMETRIC_DEFAULT",
        "KeySpec": "SYMMETRIC_DEFAULT",
        "EncryptionAlgorithms": [
            "SYMMETRIC_DEFAULT"
        ],
        "MultiRegion": false
    }
}

キーポリシーを設定します。

aws kms get-key-policy --key-id key-id --policy-name default --output text > ./policy.json
nano policy.json

デフォルトのキーポリシーを削除して、ドキュメントに記載されているポリシーで上書きします。

{
    "Version": "2012-10-17",
    "Id": "key-default-1",
    "Statement": [
        {
            "Sid": "Enable IAM User Permissions",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::Your_account_ID:root"
            },
            "Action": "kms:*",
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "logs.region.amazonaws.com"
            },
            "Action": [
                "kms:Encrypt*",
                "kms:Decrypt*",
                "kms:ReEncrypt*",
                "kms:GenerateDataKey*",
                "kms:Describe*"
            ],
            "Resource": "*",
            "Condition": {
                "ArnLike": {
                    "kms:EncryptionContext:aws:logs:arn": "arn:aws:logs:region:account-id:*"
                }
            }
        }    
    ]
}
cat policy.json

{
    "Version": "2012-10-17",
    "Id": "key-default-1",
    "Statement": [
        {
            "Sid": "Enable IAM User Permissions",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::012345678901:root"
            },
            "Action": "kms:*",
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "logs.ap-northeast-1.amazonaws.com"
            },
            "Action": [
                "kms:Encrypt*",
                "kms:Decrypt*",
                "kms:ReEncrypt*",
                "kms:GenerateDataKey*",
                "kms:Describe*"
            ],
            "Resource": "*",
            "Condition": {
                "ArnLike": {
                    "kms:EncryptionContext:aws:logs:arn": "arn:aws:logs:ap-northeast-1:012345678901:*"
                }
            }
        }    
    ]
}

キーポリシーを更新します。

aws kms put-key-policy --key-id key-id --policy-name default --policy file://policy.json

CMK をロググループに関連付ける

CloudWatch コンソールを使用して CMK をロググループと関連付けることはできないため、AWS CLI を使用して関連付けます。

AWS Key Management Service を使用して CloudWatch Logs のログデータを暗号化する - Amazon CloudWatch Logs

CloudWatch コンソールを使用して、カスタマーマネージドキーをロググループと関連付けることはできません。

まずはロググループに CMK が関連付けられていないことを確認します。

aws logs describe-log-groups --log-group-name-prefix "log-group-name-prefix"

{
    "logGroups": [
        {
            "logGroupName": "/aws/lambda/test",
            "creationTime": 1689651341777,
            "metricFilterCount": 0,
            "arn": "arn:aws:logs:ap-northeast-1:012345678901:log-group:/aws/lambda/test:*",
            "storedBytes": 0
        }
    ]
}

ドキュメントに記載されている通り、レスポンスに kmsKeyId が含まれていない場合、CMK はロググループに関連付けられていません。

CMK を新規作成するロググループに関連付けるには create-log-group コマンドを使用しますが、今回は既存のロググループに関連づけるため、associate-kms-key コマンドを使用します。

aws logs associate-kms-key --log-group-name my-log-group --kms-key-id "key-arn"

再度 describe-log-groups コマンドで関連付けられたことを確認します。

aws logs describe-log-groups --log-group-name-prefix "log-group-name-prefix"

{
    "logGroups": [
        {
            "logGroupName": "/aws/lambda/test",
            "creationTime": 1689651341777,
            "metricFilterCount": 0,
            "arn": "arn:aws:logs:ap-northeast-1:012345678901:log-group:/aws/lambda/test:*",
            "storedBytes": 0,
            "kmsKeyId": "arn:aws:kms:ap-northeast-1:012345678901:key/ca8ef4df-4d3c-4fc5-98aa-cd088e22cf77"
        }
    ]
}

レスポンスに kmsKeyId が含まれているため CMK がロググループに関連付けられています。

ログ出力できることを確認

この段階では CMK のキーポリシーでロググループからのアクセスを許可しているのでログ出力可能です。
Lambda をテスト実行してログ出力できることを確認します。


ロググループ /aws/lambda/test にログが出力されていることを確認できました。

CMK のキーポリシーを変更

CMK のキーポリシーをロググループからアクセスできないように変更します。
今回は KMS のコンソールから変更しました。

  • ロググループからのアクセス許可を定義していた Statement を削除
  • arn:aws:iam::012345678901:root でのアクセスを特定の IAM ロールのみからアクセスに変更
{
    "Version": "2012-10-17",
    "Id": "key-default-1",
    "Statement": [
        {
            "Sid": "Enable IAM User Permissions",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::012345678901:role/OrganizationAccountAccessRole"
            },
            "Action": "kms:*",
            "Resource": "*"
        }
    ]
}

上記キーポリシーへ変更することで特定の IAM ロール以外は CMK へアクセスできなくなりました。

ログ出力できないことを確認

CMK のキーポリシーでロググループからのアクセスができないように変更したので、Lambda をテスト実行してログ出力できなくなったことを確認します。

ログストリームは作成されているもののログが出力されていません。
ログストリームの作成は Lambda の IAM ロールの権限で実行されますが、ログ出力のための暗号化処理でロググループから CMK へのアクセス権がないためログ出力処理が停止しているようです。

CMK のキーポリシーを元に戻す

CMK のキーポリシーを元に戻してロググループからのアクセスを許可します。

{
    "Version": "2012-10-17",
    "Id": "key-default-1",
    "Statement": [
        {
            "Sid": "Enable IAM User Permissions",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::Your_account_ID:root"
            },
            "Action": "kms:*",
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "logs.region.amazonaws.com"
            },
            "Action": [
                "kms:Encrypt*",
                "kms:Decrypt*",
                "kms:ReEncrypt*",
                "kms:GenerateDataKey*",
                "kms:Describe*"
            ],
            "Resource": "*",
            "Condition": {
                "ArnLike": {
                    "kms:EncryptionContext:aws:logs:arn": "arn:aws:logs:region:account-id:*"
                }
            }
        }    
    ]
}

ログ出力できることを確認

Lambda をテスト実行してログ出力できることを確認します。


ログ出力されています。
しかも先ほど出力されなかった分のログも出力されています。

CMK へアクセスできなかった期間のログがどの程度内部で保存されているのかは不明ですが、CMK へのアクセスができるようになった段階で出力されるという面白い挙動でした。

CloudTrail の記録に残らない

通常 KMS キーでの EncryptDecrypt は CloudTrail に記録されますが、ロググループからのアクセスについては記録がありませんでした。

そのため、ログが出力されない原因がアクセス権限の問題であるというトラブルシューティングが難しくなりそうだと思いました。

まとめ

今回は Lambda 実行時にログストリームは作成されるもののログが出力されない事象について検証してみました。

CloudTrail では調査が難しい事象でしたが、一部の Lambda でログが出力されないという事象が発生した場合には CMK へのアクセス権限を確認することも有用だと思います。

今回の内容がどなたかの参考になれば幸いです。

参考資料

Discussion