TerraformでCloudWatchイベントのターゲット先に「別アカウントのイベントバス」を設定してみた

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

こんにちは、コンサルティング部の後藤です。

先日CloudWatchイベントルールの作成をTerraformで行いました。その時、ターゲットを「別アカウントのイベントバスを指定」にする必要があったのですが、Terraformで設定する際に少し分かりにくかったので備忘録になります。

Terraformバージョン

本記事は以下のバージョンを使用して実行しています。

$ terraform --version
Terraform v0.12.29
+ provider.aws v3.4.0

CloudWatchイベント作成

TerraformでCloudWatchイベントを作成する場合、イベントソースとターゲットでresourceが異なります。

まず、イベントソースのみ指定したルールを作成します。今回はイベントソースとしてGuardDutyを指定しています。

resource "aws_cloudwatch_event_rule" "rule" {
        name = "test-rule"

        event_pattern = <<EOF
{
        "source" : [
                "aws.guardduty"
        ],
        "detail-type": [
                "GuardDuty Finding"
        ]
}
EOF
}

Terraformを実行してマネージドコンソールを確認すると、ルールが作成されていることがわかります。

CloudWatchイベントのターゲットを設定

TerraformでCloudWatchイベントのターゲットを設定する場合、resource "aws_cloudwatch_event_target"を使用します。   ドキュメントがこちらになるのですが、ECSやKinesis、Batch等をターゲットにした設定値はあるのに対して、「別アカウントのイベントバスを指定」で使用する設定値が見当たらないので、一度手動で設定し、Terraformにimportしてどの項目を設定すれば良いか確認してみました。

ターゲット設定をTerraformにimportするためにtarget-idが必要になるため、AWS CLIで取得します。

$ aws events list-targets-by-rule --rule 【ルール名】
{
    "Targets": [
        {
            "Id": "Id441716527535", # ここ!
            "Arn": "arn:aws:events:ap-northeast-1:123456789010:event-bus/default",
            "RoleArn": "arn:aws:iam::010987654321:role/service-role/AWS_Events_Invoke_Event_Bus_1500696013"
        }
    ]
}

Terraform importを実行する前にresourceを以下のように定義しました。

resource "aws_cloudwatch_event_target" "target" {
  rule = "hoge"
  arn = ""
}

取得したtarget-idを使用してimportを実行します。

$ terraform import aws_cloudwatch_event_target.target 【ルール名】/【target-id】

# 実行例
$ terraform import aws_cloudwatch_event_target.target test-rule/Id441716527535
aws_cloudwatch_event_target.target: Importing from ID "test-rule/Id441716527535"...
aws_cloudwatch_event_target.target: Import prepared!
  Prepared aws_cloudwatch_event_target for import
aws_cloudwatch_event_target.target: Refreshing state... [id=test-rule-Id441716527535]

Import successful!

The resources that were imported are shown above. These resources are now in
your Terraform state and will henceforth be managed by Terraform.

import後、terraform planで不足している値を確認すると、

  # aws_cloudwatch_event_target.target must be replaced
-/+ resource "aws_cloudwatch_event_target" "target" {
      - arn       = "arn:aws:events:ap-northeast-1:xxxxxxxxx:event-bus/default" -> null
      ~ id        = "test-rule-Id441716527535" -> (known after apply)
      - role_arn  = "arn:aws:iam::xxxxxxxxxx:role/service-role/AWS_Events_Invoke_Event_Bus_1500696013" -> null
      ~ rule      = "test-rule" -> "hoge" # forces replacement
      ~ target_id = "Id441716527535" -> (known after apply)
    }

arn / rule / role_arn の値だけで「別アカウントのイベントバスを指定」は設定出来そうです。
上記結果を参考に、以下のようなTerraformを書いてみました。

$ cat cw_event.tf 
## IAMポリシー作成
resource "aws_iam_policy" "policy" {
  name   = "cw-test-policy"
  policy = <<EOF
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "events:PutEvents"
            ],
            "Resource": [
                "arn:aws:events:*:123456789010:event-bus/default"
            ]
        }
    ]
}
EOF
}

## IAMロール作成
resource "aws_iam_role" "role" {
  name = "cw-test-role"

  assume_role_policy = <<EOF
{
      "Version": "2012-10-17",
      "Statement": [
        {
          "Action": "sts:AssumeRole",
          "Principal": {
            "Service": "events.amazonaws.com"
          },
          "Effect": "Allow",
          "Sid": ""
        }
      ]
    }
EOF
}

## IAMロールにIAMポリシーをアタッチ
resource "aws_iam_role_policy_attachment" "attach" {
  role       = aws_iam_role.role.name
  policy_arn = aws_iam_policy.policy.arn
}

## CloudWatchイベント作成
resource "aws_cloudwatch_event_rule" "rule" {
  name = "test2-rule"

  event_pattern = <<EOF
{
        "source" : [
                "aws.guardduty"
        ],
        "detail-type": [
                "GuardDuty Finding"
        ]
}
EOF
}

## CloudWatchイベントのターゲット設定
resource "aws_cloudwatch_event_target" "target" {
  rule     = aws_cloudwatch_event_rule.rule.name
  arn      = "arn:aws:events:ap-northeast-1:662149051709:event-bus/default"
  role_arn = aws_iam_role.role.arn
}

AWSマネージドコンソールでターゲットを設定すると自動でIAMロールを作成、設定してくれますが、Terraformでターゲットを設定する場合はIAMロールを作成してあげる必要がありました。

上記Terraformを実行してAWSマネージドコンソールを確認してみると、「別のAWSアカウントのイベントバス」でターゲットが設定されたCloudWatchイベントが作成されていました。

まとめ

TerraformでCloudWatchイベントの作成、ターゲットに「別のAWSアカウントのイベントバス」を指定する方法を紹介しました。かなり小ネタなTipsになりましたが、どなたかのお役に立てば幸いです。