Skip to content

Commit db53c26

Browse files
ps-occrpimrannayer
andauthored
feat: Add support for autokey in postgres module (#712)
Co-authored-by: Imran Nayer <[email protected]>
1 parent 4373bdb commit db53c26

File tree

12 files changed

+133
-8
lines changed

12 files changed

+133
-8
lines changed

examples/postgresql-ha/README.md

+2
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ terraform destroy
2323

2424
| Name | Description | Type | Default | Required |
2525
|------|-------------|------|---------|:--------:|
26+
| folder\_id | The folder where project is created | `string` | n/a | yes |
27+
| key\_project\_id | The project where autokey is setup | `string` | n/a | yes |
2628
| pg\_ha\_external\_ip\_range | The ip range to allow connecting from/to Cloud SQL | `string` | `"192.10.10.10/32"` | no |
2729
| pg\_ha\_name | The name for Cloud SQL instance | `string` | `"tf-pg-ha"` | no |
2830
| project\_id | The project to run tests against | `string` | n/a | yes |

examples/postgresql-ha/main.tf

+13
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ module "pg" {
4848
maintenance_window_hour = 12
4949
maintenance_window_update_track = "stable"
5050

51+
use_autokey = true
5152
deletion_protection = false
5253

5354
database_flags = [{ name = "autovacuum", value = "off" }]
@@ -127,4 +128,16 @@ module "pg" {
127128
random_password = false
128129
},
129130
]
131+
depends_on = [time_sleep.wait_autokey_config]
132+
}
133+
134+
resource "google_kms_autokey_config" "autokey_config" {
135+
provider = google-beta
136+
folder = var.folder_id
137+
key_project = "projects/${var.key_project_id}"
138+
}
139+
140+
resource "time_sleep" "wait_autokey_config" {
141+
create_duration = "10s"
142+
depends_on = [google_kms_autokey_config.autokey_config]
130143
}

examples/postgresql-ha/outputs.tf

+4-2
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,11 @@ output "authorized_network" {
2828
}
2929

3030
output "replicas" {
31-
value = module.pg.replicas
31+
value = module.pg.replicas
32+
sensitive = true
3233
}
3334

3435
output "instances" {
35-
value = module.pg.instances
36+
value = module.pg.instances
37+
sensitive = true
3638
}

examples/postgresql-ha/variables.tf

+10
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,13 @@ variable "pg_ha_external_ip_range" {
3030
description = "The ip range to allow connecting from/to Cloud SQL"
3131
default = "192.10.10.10/32"
3232
}
33+
34+
variable "key_project_id" {
35+
type = string
36+
description = "The project where autokey is setup"
37+
}
38+
39+
variable "folder_id" {
40+
type = string
41+
description = "The folder where project is created"
42+
}

modules/postgresql/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ module "pg" {
170170
| secondary\_zone | The preferred zone for the replica instance, it should be something like: `us-central1-a`, `us-east1-c`. | `string` | `null` | no |
171171
| tier | The tier for the Cloud SQL instance. | `string` | `"db-f1-micro"` | no |
172172
| update\_timeout | The optional timout that is applied to limit long database updates. | `string` | `"30m"` | no |
173+
| use\_autokey | Enable the use of autokeys from Google Cloud KMS for CMEK. This requires autokey already configured in the project. | `bool` | `false` | no |
173174
| user\_deletion\_policy | The deletion policy for the user. Setting ABANDON allows the resource to be abandoned rather than deleted. This is useful for Postgres, where users cannot be deleted from the API if they have been granted SQL roles. Possible values are: "ABANDON". | `string` | `null` | no |
174175
| user\_labels | The key/value labels for the Cloud SQL instances. | `map(string)` | `{}` | no |
175176
| user\_name | The name of the default user | `string` | `"default"` | no |

modules/postgresql/main.tf

+12-1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ locals {
4545
connector_enforcement = var.connector_enforcement ? "REQUIRED" : "NOT_REQUIRED"
4646

4747
database_name = var.enable_default_db ? var.db_name : (length(var.additional_databases) > 0 ? var.additional_databases[0].name : "")
48+
49+
encryption_key = var.encryption_key_name != null ? var.encryption_key_name : var.use_autokey ? google_kms_key_handle.default[0].kms_key : null
4850
}
4951

5052
resource "random_id" "suffix" {
@@ -60,7 +62,7 @@ resource "google_sql_database_instance" "default" {
6062
database_version = can(regex("\\d", substr(var.database_version, 0, 1))) ? format("POSTGRES_%s", var.database_version) : replace(var.database_version, substr(var.database_version, 0, 8), "POSTGRES")
6163
maintenance_version = var.maintenance_version
6264
region = var.region
63-
encryption_key_name = var.encryption_key_name
65+
encryption_key_name = local.encryption_key
6466
deletion_protection = var.deletion_protection
6567
root_password = var.root_password
6668

@@ -211,6 +213,15 @@ resource "google_sql_database_instance" "default" {
211213
depends_on = [null_resource.module_depends_on]
212214
}
213215

216+
resource "google_kms_key_handle" "default" {
217+
count = var.use_autokey ? 1 : 0
218+
provider = google-beta
219+
project = var.project_id
220+
name = local.instance_name
221+
location = coalesce(var.region, join("-", slice(split("-", var.zone), 0, 2)))
222+
resource_type_selector = "sqladmin.googleapis.com/Instance"
223+
}
224+
214225
resource "google_sql_database" "default" {
215226
count = var.enable_default_db ? 1 : 0
216227
name = var.db_name

modules/postgresql/variables.tf

+6
Original file line numberDiff line numberDiff line change
@@ -456,3 +456,9 @@ variable "database_integration_roles" {
456456
type = list(string)
457457
default = []
458458
}
459+
460+
variable "use_autokey" {
461+
description = "Enable the use of autokeys from Google Cloud KMS for CMEK. This requires autokey already configured in the project."
462+
type = bool
463+
default = false
464+
}

test/fixtures/postgresql-ha/main.tf

+2-3
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ module "example" {
3232
project_id = var.project_id
3333
pg_ha_name = var.pg_ha_name
3434
pg_ha_external_ip_range = var.pg_ha_external_ip_range
35+
key_project_id = var.key_project_id
36+
folder_id = var.folder_id
3537
}
36-
37-
38-

test/fixtures/postgresql-ha/variables.tf

+10
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,13 @@ variable "pg_ha_external_ip_range" {
3030
description = "The ip range to allow connecting from/to Cloud SQL"
3131
default = "192.10.10.10/32"
3232
}
33+
34+
variable "key_project_id" {
35+
type = string
36+
description = "The project where autokey is setup"
37+
}
38+
39+
variable "folder_id" {
40+
type = string
41+
description = "The folder where project is created"
42+
}

test/setup/iam.tf

+10
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
locals {
1818
int_required_roles = [
1919
"roles/cloudkms.admin",
20+
"roles/cloudkms.autokeyAdmin",
2021
"roles/cloudkms.cryptoKeyEncrypterDecrypter",
2122
"roles/cloudscheduler.admin",
2223
"roles/cloudsql.admin",
@@ -45,6 +46,15 @@ resource "google_project_iam_member" "int_test" {
4546
member = "serviceAccount:${google_service_account.int_test.email}"
4647
}
4748

49+
resource "google_folder_iam_member" "int_test" {
50+
count = length(local.int_required_roles)
51+
52+
folder = google_folder.autokey_folder.folder_id
53+
role = local.int_required_roles[count.index]
54+
member = "serviceAccount:${google_service_account.int_test.email}"
55+
}
56+
57+
4858
resource "google_service_account_key" "int_test" {
4959
service_account_id = google_service_account.int_test.id
5060
}

test/setup/main.tf

+55-2
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,12 @@
1616

1717
module "project" {
1818
source = "terraform-google-modules/project-factory/google"
19-
version = "~> 17.0"
19+
version = "~> 18.0"
2020

2121
name = "ci-sql-db"
2222
random_project_id = "true"
2323
org_id = var.org_id
24-
folder_id = var.folder_id
24+
folder_id = google_folder.autokey_folder.folder_id
2525
billing_account = var.billing_account
2626
deletion_policy = "DELETE"
2727

@@ -54,3 +54,56 @@ resource "google_project_service_identity" "workflos_sa" {
5454
project = module.project.project_id
5555
service = "workflows.googleapis.com"
5656
}
57+
58+
resource "google_folder" "autokey_folder" {
59+
provider = google-beta
60+
display_name = "ci-sql-db-folder"
61+
parent = "folders/${var.folder_id}"
62+
deletion_protection = false
63+
}
64+
65+
module "autokey-project" {
66+
source = "terraform-google-modules/project-factory/google"
67+
version = "~> 18.0"
68+
69+
name = "ci-sql-db-autokey"
70+
random_project_id = "true"
71+
org_id = var.org_id
72+
folder_id = google_folder.autokey_folder.folder_id
73+
billing_account = var.billing_account
74+
deletion_policy = "DELETE"
75+
76+
activate_apis = [
77+
"cloudkms.googleapis.com",
78+
]
79+
}
80+
81+
resource "time_sleep" "wait_enable_service_api" {
82+
depends_on = [module.autokey-project]
83+
create_duration = "30s"
84+
}
85+
86+
resource "google_project_service_identity" "kms_service_agent" {
87+
provider = google-beta
88+
service = "cloudkms.googleapis.com"
89+
project = module.autokey-project.project_id
90+
depends_on = [time_sleep.wait_enable_service_api]
91+
}
92+
93+
resource "time_sleep" "wait_service_agent" {
94+
depends_on = [google_project_service_identity.kms_service_agent]
95+
create_duration = "10s"
96+
}
97+
98+
resource "google_project_iam_member" "autokey_project_admin" {
99+
provider = google-beta
100+
project = module.autokey-project.project_id
101+
role = "roles/cloudkms.admin"
102+
member = "serviceAccount:service-${module.autokey-project.project_number}@gcp-sa-cloudkms.iam.gserviceaccount.com"
103+
depends_on = [time_sleep.wait_service_agent]
104+
}
105+
106+
resource "time_sleep" "wait_srv_acc_permissions" {
107+
create_duration = "10s"
108+
depends_on = [google_project_iam_member.autokey_project_admin]
109+
}

test/setup/outputs.tf

+8
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,11 @@ output "cloudsql_mysql_sa" {
3232
value = google_service_account.cloudsql_mysql_sa.email
3333
description = "IAM service account user created for Cloud SQL for MySql."
3434
}
35+
36+
output "key_project_id" {
37+
value = module.autokey-project.project_id
38+
}
39+
40+
output "folder_id" {
41+
value = google_folder.autokey_folder.folder_id
42+
}

0 commit comments

Comments
 (0)