CloudWatch LogsをターゲットとするEventBridgeルールをCloudFormationで作成するには

2021.06.07

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

困っていた内容

Amazon EventBridge(旧 CloudWatch イベント)のログを CloudWatch Logs ロググループに転送する流れを CloudFormation で実現することはできますか?

または、

CloudFormation で作成したのですが、ログが記録されず、FailedInvocations となります。

どう対応すればいいの?

CloudFormation で EventBridge のルールを作成した上で、さらにリソースベースのポリシーが必要となります。

CloudFormation

コンソールを使って作成する方法が下記のブログにありますが、CloudFormation のテンプレートでも同様に AWS::Events::Rule を作成いただくだけでOKです。

以下、EC2 状態変更を検知するルールを作成したサンプルです。ここではターゲットのロググループも一緒に作成しています。

AWSTemplateFormatVersion: '2010-09-09'
Resources:
  RuleEc2StateChange:
    Type: AWS::Events::Rule
    Properties: 
      EventPattern: 
        {
          "source": [
            "aws.ec2"
          ],
          "detail-type": [
            "EC2 Instance State-change Notification"
          ]
        }
      Targets: 
        - Arn: !GetAtt LogGroupEc2StateChange.Arn
          Id: LogGroup

  LogGroupEc2StateChange:
    Type: AWS::Logs::LogGroup
    Properties:
      RetentionInDays: 3
      LogGroupName: /aws/events/Ec2StateChange

ただし、このルールが動作するには、次の CloudWatch Logs へのアクセスを許可するリソースベースのポリシーが必要です。
これがなくてもCloudFormationのリソース作成には成功しますが、いざ該当するイベントが発生してルールがトリガーされてもログが入らず、 FailedInvocations メトリクスが記録されることとなります。

リソースベースのポリシー

EventBridge ルールから CloudWatch Logs へのアクセスを許可するためには、CloudWatch Logs のリソースに対するポリシー(リソースベースのポリシー)が必要です。

以下のドキュメントの通り、このポリシーはマネジメントコンソールでのルール作成時に自動的に作成されますが、コンソールを使用しない場合はCLI等で自分で作成する必要があります。
IAMポリシーとは異なり、コンソール上で作成や管理をすることは(現時点では)できず、また紐づけるリソースをポリシー内で記述するため、ポリシーを作成するだけで良くて"アタッチ"をする必要はありません。

EventBridge がログストリームの作成とイベントのログへの記録を許可するには、CloudWatch Logs に EventBridge が CloudWatch Logs に書き込めるようにするリソースベースのポリシーを含める必要があります。AWS マネジメントコンソールを使用して CloudWatch Logs をルールのターゲットに追加する場合、このポリシーは自動的に作成されます。AWS CLI を使用してターゲットを追加する場合、このポリシーが存在しないときは作成する必要があります。

(ドキュメント:CloudWatch Logs のアクセス許可)

既存ポリシーの確認

もし、以前にコンソールから CloudWatch Logs をターゲットとした EventBridge ルールを作成している場合には、既にリソースベースのポリシーが存在しているはずです。ポリシーの有無は、DescribeResourcePoliciesを使って確認します。

% aws logs describe-resource-policies
{
    "resourcePolicies": [
        {
            "policyName": "TrustEventsToStoreLogEvents",
            "policyDocument": "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Sid\":\"TrustEventsToStoreLogEvent\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":[\"delivery.logs.amazonaws.com\",\"events.amazonaws.com\"]},\"Action\":[\"logs:CreateLogStream\",\"logs:PutLogEvents\"],\"Resource\":\"arn:aws:logs:eu-central-1:123456789012:log-group:/aws/events/*:*\"}]}",
            "lastUpdatedTime": 1622824080912
        }
    ]
}

policyDocumentの中身を確認すると、デフォルトで作成されるポリシーでは "Resource": "arn:aws:logs:::log-group:/aws/events/*:*\" のようにロググループ名でプレフィックスまで指定されています。つまり、「/aws/events/~」のロググループ名のみがターゲットとして許可されている状態です。

コンソール上でルール作成・ターゲット指定する際には、以下のようにデフォルトでこのプレフィックスが付与されます。
既存のロググループから選択する場合でも、このプレフィックスを持つロググループしか選択肢に表示されません。(キャプチャはEventBridgeですが、CloudWatchイベントのコンソールでも同様)

ただし、コンソールを使わなければ任意のロググループ名へログ配信するよう設定することも可能です。その場合には、リソースベースポリシーも次のように変更しましょう。

ポリシーの作成・変更

リソースベースのポリシーがまだ存在しない場合や、既存のものを変更する場合には、 PutResourcePolicy を使います。
必要な権限はドキュメントを参考にしています。

以下の例では、アイルランドリージョンのロググループ(プレフィックス指定なし)へログ配信の許可を付与しています。

aws logs put-resource-policy \
--policy-name "TrustEventsToStoreLogEvents" \
--policy-document '{
    "Statement": [
        {
            "Action": [
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Effect": "Allow",
            "Principal": {
                "Service": "events.amazonaws.com"
            },
            "Resource": "arn:aws:logs:eu-central-1:123456789012:log-group:*",
            "Sid": "TrustEventsToStoreLogEvent"
        }
    ],
    "Version": "2012-10-17"
}'

リソースベースのポリシーは CloudFormation では作成できないのか?

現在(2022.06)はこちらのドキュメントにあるように AWS::Logs::ResourcePolicy リソースを使うことで対応できるようです。(ご指摘感謝です!)

リソースベースのポリシーは、CloudFormation からの作成が現時点(2021.06)でサポートされていないようです。(以下参考)なので、まだ作成されていない場合には、上述のように CloudFormation とは別に手動で作成する必要があります。

なお、こちらのイシュー(#351)でもいろいろな意見が飛び交っておりますが、各種説について次の通り確認しました:

  • スタック内で一緒にIAMロールを作成し、それをルールのRoleArnで指定すれば動作する?

いいえ、リソースベースのポリシーは必要で、IAMロールで代替することはできません。IAMロールを作成・RoleArnに指定しても意味はありません。

  • ロググループ名は「/aws/events」で始まらなければならない?

いいえ、任意の名前のロググループへログ配信が可能です。ただし、上述の通りデフォルトのリソースベースポリシーではプレフィックス指定がされているので、必要に応じてポリシーを修正または作成してください。

関連記事

[アップデート] CloudWatch EventsのターゲットとしてCloudWatch Logsがサポートされました!

Amazon CloudWatch Events のログを Amazon CloudWatch Logs Insights で検索してみる!