LoginSignup
2
2

More than 3 years have passed since last update.

Terraformで総当たりの組み合わせtupleを生成する

Last updated at Posted at 2021-05-05

Google IAMのメンバー設定を記述していて、いちいち resource を繰り返し定義するのがバカらしくなったので調べてみました。

やりたいこと

2つのサービスアカウント、3つのロールについて、 google_project_iam_member を設定する

サービスアカウント

  • compute-engine@hogehoge.iam.gserviceaccount.com
  • cloud-functions@hogehoge.iam.gserviceaccount.com

ロール

  • roles/bigquery.jobUser
  • roles/bigquery.dataViewer
  • roles/bigquery.dataEditor

愚直に書くと…

resource "google_project_iam_member" "computeEngine-bigquery_jobUser" {
  role   = "roles/bigquery.jobUser"
  member = "serviceAccount:compute-engine@hogehoge.iam.gserviceaccount.com"
}

面倒くさいこと

  • これを2 * 3 = 6回書かなければならない
    • もし 3 * 4 になると12回も書かなければならない
  • それぞれユニークに名付ける
  • 抜け漏れ確認
  • 対象ロールやサービスアカウントが増えたらまたコピペ地獄

ループしちゃえ

サービスアカウント、ロールの配列を定義

locals {
  # サービスアカウント、ロールの配列を定義
  service_accounts = [
    "compute-engine@hogehoge.iam.gserviceaccount.com",
    "cloud-functions@hogehoge.iam.gserviceaccount.com"
  ]
  roles = [
    "roles/bigquery.jobUser",
    "roles/bigquery.dataViewer",
    "roles/bigquery.dataEditor",
  ]

  # setproduct で総当りの組み合わせをループしながらtupleを作る(ついでにmemberを加工)
  iam_members = [
    for pair in setproduct(local.roles, local.service_accounts) : {
      role   = pair[0]
      member = "serviceAccount:${pair[1]}"
    }
  ]
}

この時点で output で確認してみるとこのようになります。

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:

Terraform will perform the following actions:

Plan: 0 to add, 0 to change, 0 to destroy.

Changes to Outputs:
  + iam_members = [
      + {
          + member = "serviceAccount:compute-engine@hogehoge.iam.gserviceaccount.com"
          + role   = "roles/bigquery.jobUser"
        },
      + {
          + member = "serviceAccount:cloud-functions@hogehoge.iam.gserviceaccount.com"
          + role   = "roles/bigquery.jobUser"
        },
      + {
          + member = "serviceAccount:compute-engine@hogehoge.iam.gserviceaccount.com"
          + role   = "roles/bigquery.dataViewer"
        },
      + {
          + member = "serviceAccount:cloud-functions@hogehoge.iam.gserviceaccount.com"
          + role   = "roles/bigquery.dataViewer"
        },
      + {
          + member = "serviceAccount:compute-engine@hogehoge.iam.gserviceaccount.com"
          + role   = "roles/bigquery.dataEditor"
        },
      + {
          + member = "serviceAccount:cloud-functions@hogehoge.iam.gserviceaccount.com"
          + role   = "roles/bigquery.dataEditor"
        },
    ]

ちゃんと6つの要素ができています。

resource で利用する

# "${item.member}__${item.role}" はリソースの名前になるため、ユニークなキーにしなければならない

resource "google_project_iam_member" "iam_members" {
  for_each = { for item in local.iam_members : "${item.member}__${item.role}" => item }

  # each.key は "${item.member}__${item.role}"
  role = each.value.role
  member = each.value.member
}

もちろん、 locals.iam_members を定義せず、 resource 内でインライン利用することもできます。
locals にロジックを書きたくない場合はこちらもアリかもですね。

resource "google_project_iam_member" "iam_members" {
  for_each = {
    for item in [
      for pair in setproduct(local.roles, local.service_accounts) : {
        role   = pair[0]
        member = "serviceAccount:${pair[1]}"
      }
    ] : "${item.member}__${item.role}" => item
  }

  role   = each.value.role
  member = each.value.member
}

参考

2
2
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
2
2