From 4da440bc4f1dd1600a9baf761b65304046917f91 Mon Sep 17 00:00:00 2001 From: lcaggio Date: Thu, 8 Sep 2022 17:47:20 +0200 Subject: [PATCH 1/2] First commit. --- examples/data-solutions/README.md | 2 +- .../cloudsql-multiregion/README.md | 41 ++++++++++++++---- .../cloudsql-multiregion/cloudsql.tf | 6 +-- .../cloudsql-multiregion/datastorage.tf | 2 +- .../cloudsql-multiregion/gce.tf | 8 ++-- .../cloudsql-multiregion/images/diagram.png | Bin 33464 -> 24246 bytes .../cloudsql-multiregion/kms.tf | 37 ---------------- .../cloudsql-multiregion/main.tf | 34 ++++++++++++++- .../cloudsql-multiregion/variables.tf | 19 ++++++-- .../cloudsql-multiregion/test_plan.py | 4 +- 10 files changed, 91 insertions(+), 62 deletions(-) delete mode 100644 examples/data-solutions/cloudsql-multiregion/kms.tf diff --git a/examples/data-solutions/README.md b/examples/data-solutions/README.md index e91e4873..6217f2cb 100644 --- a/examples/data-solutions/README.md +++ b/examples/data-solutions/README.md @@ -30,7 +30,7 @@ This [example](./data-platform-foundations/) implements SQL Server Always On Ava ### Cloud SQL instance with multi-region read replicas - + This [example](./cloudsql-multiregion/) creates a [Cloud SQL instance](https://cloud.google.com/sql) with multi-region read replicas as described in the [Cloud SQL for PostgreSQL disaster recovery](https://cloud.google.com/architecture/cloud-sql-postgres-disaster-recovery-complete-failover-fallback) article.
diff --git a/examples/data-solutions/cloudsql-multiregion/README.md b/examples/data-solutions/cloudsql-multiregion/README.md index 29fe63c9..214eaa93 100644 --- a/examples/data-solutions/cloudsql-multiregion/README.md +++ b/examples/data-solutions/cloudsql-multiregion/README.md @@ -80,6 +80,30 @@ This implementation is intentionally minimal and easy to read. A real world use - Using a Shared VPC - Using VPC-SC to mitigate data exfiltration +### Share VPC +The example support the configuration of a Shared VPC as an input variable. +To deploy the solution on a Shared VPC, you have to configure the `network_config` variable: + +``` +network_config = { + host_project = "PROJECT_ID" + network_self_link = "https://www.googleapis.com/compute/v1/projects/PROJECT_ID/global/networks/VPC_NAME" + subnet_self_link = "https://www.googleapis.com/compute/v1/projects/PROJECT_ID/regions/$REGION/subnetworks/SUBNET_NAME" + cloudsql_psa_range = "10.60.0.0/24" + } +``` + +To run this example, the Shared VPC project need to have: + - A Private Service Connect with a range of `/24` (example: `10.60.0.0/24`) to deploy the Cloud SQL instance. + - Internet gateway configured to let the Test VM download packages. + +In order to run the example and deploy Cloud SQL on a shared VPC the identity running Terraform must have the following IAM permissions on the Shared VPC Host project. + - compute.networks.list + - compute.addresses.create + - compute.addresses.list + - servicenetworking.services.addPeering + - compute.xpnAdmin + ## Test your environment We assume all those steps are run using a user listed on `data_eng_principals`. You can authenticate as the user using the following command: @@ -118,15 +142,16 @@ The above command will delete the associated resources so there will be no billa | name | description | type | required | default | |---|---|:---:|:---:|:---:| -| [postgres_user_password](variables.tf#L29) | `postgres` user password. | string | ✓ | | -| [prefix](variables.tf#L40) | Unique prefix used for resource names. Not used for project if 'project_create' is null. | string | ✓ | | -| [project_id](variables.tf#L54) | Project id, references existing project if `project_create` is null. | string | ✓ | | -| [cmek_encryption](variables.tf#L17) | Flag to enable CMEK on GCP resources created. | bool | | false | +| [postgres_user_password](variables.tf#L40) | `postgres` user password. | string | ✓ | | +| [prefix](variables.tf#L51) | Unique prefix used for resource names. Not used for project if 'project_create' is null. | string | ✓ | | +| [project_id](variables.tf#L65) | Project id, references existing project if `project_create` is null. | string | ✓ | | | [data_eng_principals](variables.tf#L23) | Groups with Service Account Token creator role on service accounts in IAM format, only user supported on CloudSQL, eg 'user@domain.com'. | list(string) | | [] | -| [postgres_database](variables.tf#L34) | `postgres` database. | string | | "guestbook" | -| [project_create](variables.tf#L45) | Provide values if project creation is needed, uses existing project if null. Parent is in 'folders/nnn' or 'organizations/nnn' format. | object({…}) | | null | -| [regions](variables.tf#L59) | Map of instance_name => location where instances will be deployed. | map(string) | | {…} | -| [sql_configuration](variables.tf#L73) | Cloud SQL configuration | object({…}) | | {…} | +| [network_config](variables.tf#L29) | Shared VPC network configurations to use. If null networks will be created in projects with preconfigured values. | object({…}) | | null | +| [postgres_database](variables.tf#L45) | `postgres` database. | string | | "guestbook" | +| [project_create](variables.tf#L56) | Provide values if project creation is needed, uses existing project if null. Parent is in 'folders/nnn' or 'organizations/nnn' format. | object({…}) | | null | +| [regions](variables.tf#L70) | Map of instance_name => location where instances will be deployed. | map(string) | | {…} | +| [service_encryption_keys](variables.tf#L17) | Cloud KMS keys to use to encrypt resources. Provide a key for each reagion configured. | map(string) | | null | +| [sql_configuration](variables.tf#L84) | Cloud SQL configuration | object({…}) | | {…} | ## Outputs diff --git a/examples/data-solutions/cloudsql-multiregion/cloudsql.tf b/examples/data-solutions/cloudsql-multiregion/cloudsql.tf index 01c30565..7962acea 100644 --- a/examples/data-solutions/cloudsql-multiregion/cloudsql.tf +++ b/examples/data-solutions/cloudsql-multiregion/cloudsql.tf @@ -16,8 +16,8 @@ module "db" { source = "../../../modules/cloudsql-instance" project_id = module.project.project_id availability_type = var.sql_configuration.availability_type - encryption_key_name = var.cmek_encryption ? module.kms[var.regions.primary].keys.key.id : null - network = module.vpc.self_link + encryption_key_name = var.service_encryption_keys != null ? var.service_encryption_keys[var.regions.primary] : null + network = local.vpc_self_link name = "${var.prefix}-db" region = var.regions.primary database_version = var.sql_configuration.database_version @@ -29,7 +29,7 @@ module "db" { for k, v in var.regions : k => { region = v, - encryption_key_name = var.cmek_encryption ? module.kms[v].keys.key.id : null + encryption_key_name = var.service_encryption_keys != null ? var.service_encryption_keys[v] : null } if k != "primary" } databases = [var.postgres_database] diff --git a/examples/data-solutions/cloudsql-multiregion/datastorage.tf b/examples/data-solutions/cloudsql-multiregion/datastorage.tf index 1b75deb0..f394a128 100644 --- a/examples/data-solutions/cloudsql-multiregion/datastorage.tf +++ b/examples/data-solutions/cloudsql-multiregion/datastorage.tf @@ -19,7 +19,7 @@ module "gcs" { name = "data" location = var.regions.primary storage_class = "REGIONAL" - encryption_key = var.cmek_encryption ? module.kms[var.regions.primary].keys["key"].id : null + encryption_key = var.service_encryption_keys != null ? var.service_encryption_keys[var.regions.primary] : null force_destroy = true } diff --git a/examples/data-solutions/cloudsql-multiregion/gce.tf b/examples/data-solutions/cloudsql-multiregion/gce.tf index 435d0495..78078838 100644 --- a/examples/data-solutions/cloudsql-multiregion/gce.tf +++ b/examples/data-solutions/cloudsql-multiregion/gce.tf @@ -29,8 +29,8 @@ module "test-vm" { zone = "${var.regions.primary}-b" name = "sql-test" network_interfaces = [{ - network = module.vpc.self_link - subnetwork = module.vpc.subnets["${var.regions.primary}/subnet"].self_link + network = local.vpc_self_link + subnetwork = local.subnet nat = false addresses = null }] @@ -50,10 +50,10 @@ module "test-vm" { type = "pd-ssd" size = 10 } - encryption = var.cmek_encryption ? { + encryption = var.service_encryption_keys != null ? { encrypt_boot = true disk_encryption_key_raw = null - kms_key_self_link = var.cmek_encryption ? module.kms[var.regions.primary].keys["key"].id : null + kms_key_self_link = var.service_encryption_keys != null ? var.service_encryption_keys[var.regions.primary] : null } : null metadata = { startup-script = local.startup-script } tags = ["ssh"] diff --git a/examples/data-solutions/cloudsql-multiregion/images/diagram.png b/examples/data-solutions/cloudsql-multiregion/images/diagram.png index 35c8ff8e6d0501b1acd87d91e2f14b419f87c632..6679e013b1dbccf000e9e7e081cf632c1e205358 100644 GIT binary patch literal 24246 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 XEt$gKy>kYiAxMhKiIfU`^83F4={3@+ diff --git a/examples/data-solutions/cloudsql-multiregion/kms.tf b/examples/data-solutions/cloudsql-multiregion/kms.tf deleted file mode 100644 index d35ca71f..00000000 --- a/examples/data-solutions/cloudsql-multiregion/kms.tf +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright 2022 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -module "kms" { - for_each = toset(distinct(values(var.regions))) - source = "../../../modules/kms" - project_id = module.project.project_id - - keyring = { - name = "${var.prefix}-keyring-${each.value}" - location = each.value - } - - keys = { - key = null - } - key_iam = { - key = { - "roles/cloudkms.cryptoKeyEncrypterDecrypter" = [ - "serviceAccount:${module.project.service_accounts.robots.compute}", - "serviceAccount:${module.project.service_accounts.robots.sql}", - "serviceAccount:${module.project.service_accounts.robots.storage}" - ] - } - } -} diff --git a/examples/data-solutions/cloudsql-multiregion/main.tf b/examples/data-solutions/cloudsql-multiregion/main.tf index da4e076f..c3264877 100644 --- a/examples/data-solutions/cloudsql-multiregion/main.tf +++ b/examples/data-solutions/cloudsql-multiregion/main.tf @@ -54,6 +54,20 @@ locals { "serviceAccount:${module.project.service_accounts.robots.sql}" ] } + + shared_vpc_project = try(var.network_config.host_project, null) + use_shared_vpc = var.network_config != null + + subnet = ( + local.use_shared_vpc + ? var.network_config.subnet_self_link + : values(module.vpc.0.subnet_self_links)[0] + ) + vpc_self_link = ( + local.use_shared_vpc + ? var.network_config.network_self_link + : module.vpc.0.self_link + ) } module "project" { @@ -67,6 +81,7 @@ module "project" { iam_additive = var.project_create == null ? local.iam : {} services = [ "cloudkms.googleapis.com", + "compute.googleapis.com", "iap.googleapis.com", "logging.googleapis.com", "monitoring.googleapis.com", @@ -77,6 +92,18 @@ module "project" { "storage.googleapis.com", "storage-component.googleapis.com", ] + + shared_vpc_service_config = local.shared_vpc_project == null ? null : { + attach = true + host_project = local.shared_vpc_project + service_identity_iam = {} + } + + service_encryption_key_ids = { + compute = try(values(var.service_encryption_keys), []) + sql = try(values(var.service_encryption_keys), []) + storage = try(values(var.service_encryption_keys), []) + } service_config = { disable_on_destroy = false, disable_dependent_services = false } @@ -84,6 +111,7 @@ module "project" { module "vpc" { source = "../../../modules/net-vpc" + count = local.use_shared_vpc ? 0 : 1 project_id = module.project.project_id name = "vpc" subnets = [ @@ -103,15 +131,17 @@ module "vpc" { module "firewall" { source = "../../../modules/net-vpc-firewall" + count = local.use_shared_vpc ? 0 : 1 project_id = module.project.project_id - network = module.vpc.name + network = module.vpc.0.name admin_ranges = ["10.0.0.0/20"] } module "nat" { source = "../../../modules/net-cloudnat" + count = local.use_shared_vpc ? 0 : 1 project_id = module.project.project_id region = var.regions.primary name = "${var.prefix}-default" - router_network = module.vpc.name + router_network = module.vpc.0.name } diff --git a/examples/data-solutions/cloudsql-multiregion/variables.tf b/examples/data-solutions/cloudsql-multiregion/variables.tf index 3764f4e1..66083b5f 100644 --- a/examples/data-solutions/cloudsql-multiregion/variables.tf +++ b/examples/data-solutions/cloudsql-multiregion/variables.tf @@ -14,10 +14,10 @@ * limitations under the License. */ -variable "cmek_encryption" { - description = "Flag to enable CMEK on GCP resources created." - type = bool - default = false +variable "service_encryption_keys" { + description = "Cloud KMS keys to use to encrypt resources. Provide a key for each reagion configured." + type = map(string) + default = null } variable "data_eng_principals" { @@ -26,6 +26,17 @@ variable "data_eng_principals" { default = [] } +variable "network_config" { + description = "Shared VPC network configurations to use. If null networks will be created in projects with preconfigured values." + type = object({ + host_project = string + network_self_link = string + subnet_self_link = string + cloudsql_psa_range = string + }) + default = null +} + variable "postgres_user_password" { description = "`postgres` user password." type = string diff --git a/tests/examples/data_solutions/cloudsql-multiregion/test_plan.py b/tests/examples/data_solutions/cloudsql-multiregion/test_plan.py index e97e22d3..90371cf7 100644 --- a/tests/examples/data_solutions/cloudsql-multiregion/test_plan.py +++ b/tests/examples/data_solutions/cloudsql-multiregion/test_plan.py @@ -15,5 +15,5 @@ def test_resources(e2e_plan_runner): "Test that plan works and the numbers of resources is as expected." modules, resources = e2e_plan_runner() - assert len(modules) == 11 - assert len(resources) == 53 + assert len(modules) == 9 + assert len(resources) == 48 From 3fd7a4005dfe59c6dccc973412965db510cf81c9 Mon Sep 17 00:00:00 2001 From: lcaggio Date: Fri, 9 Sep 2022 10:05:37 +0200 Subject: [PATCH 2/2] fixes --- .../cloudsql-multiregion/README.md | 17 +++++++---------- .../cloudsql-multiregion/cloudsql.tf | 4 ++-- .../cloudsql-multiregion/datastorage.tf | 2 +- .../data-solutions/cloudsql-multiregion/gce.tf | 2 +- 4 files changed, 11 insertions(+), 14 deletions(-) diff --git a/examples/data-solutions/cloudsql-multiregion/README.md b/examples/data-solutions/cloudsql-multiregion/README.md index 214eaa93..29da83ec 100644 --- a/examples/data-solutions/cloudsql-multiregion/README.md +++ b/examples/data-solutions/cloudsql-multiregion/README.md @@ -80,8 +80,8 @@ This implementation is intentionally minimal and easy to read. A real world use - Using a Shared VPC - Using VPC-SC to mitigate data exfiltration -### Share VPC -The example support the configuration of a Shared VPC as an input variable. +### Shared VPC +The example supports the configuration of a Shared VPC as an input variable. To deploy the solution on a Shared VPC, you have to configure the `network_config` variable: ``` @@ -93,16 +93,13 @@ network_config = { } ``` -To run this example, the Shared VPC project need to have: +To run this example, the Shared VPC project needs to have: - A Private Service Connect with a range of `/24` (example: `10.60.0.0/24`) to deploy the Cloud SQL instance. - - Internet gateway configured to let the Test VM download packages. + - Internet access configured (for example Cloud NAT) to let the Test VM download packages. -In order to run the example and deploy Cloud SQL on a shared VPC the identity running Terraform must have the following IAM permissions on the Shared VPC Host project. - - compute.networks.list - - compute.addresses.create - - compute.addresses.list - - servicenetworking.services.addPeering - - compute.xpnAdmin +In order to run the example and deploy Cloud SQL on a shared VPC the identity running Terraform must have the following IAM role on the Shared VPC Host project. + - Compute Network Admin (roles/compute.networkAdmin) + - Compute Shared VPC Admin (roles/compute.xpnAdmin) ## Test your environment diff --git a/examples/data-solutions/cloudsql-multiregion/cloudsql.tf b/examples/data-solutions/cloudsql-multiregion/cloudsql.tf index 7962acea..b33dc980 100644 --- a/examples/data-solutions/cloudsql-multiregion/cloudsql.tf +++ b/examples/data-solutions/cloudsql-multiregion/cloudsql.tf @@ -16,7 +16,7 @@ module "db" { source = "../../../modules/cloudsql-instance" project_id = module.project.project_id availability_type = var.sql_configuration.availability_type - encryption_key_name = var.service_encryption_keys != null ? var.service_encryption_keys[var.regions.primary] : null + encryption_key_name = var.service_encryption_keys != null ? try(var.service_encryption_keys[var.regions.primary], null) : null network = local.vpc_self_link name = "${var.prefix}-db" region = var.regions.primary @@ -29,7 +29,7 @@ module "db" { for k, v in var.regions : k => { region = v, - encryption_key_name = var.service_encryption_keys != null ? var.service_encryption_keys[v] : null + encryption_key_name = var.service_encryption_keys != null ? try(var.service_encryption_keys[v], null) : null } if k != "primary" } databases = [var.postgres_database] diff --git a/examples/data-solutions/cloudsql-multiregion/datastorage.tf b/examples/data-solutions/cloudsql-multiregion/datastorage.tf index f394a128..1b45a97b 100644 --- a/examples/data-solutions/cloudsql-multiregion/datastorage.tf +++ b/examples/data-solutions/cloudsql-multiregion/datastorage.tf @@ -19,7 +19,7 @@ module "gcs" { name = "data" location = var.regions.primary storage_class = "REGIONAL" - encryption_key = var.service_encryption_keys != null ? var.service_encryption_keys[var.regions.primary] : null + encryption_key = var.service_encryption_keys != null ? try(var.service_encryption_keys[var.regions.primary], null) : null force_destroy = true } diff --git a/examples/data-solutions/cloudsql-multiregion/gce.tf b/examples/data-solutions/cloudsql-multiregion/gce.tf index 78078838..17048aa8 100644 --- a/examples/data-solutions/cloudsql-multiregion/gce.tf +++ b/examples/data-solutions/cloudsql-multiregion/gce.tf @@ -53,7 +53,7 @@ module "test-vm" { encryption = var.service_encryption_keys != null ? { encrypt_boot = true disk_encryption_key_raw = null - kms_key_self_link = var.service_encryption_keys != null ? var.service_encryption_keys[var.regions.primary] : null + kms_key_self_link = var.service_encryption_keys != null ? try(var.service_encryption_keys[var.regions.primary], null) : null } : null metadata = { startup-script = local.startup-script } tags = ["ssh"]