ふり返る暇なんて無いね

日々のメモ書きをつらつらと。メインブログに書くほどでもないことを流してます

TerraformでEventBridgeのターゲットにCloudWatch Logsにするリソースを構築するとうまく動かない件

現象

Terraformで以下のようにECSイベントが発生した際にそれをCloudWatch Logsに出力するEventBridge ruleとtargetを作成したところ、うまくCloudWatch Logsにイベントが出力されませんでした。

resource "aws_cloudwatch_log_group" "main" {
  name              = "/aws/events/masasuzu/test/ecs/event"
  retention_in_days = 3
}

module "eventbridge" {
  source = "terraform-aws-modules/eventbridge/aws"

  create_bus = false
  create_role = false

  rules = {
    "masasuzu-test-ecs-event-log" = {
      event_pattern = jsonencode({
        "source" : ["aws.ecs"],
      })
      enabled = true
    }
  }

  targets = {
    "masasuzu-test-ecs-event-log" = [
      {
        name = "masasuzu-test-ecs-event-log"
        arn  = aws_cloudwatch_log_group.main.arn
      }
    ]
  }
}

試しにコンソールから同様のリソースを作成したところうまくCloudWatch Logsに出力され、Terraformで作ったEventBridgeも正しく動くようになりました。

ここからわかることはコンソールでEventBridgeの設定をした際に裏側で暗黙的になにかリソースが作られたということです。

原因

EventBridgeからCloudWatch Logsへの出力を許可するためにCloudWatch Logsのリソースポリシーを設定する必要があります。

まっさらなAWSアカウントでは以下のようにCloudWatch Logsのリソースポリシーが設定されています。何も設定されていません。

% aws logs describe-resource-policies --no-cli-pager
{
    "resourcePolicies": []
}

コンソールからEventBridgeの設定をすると以下のような設定が追加されます。これにより、EventBridgeからCloudWatch LogsへのPutLogEventsやCreateLogStreamが許可され、無事イベントがログに出力されるようになります。

% aws logs describe-resource-policies --no-cli-pager
{
    "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:ap-northeast-1:xxxxxxxxxx:log-group:/aws/events/*:*\"}]}",
            "lastUpdatedTime": 1705025982872
        }
    ]
}

対策

リソースポリシーを設定するために、以下のような記述を追加してあげると良いでしょう。

data "aws_iam_policy_document" "main" {
  statement {
    actions = [
      "logs:CreateLogStream",
      "logs:PutLogEvents",
    ]

    resources = ["arn:aws:logs:ap-northeast-1:${var.account_id}:log-group:${var.log_group_path}:*"]

    principals {
      identifiers = ["events.amazonaws.com"]
      type        = "Service"
    }
  }
}

resource "aws_cloudwatch_log_resource_policy" "main" {
  policy_document = data.aws_iam_policy_document.main.json
  policy_name     = "EventsToLog"
}

参考: CloudWatch Logs リソースへの許可の管理の概要 - Amazon CloudWatch Logs

参考: aws_cloudwatch_log_resource_policy | Resources | hashicorp/aws | Terraform | Terraform Registry