Terraform to manage GCP Service Accounts
2022-06-30
TerraformGCPThe Google provider of Terraform has some mechanisms to manage Service Accounts in GCP as followings.
- google_service_account_iam
- google_service_account_iam_policy
- google_service_account_iam_binding
- google_service_account_iam_member
- google_project_iam
- google_project_iam_policy
- google_project_iam_binding
- google_project_iam_member
tl;dr
Strongly recommend using google_service_account_iam_member
and google_project_iam_member
to manage GCP service accounts.
Not use google_service_account_iam_policy
and google_project_iam_policy
.
google_service_account_iam
This resource is to configure GCP service accounts that perform operations within a resource.
Meaning that if a service account doesn't need to interact with other GCP resources, google_service_account_iam
is the best choice over google_project_iam
.
As the document describes, google_service_account_iam_policy
and google_service_account_iam_binding
are Authoritative, which is possible to delete existing resources that are not managed by terraform.
Thus, I recommend using google_service_account_iam_member
resource over another two since only google_service_account_iam_member
performs additive operation, it's a little bit boring to configure all pairs of roles and members though.
Indeed, my service account for applying terraform plans was locked out because of wrong usage of google_service_account_iam
, then subsequent apply failed due to lack of permission because the service account had been deleted unexpectedly.
google_project_iam
As I described above, google_project_iam
is to configure GCP service accounts that need to interact with other GCP resources.
So, basically we can use google_service_account_iam
, but sometimes we have to use it.
For example, it requires google_project_iam
configurations for giving a permission (roles/cloudsql.client
) on a Cloud Run resource to act as a client for a Cloud SQL instance.
https://cloud.google.com/sql/docs/mysql/roles-and-permissions
This code snippet shows how google_project_iam_member
can be used in configuring the above scenario.
resource "google_project_iam_member" "cloud_sql_client" {
project = "${var.gcp_project}"
role = "roles/cloudsql.client"
member = "serviceAccount:${local.cloud_sql_service_accounts_email}"
condition {
expression = "resource.name == '${google_sql_database_instance.my_database.id}' && resource.type == 'sqladmin.googleapis.com/Instance'"
title = "cloudsql.client policy"
description = "Cloud SQL instance client"
}
}
https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/google_project_iam
This document describes google_project_iam
resources and also it mentions that wrong usage of google_project_iam_policy
may lock yourself out of your project.
It's the reason why I recommend using google_project_iam_member
rather than google_project_iam_policy
.
In addition, there is google_project_iam_binding
, but it's also marked as "authoritive", whereas google_project_iam_member
is "Non-authoritive".
"Authoritive" means that it's possible to delete existing resources by following given configurations.
So, even though it takes a time to configure all of role and member mappings, using google_project_iam_member
is the safest way, I believe.
How to configure Service Accounts by Terraform
Basic usage of google_service_account_iam_member
looks like below.
resource "google_service_account" "sa" {
account_id = "my-sa"
display_name = "my ServiceAccount"
}
resource "google_service_account_iam_member" "sa_run" {
service_account_id = google_service_account.sa.name
role = "roles/run.serviceAgent"
member = "serviceAccount:${google_service_account.sa.email}"
}
First of all, creating a service account is done by google_service_account
resource, then giving a role to the created service account.
As another example, creating a service account for operating GitHub Actions that needs to deploy Cloud Run.
resource "google_service_account" "github_actions" {
account_id = "github-actions"
display_name = "github-actions"
}
locals {
# https://cloud.google.com/run/docs/deploying-source-code#permissions_required_to_deploy
github_actions_roles = [
"roles/run.admin",
"roles/cloudbuild.builds.editor",
"roles/storage.admin",
"roles/viewer",
"roles/artifactregistry.admin",
]
}
resource "google_project_iam_member" "github_actions" {
count = length(local.github_actions_roles)
project = var.gcp_project
role = local.github_actions_roles[count.index]
member = "serviceAccount:${google_service_account.github_actions.email}"
}
As the same with the previous example, create a service account and give permissions needed.