diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index c00765d..843ef37 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -8,7 +8,9 @@ jobs: check-formatting: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: hashicorp/setup-terraform@v3 + + - uses: actions/checkout@v5 - name: Check formatting run: terraform fmt -check @@ -16,7 +18,9 @@ jobs: validate-module: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: hashicorp/setup-terraform@v3 + + - uses: actions/checkout@v5 - name: Run terraform init run: terraform init diff --git a/locals.tf b/locals.tf index e669524..2ca0158 100644 --- a/locals.tf +++ b/locals.tf @@ -8,6 +8,8 @@ locals { for database in role_.databases_ro : { role = role database = database + is_iam = contains(["CLOUD_IAM_USER", "CLOUD_IAM_GROUP", "CLOUD_IAM_SERVICE_ACCOUNT"], role_.type) + type = role_.type } ] ]) @@ -16,6 +18,8 @@ locals { for database in role_.databases_rw : { role = role database = database + is_iam = contains(["CLOUD_IAM_USER", "CLOUD_IAM_GROUP", "CLOUD_IAM_SERVICE_ACCOUNT"], role_.type) + type = role_.type } ] ], [ @@ -23,10 +27,15 @@ locals { for writer in var.legacy_writers : { role = writer database = database + is_iam = false + type = "BUILT_IN" } ] ])) + roles_iam = { for role, role_ in var.roles : role => role_ if contains(["CLOUD_IAM_USER", "CLOUD_IAM_GROUP", "CLOUD_IAM_SERVICE_ACCOUNT"], role_.type) } + roles_built_in = { for role, role_ in var.roles : role => role_ if role_.type == "BUILT_IN" } + privileges_ro = [ "SELECT", ] diff --git a/roles.tf b/roles.tf index d024be8..728f2f6 100644 --- a/roles.tf +++ b/roles.tf @@ -1,5 +1,5 @@ resource "random_password" "role" { - for_each = var.roles + for_each = local.roles_built_in length = 48 min_lower = 0 @@ -18,7 +18,7 @@ resource "random_password" "role" { } resource "postgresql_role" "role" { - for_each = var.roles + for_each = local.roles_built_in name = each.key superuser = false @@ -75,6 +75,15 @@ resource "postgresql_role" "role_ro" { statement_timeout = 0 } +resource "postgresql_grant_role" "role_ro" { + for_each = { + for role in local.databases_readers : "${role.database}__${role.role}" => role if role.is_iam + } + + role = each.value.role + grant_role = "${each.value.database}_role_ro" +} + resource "postgresql_default_privileges" "role_ro_table" { for_each = { for database_writer in local.databases_writers : "${database_writer.database}.${database_writer.role}" => database_writer @@ -158,6 +167,15 @@ resource "postgresql_role" "role_rw" { statement_timeout = 0 } +resource "postgresql_grant_role" "role_rw" { + for_each = { + for role in local.databases_writers : "${role.database}__${role.role}" => role if role.is_iam + } + + role = each.value.role + grant_role = "${each.value.database}_role_rw" +} + resource "postgresql_default_privileges" "role_rw_table" { for_each = { for database_writer in local.databases_writers : "${database_writer.database}.${database_writer.role}" => database_writer @@ -218,14 +236,3 @@ resource "postgresql_grant" "role_rw_schema" { privileges = ["CREATE", "USAGE"] with_grant_option = false } - - -moved { - from = postgresql_default_privileges.role_ro - to = postgresql_default_privileges.role_ro_table -} - -moved { - from = postgresql_default_privileges.role_rw - to = postgresql_default_privileges.role_rw_table -} diff --git a/users-iam.tf b/users-iam.tf new file mode 100644 index 0000000..341206f --- /dev/null +++ b/users-iam.tf @@ -0,0 +1,7 @@ +resource "google_sql_user" "iam" { + for_each = local.roles_iam + + instance = var.instance_id + name = each.key + type = each.value.type +} diff --git a/variables.tf b/variables.tf index ffb8b4d..645f199 100644 --- a/variables.tf +++ b/variables.tf @@ -3,10 +3,23 @@ variable "legacy_writers" { default = [] } +variable "instance_id" { + type = string + default = null +} + variable "roles" { type = map(object({ connection_limit = optional(number) databases_ro = list(string) databases_rw = list(string) + type = optional(string, "BUILT_IN") })) + + validation { + condition = alltrue([ + for u in var.roles : contains(["BUILT_IN", "CLOUD_IAM_USER", "CLOUD_IAM_GROUP", "CLOUD_IAM_SERVICE_ACCOUNT"], u.type) + ]) + error_message = "Invalid user type. Only BUILT_IN, CLOUD_IAM_USER, CLOUD_IAM_GROUP, CLOUD_IAM_SERVICE_ACCOUNT are supported." + } }