Terraform: String Manipulation for Default Domains


Imaging when I needed to grant access to a Google storage bucket for a list of Google service accounts, I put the list in YAML like this:

# data/gcs.yaml
google-service-accounts:
  - [email protected]
  - [email protected]
  - [email protected]
  - [email protected]
  ...

Assuming horizon is the default GCP project and mass-effect is a partner project and most GSAs are of course from the default project. So can this list be DRYed up a bit like this?

# data/gcs.yaml
google-service-accounts:
  - gaia
  - nova
  - cyan
  - edi@mass-effect
  ...
default:
  project: horizon

The terraform code to read this YAML and grant IAM members could look like:

locals {
  manifest = yamldecode(file("./data/gcs.yaml"))
}

resource "google_storage_bucket" "default" {
  ...
}

resource "google_storage_bucket_iam_binding" "default_readers" {
  bucket  = google_storage_bucket.default.name
  role    = "roles/storage.objectViewer"
  members = formatlist(
    "serviceAccount:%s",
    [for member in local.manifest['google-service-accounts'] : format("%s@%s.iam.gserviceaccount.com", split("@", member)[0], try(split("@", member)[1], local.manifest.default.project))]
  )
}

A quick explanation on how this works:

# for item `gaia`
split("@", "gaia") -> ["gaia"]
split("@", "gaia")[0] -> "gaia"
split("@", "gaia")[1] -> error # doesn't exist
try(split("@", "gaia")[1], "horizon") -> "horizon"
format("%s@%s.iam.gserviceaccount.com", ...) -> "[email protected]"

# for item edi@mass-effect
split("@", "edi@mass-effect") -> ["edi", "mass-effect"]
split("@", "edi@mass-effect")[0] -> "edi"
split("@", "edi@mass-effect")[1] -> "mass-effect"
try(split("@", "edi@mass-effect")[1], "horizon") -> "mass-effect"
format("%s@%s.iam.gserviceaccount.com", ...) -> "[email protected]"

PS. yes I like the Horizon and Mass Effect games. 🙂