Skip to content

Commit

Permalink
fix!: removes instanceUser iam binding from the postgresql module (#382)
Browse files Browse the repository at this point in the history
Co-authored-by: g-awmalik <[email protected]>
  • Loading branch information
ykyr and g-awmalik authored Jan 5, 2023
1 parent 562455b commit cc39074
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 15 deletions.
115 changes: 115 additions & 0 deletions docs/upgrading_to_sql_db_14.0.0.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# Upgrading to SQL DB 14.0.0

The 14.0.0 release of SQL DB is a backward incompatible release. This incompatibility affects `postgresql` submodule that uses IAM authentication.

## Migration Instructions

### Removed cloudsql.instanceUser iam_binding

Prior to the 14.0.0 release, in `postgresql` submodule with IAM athentication, for every `iam_user_emails` there was `cloudsql.instanceUser` IAM binding created automatically. However keeping IAM binding inside the module can cause an unintentional outage in some cases (see[#381](https://github.com/terraform-google-modules/terraform-google-sql-db/issues/381))

```hcl
module "pg" {
source = "GoogleCloudPlatform/sql-db/google//modules/postgresql"
version = "~> 13.0"
name = "test"
database_version = "POSTGRES_14"
project_id = var.project_id
zone = "europe-west1-b"
region = "europe-west1"
tier = "db-custom-1-3840"
database_flags = [
{
name = "cloudsql.iam_authentication"
value = "on"
}
]
iam_user_emails = [
"test-sa@${var.project_id}.iam.gserviceaccount.com",
"test-sa-two@${var.project_id}.iam.gserviceaccount.com"
]
}
```

With the 14.0.0 release, the `google_project_iam_member` resource was removed from the module. Respective IAM binding for `cloudsql.instanceUser` should be created and managed outside of the module.

```diff
module "pg" {
source = "GoogleCloudPlatform/sql-db/google//modules/postgresql"
- version = "~> 13.0"
+ version = "~> 14.0"

name = "test"
database_version = "POSTGRES_14"
project_id = var.project_id
zone = "europe-west1-b"
region = "europe-west1"
tier = "db-custom-1-3840"

database_flags = [
{
name = "cloudsql.iam_authentication"
value = "on"
}
]

iam_user_emails = [
"test-sa@${var.project_id}.iam.gserviceaccount.com",
"[email protected]"
]
}

+ locals {
+ iam_users = [for iu in module.pg.iam_user_emails : {
+ email = iu,
+ is_account_sa = trimsuffix(iu, "gserviceaccount.com") == iu ? false : true
+ }]
+ }
+
+ resource "google_project_iam_member" "iam_binding" {
+ for_each = {
+ for iu in local.iam_users :
+ "${iu.email} ${iu.is_account_sa}" => iu
+ }
+ project = var.project_id
+ role = "roles/cloudsql.instanceUser"
+ member = each.value.is_account_sa ? (
+ "serviceAccount:${each.value.email}"
+ ) : (
+ "user:${each.value.email}"
+ )
+ }
```

To gracefully and safely migrate, recommend way is to use `terraform state mv`:

```sh
terraform state mv \
'module.pg.google_project_iam_member.iam_binding["test-sa@${var.project_id}.iam.gserviceaccount.com true"]' \
'google_project_iam_member.iam_binding["test-sa@${var.project_id}.iam.gserviceaccount.com true"]'
terraform state mv \
'module.pg.google_project_iam_member.iam_binding["[email protected] false"]' \
'google_project_iam_member.iam_binding["[email protected] false"]'
```

[OPTIONAL] To automatically generate `terraform state mv` commands from above, you can use this simple script:

```sh
#!/usr/bin/env bash
#########################################################
# The script outputs prepared terraform state mv commands
# Based on the sql_module_name variable

sql_module_name="module.pg"
IFS='
'
for n in $(terraform state list | grep ''${sql_module_name}'.google_project_iam_member.iam_binding'); do
iam_binding=$(echo $n | sed "s/${sql_module_name}\.//g")
echo "terraform state mv '$n' '$iam_binding'"
done
```

After IAM bindings are moved, **terraform apply should be without any changes**.
1 change: 1 addition & 0 deletions modules/postgresql/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ Note: CloudSQL provides [disk autoresize](https://cloud.google.com/sql/docs/mysq
|------|-------------|
| additional\_users | List of maps of additional users and passwords |
| generated\_user\_password | The auto generated default user password if not input password was provided |
| iam\_user\_emails | The list of the IAM users with the access to the Cloudsql instance |
| instance\_connection\_name | The connection name of the master instance to be used in connection strings |
| instance\_first\_ip\_address | The first IPv4 address of the addresses assigned. |
| instance\_ip\_address | The IPv4 address assigned for the master instance |
Expand Down
15 changes: 0 additions & 15 deletions modules/postgresql/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -233,20 +233,6 @@ resource "google_sql_user" "additional_users" {
deletion_policy = var.user_deletion_policy
}

resource "google_project_iam_member" "iam_binding" {
for_each = {
for iu in local.iam_users :
"${iu.email} ${iu.is_account_sa}" => iu
}
project = var.project_id
role = "roles/cloudsql.instanceUser"
member = each.value.is_account_sa ? (
"serviceAccount:${each.value.email}"
) : (
"user:${each.value.email}"
)
}

resource "google_sql_user" "iam_account" {
for_each = {
for iu in local.iam_users :
Expand All @@ -263,7 +249,6 @@ resource "google_sql_user" "iam_account" {

depends_on = [
null_resource.module_depends_on,
google_project_iam_member.iam_binding,
]
deletion_policy = var.user_deletion_policy
}
Expand Down
5 changes: 5 additions & 0 deletions modules/postgresql/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,11 @@ output "additional_users" {
sensitive = true
}

output "iam_user_emails" {
description = "The list of the IAM users with the access to the Cloudsql instance"
value = var.iam_user_emails
}

// Resources
output "primary" {
value = google_sql_database_instance.default
Expand Down

0 comments on commit cc39074

Please sign in to comment.