0
0

More than 1 year has passed since last update.

複数アカウントのメトリクスを1アカウントに集約するCloudWatchダッシュボードをTerraformで構築する

Posted at

はじめに

マルチアカウントで運用している環境で、同じメトリクスをいちいちスイッチロールしながら取得するのは面倒くさい。
CloudWatchダッシュボードを使えば、クロスアカウント設定でセレクタを切り替えながら確認することも可能だが、それも手間なので、一つのダッシュボードの画面で俯瞰できた方がいいよね!

ということで、やってみた。

なお、本記事は

  • CloudWatchメトリクスを触ったことがある
  • Terraformはある程度分かる

くらいの知識があることを前提としている。自分の書いた過去の記事でTerraform関連を読んで理解ができるのであれば、特に問題ないはずの難易度。

IAMロールを作成する

AWS公式のユーザーガイドに書かれているように、今回の対応をするには、集約する側のアカウントとされる側のアカウントにそれぞれ固定名のIAMロールが必要だ。
ためしにIAMロール名を変えて動かそうとしてみたが、Access Deniedになってしまった。

IAMポリシーはマネージドポリシーが用意されているので、以下のような固定名ロールを作れば良い。

################################################################################
# 集約する側のアカウント用                                                       #
#   存在しない場合のみ作成                                                       #
################################################################################
resource "aws_iam_role" "cloudwatch_monitoringaccount" {
  name               = "AWSServiceRoleForCloudWatchCrossAccount"
  assume_role_policy = data.aws_iam_policy_document.cloudwatch_monitoringaccount_assume.json
}

data "aws_iam_policy_document" "cloudwatch_monitoringaccount_assume" {
  statement {
    effect = "Allow"

    actions = [
      "sts:AssumeRole",
    ]

    principals {
      type = "Service"
      identifiers = [
        "cloudwatch-crossaccount.amazonaws.com",
      ]
    }
  }
}

resource "aws_iam_role_policy_attachment" "cloudwatch_monitoringaccount" {
  role       = aws_iam_role.cloudwatch_monitoringaccount.name
  policy_arn = "arn:aws:iam::aws:policy/aws-service-role/CloudWatch-CrossAccountAccess"
}

################################################################################
# 集約される側のアカウント用                                                     #
#   存在しない場合のみ作成                                                       #
################################################################################
resource "aws_iam_role" "cloudwatch_crossaccount" {
  provider = aws.cross_account

  name               = "CloudWatch-CrossAccountSharingRole"
  assume_role_policy = data.aws_iam_policy_document.cloudwatch_crossaccount_assume.json
}

data "aws_iam_policy_document" "cloudwatch_crossaccount_assume" {
  statement {
    effect = "Allow"

    actions = [
      "sts:AssumeRole",
    ]

    principals {
      type = "AWS"
      identifiers = [
        "arn:aws:iam::${data.aws_caller_identity.self.account_id}:root",
      ]
    }
  }
}

resource "aws_iam_role_policy_attachment" "cloudwatch_crossaccount1" {
  provider = aws.cross_account

  role       = aws_iam_role.cloudwatch_crossaccount.name
  policy_arn = "arn:aws:iam::aws:policy/CloudWatchReadOnlyAccess"
}

resource "aws_iam_role_policy_attachment" "cloudwatch_crossaccount2" {
  provider = aws.cross_account

  role       = aws_iam_role.cloudwatch_crossaccount.name
  policy_arn = "arn:aws:iam::aws:policy/CloudWatchAutomaticDashboardsAccess"
}

Terraformプロバイダ設定

クロスアカウントで動かすので、Terraformプロバイダを複数設定する。
cross_account側の設定は、あらかじめaws configure --profile myenvで設定しておくようにしよう。
shared_config_filesshared_credentials_filesの位置は適宜変更すること。

provider "aws" {
  region = "ap-northeast-1"
}

provider "aws" {
  alias = "cross_account"

  shared_config_files      = ["/home/username/.aws/config"]
  shared_credentials_files = ["/home/username/.aws/credentials"]
  profile                  = "myenv"

  region                   = "ap-northeast-1"
}

CloudWatchダッシュボードを作る

CloudWatchダッシュボードは、Terraformの公式ドキュメントを見てわかるとおり、ほとんどがCloudWatchのダッシュボードの構造体のJSONを書くだけだ。[AWS公式のユーザーガイド]を見つつ書いていこう。

今回はサンプルとしてElastic Load BalancingTargetGroupsPerRegionで作ってみる。

なお、アカウントIDは直接書くと当然ながら危険なので、aws_caller_identityデータソースでProviderの設定から引っ張ってこよう。
同じ情報を並べて確認したいので、せっかくだからTerraformの構文でfor文を使って回して、jsonencodeで整形してあげると、コード量が減ってナイスな感じになる。

data "aws_caller_identity" "self" {}

data "aws_caller_identity" "cross_account" {
  provider = "aws.cross_account"
}

locals {
  accounts = [
    { graph_title = "MyAccount", account_id = data.aws_caller_identity.self.account_id },
    { graph_title = "CrossAccount", account_id = data.aws_caller_identity.cross_account.account_id },
  ]
}

resource "aws_cloudwatch_dashboard" "example" {
  dashboard_name = "cloudwatch-dashboard-example"
  dashboard_body = jsonencode({
    widgets = [
      for account in local.accounts :
      {
        type = "metric"

        properties = {
          title   = account.graph_title
          view    = "timeSeries"
          stacked = false
          region  = "ap-northeast-1"
          stat    = "Average"
          period  = 300
          metrics = [
            [
              "AWS/Usage",
              "ResourceCount",
              "Type",
              "Resource",
              "Resource",
              "TargetGroupsPerRegion",
              "Service",
              "Elastic Load Balancing",
              "Class",
              "None",
              {
                "accountId" = account.account_id
              },
            ]
          ]
        }
      }
    ]
  })
}

いざ、確認!

さて、ここまでできたら完成だ。terraform applyしてコンソールで見てみよう。

キャプチャ.png

できた!
クロスアカウントのメトリクスは右上に「xa」のアイコンが表示され、クリックするとこのようにアカウントIDを確認することも可能だ。

キャプチャ2.png

これで、見やすいダッシュボードを作成することができるようになった!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0