TerraformをGCPで使う時の注意点 著者: tkow

弊社ではGCPをterraformで管理し始めました。知見が溜まってきているのでここにまとめておこうと思います。

組織を管理する

MOCHI.incでは組織アカウントの管理も全てterraformとcloud identityを経由して管理しています。

MOCHI.incでやりたかったことは

  • folder単位で組織のグループ作ってグループに最低権限を与える
  • folder内にadmin用のprojectでservice accountを作ってfolderに対して課金とプロジェクト作成の権限を与える
  • leaderとmemberのグループを作って開発環境ごとに編集権限を与える、leaderには課金とプロジェクト作成の権限を与える
  • CI用にはservice accountでterraformを動かす、個人マシンでは個人のアカウントでterraformを動かす

ということでした。

data "google_iam_policy" "admin_project" {
  binding {
    role = "roles/viewer"

    members = var.leader_control_group
  }

  binding {
    role = "roles/storage.admin"

    members = var.leader_control_group
  }
}

resource "google_project_iam_policy" "project" {
  project = var.admin_project_id
  policy_data = data.google_iam_policy.admin_project.policy_data
}

data "google_iam_policy" "admin_project_service_account_owner" {
  binding {
    role = "roles/iam.serviceAccountUser"

    members = var.owner_control_group
  }
}

resource "google_service_account_iam_policy" "terraform" {
  service_account_id = var.terraform_service_account.name
  policy_data = data.google_iam_policy.admin_project_service_account_owner.policy_data
}

resource "google_organization_iam_binding" "billing" {
  org_id = var.organization_id

  role = "roles/billing.user"

  members = var.leader_control_group
}

data "google_iam_policy" "service_folder_policy" {
  binding {
    role = "roles/resourcemanager.projectCreator"
    members = var.leader_control_group
  }

  binding {
    role = "roles/owner"
    members = var.owner_control_group
  }
}

resource "google_folder_iam_policy" "project_folder" {
  folder      = "folders/${var.project_folder_id}"
  policy_data = data.google_iam_policy.service_folder_policy.policy_data
}

実際に以上のことを実現するために書かれたterraformのコードになります。

Cloud IdentityのアカウントはG Suiteと連携しているので、terraformでdestroyする時には十分注意してください。terraformでGCPのリソースをいじれるようにするために課金を有効にする必要がありますが、この課金アカウントだけはorganizationにiamを登録する必要があります。

ここでgoogleorganizationiambindingを誤って、googleorganization_iam resourceで書いてしまって実行すると、既存のアカウントを全て作り直してしまって、組織全員のiamが吹きとんでしまうという大事故が起きるのでapply前の確認を怠らないようにしましょう。

また、organization_iamに限らず、GCPのterraformのresource内のbindingの記述はリソースを作り直してしまうのでbindingの追加はgoogle_~_bindingまたは、google_~_memberのようにbindingを紐づけるだけのAPIを利用しましょう。 (追記: binding系のAPIはroleに対して未定義のresourceの権限を奪ってしまうようです。memberやserviceアカウントにroleを紐づける場合はgoogle_project_iam_member等のAPIを利用しましょう。)

開発環境ごとにプロジェクトを作成する

MOCHIのインフラはprojectを複数に分割しています。

GCPのブログ を参考にしました。

この仕組みに加えて、最初のgcsはローカル上のterraformで作るようにしてあります。

terraform-adminアカウントにmembershipを用いて、

Terraformで認証する

gcloud auth application-default login

を利用することでTerraformのサービスアカウントを利用せずにTerraformを実行できるようになります。 注意点は

gcloud config set project $project_id

によって現在の操作対象のGCPプロジェクトを変更した場合、

gcloud auth application-default loginを実行し直す必要が生じます。

また、利用しているGCPプロジェクトを削除すると、このプロジェクトにログインしているアカウントに紐づいているロールが仮に他のGCPプロジェクトに対するロールを保持しているユーザーでログインした場合でも、他のプロジェクトにログインし直すまで、GCPプロジェクトを対象にした操作ができなくなるようです。

このためdev環境を削除したりリソースをコマンド経由で操作するためにプロジェクトを切り替えていることを忘れると、プロジェクトへのterraform applyが通らなくて焦ったりするわけですが、adminアカウントに切り替えることできちんとapplyが通るようになりました。

サービスアカウントの検索

サービスアカウントの検索などでは

--labels="cloudidentity.googleapis.com/groups.discussion_forum"

というフラグが必須になっていたりします。これは、Googleがこのタグをサービスアカウントの識別に利用しているためで、このタグにはvalueをつけるように設定できるような仕様になっていますが、このタグは、valueなしのタグとして設定されているため、サービスアカウントを検索する場合はタグ名だけを指定するという仕様になっています。

これは非常に分かりづらい仕様なので、おそらくbetaたる所以なのかなと思いますが、このAPIからサービスアカウトの情報や情報を取得するケースが非常に多かったので、覚えておくと良いかもしれません。

gcloud beta identity groups search --labels="cloudidentity.googleapis.com/groups.discussion_forum" --organization='${organization name}'