resource "random_password" "credentials_editor" { length = 24 override_special = "-:!+<>$" } resource "postgresql_role" "credentials_editor" { name = "credentials_editor" login = true password = random_password.credentials_editor.result create_role = true lifecycle { ignore_changes = [ roles, ] } } resource "vault_kv_secret" "postgres_admin_credentials" { path = "kvv1/postgres/credentials_editor/credentials" data_json = jsonencode({ username = postgresql_role.credentials_editor.name password = postgresql_role.credentials_editor.password }) } resource "postgresql_role" "app_role" { for_each = var.applications name = "${each.value}_role" login = false } resource "postgresql_grant_role" "credentials_editor_app_role" { for_each = var.applications role = postgresql_role.credentials_editor.name grant_role = postgresql_role.app_role[each.value].name with_admin_option = true } resource "postgresql_database" "app_db" { for_each = var.applications name = each.value owner = postgresql_role.app_role[each.value].name template = "template0" alter_object_ownership = true } resource "postgresql_function" "pgbouncer_user_lookup" { for_each = var.applications name = "user_lookup" database = postgresql_database.app_db[each.value].name arg { mode = "IN" name = "i_username" type = "text" } arg { mode = "OUT" name = "uname" type = "text" } arg { mode = "OUT" name = "phash" type = "text" } returns = "record" language = "plpgsql" body = <<-EOF BEGIN SELECT usename, passwd FROM pg_catalog.pg_shadow WHERE usename = i_username INTO uname, phash; RETURN; END; EOF parallel = "SAFE" security_definer = true } resource "postgresql_grant" "pgbouncer_user_lookup_public_revoke" { for_each = var.applications database = postgresql_function.pgbouncer_user_lookup[each.value].database role = "public" schema = "public" object_type = "function" objects = [ postgresql_function.pgbouncer_user_lookup[each.value].name, ] privileges = [] } resource "postgresql_grant" "pgbouncer_user_lookup" { depends_on = [ postgresql_grant.pgbouncer_user_lookup_public_revoke ] # can't do both in parallel for_each = var.applications database = postgresql_function.pgbouncer_user_lookup[each.value].database role = "pgbouncer_auth" schema = "public" object_type = "function" objects = [ postgresql_function.pgbouncer_user_lookup[each.value].name, ] privileges = ["EXECUTE"] }