I love how DRY and lean YAML can be, since I started to learn Ansible years ago.
Recently I wanted to provision MySQL user privileges right after the database instance provisioned in Google Cloud SQL. I used petoju/mysql
Terraform provider to get the job done, it’s a community provider but seemed to be quite popular.
To grant a MySQL user some privileges, the grant statement usually looks like
GRANT SELECT ON database_name.* to 'username'@'%';
Considering I have more than 1 database cluster to provision, I created the following YAML data structure
services: app_joe: cluster: big1 grants: - db: db_elle # joe can only read elle's data privileges: - SELECT - db: db_joe app_elle: cluster: big1 grants: - db: db_elle defaults: host: '%' # full access by default privileges: - SELECT - UPDATE - INSERT - DELETE
And here’s how I generated a for_each
loop in a Terraform HCL file
terraform { backend "gcs" {} required_providers { google = { source = "hashicorp/google" version = "4.28.0" } google-beta = { source = "hashicorp/google-beta" version = "4.28.0" } mysql = { source = "petoju/mysql" version = "3.0.22" } } required_version = "1.2.8" } provider "google" {} provider "google-beta" {} provider "mysql" { # lines here only work for 1 db cluster. # can use terragrunt to make dynamic providers endpoint = "127.0.0.1:13306" username = "root" password = "password" } locals { cluster_name = "big1" service_account_maniffest = yamldecode(file("data.yaml")) # a flatterned list of objects containing grant info service_account_grants = distinct(flatten([ for k, v in local.service_account_maniffest.services : [ for g in v.grants : { service = k db = g.db privileges = lookup(g, "privileges", local.service_account_maniffest.defaults.privileges) } ] if v.cluster == local.cluster_name ])) } # Authorization via MySQL grants resource "mysql_grant" "iam_sql_service" { # for_each only works with set or map, so let's make a map for_each = { for grant in local.service_account_grants : "${grant.service}-${grant.db}" => grant } user = each.value.service host = local.service_account_maniffest.defaults.host database = each.value.db privileges = each.value.privileges }
All done 🙂