Skip to content

Commit

Permalink
fix!: pass iam_user_emails as map to postgres module (#414)
Browse files Browse the repository at this point in the history
Co-authored-by: Kareem Daggash <kareemdaggash@gmail.com>
Co-authored-by: Awais Malik <malik.awais@gmail.com>
  • Loading branch information
3 people authored Apr 18, 2023
1 parent 59b32af commit 15298c2
Show file tree
Hide file tree
Showing 7 changed files with 120 additions and 25 deletions.
82 changes: 82 additions & 0 deletions docs/upgrading_to_sql_db_15.0.0.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# Upgrading to SQL DB 15.0.0

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

## Migration Instructions

### `iam_user_emails` moved to `iam_users` and changed to be an list(object)

Prior to the `15.0.0` release, the `postgresql` submodule took a `list(string)` for `iam_user_emails`.

This meant that it was not possible to create a `google_service_account` and corresponding `google_sql_user`
in a single `terraform apply` because the `email` is `(known after apply)` and was used in the resource address.
See [issue 413](https://github.com/terraform-google-modules/terraform-google-sql-db/issues/413) for more details.

In the `15.0.0` release, the input/output variable has been renamed from `iam_user_emails` to `iam_users`, and
now accepts a `list(object({id=string, email=string}))`, where `id` is used in the resource address.

This allows a value that is known at `plan` time to be passed, for example `google_service_account.my_service_account.account_id`
would be a good candidate for this.

```diff
module "pg" {
source = "GoogleCloudPlatform/sql-db/google//modules/postgresql"
- version = "~> 14.0"
+ version = "~> 15.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",
- "john.doe@gmail.com"
- ]
+ iam_users = [
+ {
+ id = "test-sa",
+ email = "test-sa@${var.project_id}.iam.gserviceaccount.com",
+ },
+ {
+ id = "john.doe",
+ email = "john.doe@gmail.com",
+ },
+ ]
}

+ moved {
+ from = module.pg.google_sql_user.iam_account["test-sa@${var.project_id}.iam.gserviceaccount.com true"]
+ to = module.pg.google_sql_user.iam_account["test-sa"]
+ }

+ moved {
+ from = module.pg.google_sql_user.iam_account["john.doe@gmail.com false"]
+ to = module.pg.google_sql_user.iam_account["john.doe"]
+ }

```

We recommend using `moved` blocks as [documented here](https://developer.hashicorp.com/terraform/language/modules/develop/refactoring)
to explicitly migrate your state. You can find the list of state addresses to move using:

```shell
terraform state list | grep google_sql_user.iam_account
```

If you do not wish to use `moved` blocks, you can instead migrate your state using `terraform state mv`:
```shell
terraform state mv \
'module.pg.google_sql_user.iam_account["test-sa@$my-project-id.iam.gserviceaccount.com true"]' \
'module.pg.google_sql_user.iam_account["test-sa"]'
```
12 changes: 9 additions & 3 deletions examples/postgresql-public-iam/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,14 @@ module "postgresql-db" {
]

# Supports creation of both IAM Users and IAM Service Accounts with provided emails
iam_user_emails = [
var.cloudsql_pg_sa,
"dbadmin@goosecorp.org",
iam_users = [
{
id = "cloudsql_pg_sa",
email = var.cloudsql_pg_sa
},
{
id = "dbadmin",
email = "dbadmin@goosecorp.org"
}
]
}
4 changes: 2 additions & 2 deletions modules/postgresql/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ Note: CloudSQL provides [disk autoresize](https://cloud.google.com/sql/docs/mysq
| enable\_random\_password\_special | Enable special characters in generated random passwords. | `bool` | `false` | no |
| encryption\_key\_name | The full path to the encryption key used for the CMEK disk encryption | `string` | `null` | no |
| follow\_gae\_application | A Google App Engine application whose zone to remain in. Must be in the same region as this instance. | `string` | `null` | no |
| iam\_user\_emails | A list of IAM users to be created in your cluster | `list(string)` | `[]` | no |
| iam\_users | A list of IAM users to be created in your CloudSQL instance | <pre>list(object({<br> id = string,<br> email = string<br> }))</pre> | `[]` | no |
| insights\_config | The insights\_config settings for the database. | <pre>object({<br> query_string_length = number<br> record_application_tags = bool<br> record_client_address = bool<br> })</pre> | `null` | no |
| ip\_configuration | The ip configuration for the master instances. | <pre>object({<br> authorized_networks = list(map(string))<br> ipv4_enabled = bool<br> private_network = string<br> require_ssl = bool<br> allocated_ip_range = string<br> enable_private_path_for_google_cloud_services = optional(bool)<br> })</pre> | <pre>{<br> "allocated_ip_range": null,<br> "authorized_networks": [],<br> "enable_private_path_for_google_cloud_services": false,<br> "ipv4_enabled": true,<br> "private_network": null,<br> "require_ssl": null<br>}</pre> | no |
| maintenance\_window\_day | The day of week (1-7) for the master instance maintenance. | `number` | `1` | no |
Expand Down Expand Up @@ -64,7 +64,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 |
| iam\_users | The list of the IAM users with 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
16 changes: 8 additions & 8 deletions modules/postgresql/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,12 @@ locals {

databases = { for db in var.additional_databases : db.name => db }
users = { for u in var.additional_users : u.name => u }
iam_users = [for iu in var.iam_user_emails : {
email = iu,
is_account_sa = trimsuffix(iu, "gserviceaccount.com") == iu ? false : true
}]
iam_users = {
for user in var.iam_users : user.id => {
email = user.email,
is_account_sa = trimsuffix(user.email, "gserviceaccount.com") == user.email ? false : true
}
}

// HA method using REGIONAL availability_type requires point in time recovery to be enabled
point_in_time_recovery_enabled = var.availability_type == "REGIONAL" ? lookup(var.backup_configuration, "point_in_time_recovery_enabled", true) : lookup(var.backup_configuration, "point_in_time_recovery_enabled", false)
Expand Down Expand Up @@ -262,10 +264,8 @@ resource "google_sql_user" "additional_users" {
}

resource "google_sql_user" "iam_account" {
for_each = {
for iu in local.iam_users :
"${iu.email} ${iu.is_account_sa}" => iu
}
for_each = local.iam_users

project = var.project_id
name = each.value.is_account_sa ? (
trimsuffix(each.value.email, ".gserviceaccount.com")
Expand Down
14 changes: 9 additions & 5 deletions modules/postgresql/metadata.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -180,9 +180,13 @@ spec:
- name: follow_gae_application
description: A Google App Engine application whose zone to remain in. Must be in the same region as this instance.
type: string
- name: iam_user_emails
description: A list of IAM users to be created in your cluster
type: list(string)
- name: iam_users
description: A list of IAM users to be created in your CloudSQL instance
type: |-
list(object({
id = string
email = string
}))
default: []
- name: insights_config
description: The insights_config settings for the database.
Expand Down Expand Up @@ -331,8 +335,8 @@ spec:
description: List of maps of additional users and passwords
- name: generated_user_password
description: The auto generated default user password if not input password was provided
- name: iam_user_emails
description: The list of the IAM users with the access to the Cloudsql instance
- name: iam_users
description: The list of the IAM users with access to the CloudSQL instance
- name: instance_connection_name
description: The connection name of the master instance to be used in connection strings
- name: instance_first_ip_address
Expand Down
6 changes: 3 additions & 3 deletions modules/postgresql/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,9 @@ 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
output "iam_users" {
description = "The list of the IAM users with access to the CloudSQL instance"
value = var.iam_users
}

// Resources
Expand Down
11 changes: 7 additions & 4 deletions modules/postgresql/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -322,10 +322,13 @@ variable "additional_users" {
}
}

variable "iam_user_emails" {
description = "A list of IAM users to be created in your cluster"
type = list(string)
default = []
variable "iam_users" {
description = "A list of IAM users to be created in your CloudSQL instance"
type = list(object({
id = string,
email = string
}))
default = []
}

variable "create_timeout" {
Expand Down

0 comments on commit 15298c2

Please sign in to comment.