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
- DELETEAnd 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 🙂
