TerraformでCloudWatchのクロスアカウントオブザーバビリティ設定

2023/12/17に公開

こちらの記事はFusic Advent Calendar 2023の16日目の記事です。

複数のアカウントの監視状況を一つのアカウントに集約してしまいたいという状況はよくあるかと思います。
というわけで、複数のアカウントに同じ設定をする用途としてはIaCが適していますので、今回はTerraformでその設定を試してみます。

環境

Terraform: v1.6.6

実装

データを集約するアカウント

まずはデータを集約する方のアカウントの設定をします。

resource "aws_oam_sink" "sink" {
  name = "cw-oam-sink"
}

resource "aws_oam_sink_policy" "policy" {
  sink_identifier = aws_oam_sink.sink.id
  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action   = ["oam:CreateLink", "oam:UpdateLink"]
        Effect   = "Allow"
        Resource = "*"
        Principal = {
          "AWS" = var.source_aws_accounts
        }
        Condition = {
          "ForAllValues:StringEquals" = {
            "oam:ResourceTypes" = [
              "AWS::CloudWatch::Metric",
              "AWS::Logs::LogGroup"
            ]
          }
        }
      }
    ]
  })
}

こちらが未設定の状態。

上記のTerraformを流すと、以下のようにモニタリングアカウントが有効になっていることが分かります。

この段階だとソースアカウントの設定はまだ行われておらず、空になっています。

データを送信するアカウント

次にデータを送る方のアカウントの設定を行っていきます。

resource "aws_oam_link" "link" {
  label_template = "$AccountName"
  resource_types = [
    "AWS::CloudWatch::Metric",
    "AWS::Logs::LogGroup"
  ]
  sink_identifier = var.oam_sink_id
}

aws_oam_sink のIDについては、単純にARNを入れてしまうか、terraform_remote_stateで取得すると良いかと思います。

ARNは「CloudWatch>設定>ソースアカウントを管理」の設定の詳細タブから確認することが出来ます。

上記のTerraformを流すとソースアカウントの設定でリンク済みになります。

「モニタリングアカウントを表示」ボタンを押して確認してみるとメトリクスとログが集約するアカウントに連携される設定になっています。

監視設定

データを集約する方と送信するアカウントの設定が完了して、数分〜10分ほど待つと集約するアカウントの方で2つのアカウントのメトリクスが確認できるようになってきます。

resource "aws_cloudwatch_metric_alarm" "ec2_cpu" {
  alarm_name          = "ec2-cpu-alarm"
  comparison_operator = "GreaterThanThreshold"
  evaluation_periods  = 3
  threshold           = 80
  alarm_description   = "This metric monitors EC2 cpu utilization"
  metric_query {
    account_id  = var.account_id
    id          = "m1"
    period      = 0
    return_data = true

    metric {
      dimensions = {
        "InstanceId" = var.instance_id
      }
      metric_name = "CPUUtilization"
      namespace   = "AWS/EC2"
      period      = 60
      stat        = "Average"
    }
  }
  insufficient_data_actions = []
}

上記のTerraformを流すとCloudWatchアラームが正常に作成されていることが確認できます。
注意点としては、メトリクスに使用するID(今回はインスタンスID)が一意なものだからといって、それだけを指定してアラームを作成しても、データを認識してくれません。そのため、アカウントIDをちゃんと指定してあげる必要があります。

まとめ

Terraformを利用してクロスアカウントオブザーバビリティ設定を行いました。
明示的に何かIAMロールを用意してあげるようなことも不要で、設定としてはかなり楽な印象です。
今回は1つのアカウントのデータを送信するだけでしたが、複数のアカウント情報をまとめる際は命名規則を適切に設定してからfor_eachで複数のアラームを設定する等Terraformの書き方は工夫が必要そうですね。

参考

Fusic 技術ブログ

Discussion