💭

Google CloudのサービスアカウントをTerraformで作る方法について

に公開

今回は、Google CloudのサービスアカウントをTerraformから作成する方法について調べてみました。最近K8sに加えてTerraformの学習もどんどん進めており、その勉強として今回はサービスアカウントを取り扱ってみます。

Google CloudでTerraformを試してみた系は以下のスクラップにまとめていますので合わせてご覧ください!

https://zenn.dev/akasan/scraps/c6182a7d763bc8

早速やってみる!

変数の作成

まずはGoogle CloudのプロジェクトIDやリージョンを設定するためにvariables.tfを以下のように作成しました。

variables.tf
variable "project_id" {
  description = "The Google Cloud project ID"
  type        = string
}

variable "region" {
  description = "The Google Cloud region"
  type        = string
  default     = "us-central1"
}

variable "service_account_id" {
  description = "Service account's id"
  type        = string
  default     = "my-service-account"
}

project_idにはプロジェクトIDが保存され、実行時に指定するようにします。regionはとりあえず設定してますが、サービスアカウントの作成には不要です。service_account_idにはサービスアカウントのIDを指定します。作成されるサービスアカウントのプリンシパルは<service_account_id>@<project_id>.iam.gserviceaccount.comのような形式になります。

ストレージ管理者ロールを与える

まずはサービスアカウントにCloud Storageの管理者ロールを与えるためのファイルをmain.tfに書いてみます。

main.tf
provider "google" {
  project = var.project_id
  region  = var.region
}

resource "google_service_account" "my_sa" {
  account_id   = var.service_account_id
  display_name = "My Service Account"
}

resource "google_project_iam_member" "my_sa_roles" {
  project = var.project_id
  role    = "roles/storage.admin"
  member  = "serviceAccount:${google_service_account.my_sa.email}"
}

まずgoogle_service_accountリソースによりサービスアカウントを作ります。リソース名はmy_saとし、アカウントIDはvar.service_account_idを通してvariables.tfで指定した内容を参照しています。

次にgoogle_project_iam_memberリソースによりサービスアカウントにロールを付与します。この例ではroles/storage.adminを指定して、ストレージ管理者を付与しています。

それではこの設定でterraform planを実行してみましょう。実行結果は以下のようになります。ない硫黄的にはサービスアカウントとそれに対するロールの付与について記載されていますね。問題なさそうです。

`terraform plan`実行結果

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

Terraform will perform the following actions:

# google_project_iam_member.my_sa_roles will be created
+ resource "google_project_iam_member" "my_sa_roles" {
  + etag    = (known after apply)
  + id      = (known after apply)
  + member  = "serviceAccount:my-service-account@project-id.iam.gserviceaccount.com"
  + project = "project-id"
  + role    = "roles/storage.admin"
}

# google_service_account.my_sa[0m will be created
+ resource "google_service_account" "my_sa" {
  + account_id   = "my-service-account"
  + disabled     = false
  + display_name = "My Service Account"
  + email        = "my-service-account@project-id.iam.gserviceaccount.com"
  + id           = (known after apply)
  + member       = "serviceAccount:my-service-account@project-id.iam.gserviceaccount.com"
  + name         = (known after apply)
  + project      = "project-id"
  + unique_id    = (known after apply)
}

Plan: 2 to add, 0 to change, 0 to destroy.
─────────────────────────────────────────────────────────────────────────────[0m

Note: You didn't use the -out option to save this plan, so Terraform can't
guarantee to take exactly these actions if you run "terraform apply" now.

それでは実際にterraform applyしてみましょう。applyした結果、Google Cloudコンソール上で指定した名前でサービスアカウントが作成され、ストレージ管理者のロールが付与されていることを確認できました。

複数ロールの付与

例えばさきほどのストレージ管理者に加えてPubSubのパブリッシャーロール(roles/pubsub.publisher)も加えてみましょう。この場合、二つのgoogle_project_iam_memberリソースを作ってもできますが、variables.tfでリストとしてロールを持っておき、それをfor_eachで回す形で一つのリソース定義ないで対応してみようと思います。

まずはvariables.tfに以下を追加します。この設定では、rolesという変数はデフォルトでroles/storage.adminroles/pubsub.publisherの二つのロールの情報をリストとして持つことになります。

variables.tf
variable "roles" {
  type    = list(string)
  default = ["roles/storage.admin", "roles/pubsub.publisher"]
}

次にmain.tfgoogle_project_iam_memberリソースを以下のように変更します。for_eactvar.rolesを指定し、roleeach.valueを指定することで、var.rolesが保持しているリストの値それぞれをroleに設定した場合のリソースを作成することができます。

main.tf
resource "google_project_iam_member" "my_sa_roles" {
  project  = var.project_id
  for_each = toset(var.roles)
  role     = each.value
  member   = "serviceAccount:${google_service_account.my_sa.email}"
}

それではこの変更に対してterraform planを実行してみます。結果を見ると、先ほど作成されたロールは一度削除され、新たに二つのロールをもったサービスアカウントとして作られるようです。

`terraform plan`実行結果
google_service_account.my_sa: Refreshing state... [id=projects/project_id/serviceAccounts/my-service-account@project_id.iam.gserviceaccount.com]
google_project_iam_member.my_sa_roles: Refreshing state... [id=project_id/roles/storage.admin/serviceAccount:my-service-account@project_id.iam.gserviceaccount.com][0m

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

Terraform will perform the following actions:

# google_project_iam_member.my_sa_roleswill be destroyed
# (because resource uses count or for_each)
- resource "google_project_iam_member" "my_sa_roles" {
  - etag    = "BwY+/wlu044=" -> null
  - id      = "project_id/roles/storage.admin/serviceAccount:my-service-account@project_id.iam.gserviceaccount.com" -> null
  - member  = "serviceAccount:my-service-account@project_id.iam.gserviceaccount.com" -> null
  - project = "project_id" -> null
  - role    = "roles/storage.admin" -> null
}

# google_project_iam_member.my_sa_roles["roles/pubsub.publisher"] will be created
+ resource "google_project_iam_member" "my_sa_roles" {
  + etag    = (known after apply)
  + id      = (known after apply)
  + member  = "serviceAccount:my-service-account@project_id.iam.gserviceaccount.com"
  + project = "project_id"
  + role    = "roles/pubsub.publisher"
}

# google_project_iam_member.my_sa_roles["roles/storage.admin"] will be created
+ resource "google_project_iam_member" "my_sa_roles" {
  + etag    = (known after apply)
  + id      = (known after apply)
  + member  = "serviceAccount:my-service-account@project_id.iam.gserviceaccount.com"
  + project = "project_id"
  + role    = "roles/storage.admin"
}

Plan: 2 to add, 0 to change, 1 to destroy.
─────────────────────────────────────────────────────────────────────────────

Note: You didn't use the -out option to save this plan, so Terraform can't
guarantee to take exactly these actions if you run "terraform apply" now.

それでは実行してみます。terraform applyを実行すると、以下のように追加したロールも付与されていることが確認できました。

最後にterraform destroyでリソースは削除しておきます。

まとめ

今回はTerraformを利用してGoogle Cloud上でサービスアカウントを作成し、ロールを付与するところを試してみました。サービスアカウント期限などの設定もできるようなので、今後利用するときはより詳細まで確認できたらと思います。

Discussion