From 38fc9e8b9b31ed2fb2b0f9bcf955d01ff0306833 Mon Sep 17 00:00:00 2001 From: lcaggio Date: Sun, 5 Feb 2023 07:52:33 +0100 Subject: [PATCH 1/2] First commit --- .../cmek-via-centralized-kms/README.md | 15 ++-- .../cmek-via-centralized-kms/main.tf | 84 +++++++++++-------- .../cmek-via-centralized-kms/variables.tf | 36 ++++---- .../cmek_via_centralized_kms/fixture/main.tf | 13 ++- 4 files changed, 86 insertions(+), 62 deletions(-) diff --git a/blueprints/data-solutions/cmek-via-centralized-kms/README.md b/blueprints/data-solutions/cmek-via-centralized-kms/README.md index 88590c74b2..2af94f8747 100644 --- a/blueprints/data-solutions/cmek-via-centralized-kms/README.md +++ b/blueprints/data-solutions/cmek-via-centralized-kms/README.md @@ -1,8 +1,8 @@ # GCE and GCS CMEK via centralized Cloud KMS -This example creates a sample centralized [Cloud KMS](https://cloud.google.com/kms?hl=it) configuration, and uses it to implement CMEK for [Cloud Storage](https://cloud.google.com/storage/docs/encryption/using-customer-managed-keys) and [Compute Engine](https://cloud.google.com/compute/docs/disks/customer-managed-encryption) in a separate project. +This example creates a sample centralized [Cloud KMS](https://cloud.google.com/kms?hl=it) configuration, and uses it to implement CMEK for [Cloud Storage](https://cloud.google.com/storage/docs/encryption/using-customer-managed-keys) and [Compute Engine](https://cloud.google.com/compute/docs/disks/customer-managed-encryption) in a service project. -The example is designed to match real-world use cases with a minimum amount of resources, and be used as a starting point for scenarios where application projects implement CMEK using keys managed by a central team. It also includes the IAM wiring needed to make such scenarios work. +The example is designed to match real-world use cases with a minimum amount of resources, and be used as a starting point for scenarios where application projects implement CMEK using keys managed by a central team. It also includes the IAM wiring needed to make such scenarios work. Regional resources are used in this example, but the same logic will apply for 'dual regional', 'multi regional' or 'global' resources. This is the high level diagram: @@ -35,12 +35,11 @@ This sample creates several distinct groups of resources: | name | description | type | required | default | |---|---|:---:|:---:|:---:| -| [billing_account](variables.tf#L16) | Billing account id used as default for new projects. | string | ✓ | | -| [root_node](variables.tf#L45) | The resource name of the parent Folder or Organization. Must be of the form folders/folder_id or organizations/org_id. | string | ✓ | | -| [location](variables.tf#L21) | The location where resources will be deployed. | string | | "europe" | -| [project_kms_name](variables.tf#L27) | Name for the new KMS Project. | string | | "my-project-kms-001" | -| [project_service_name](variables.tf#L33) | Name for the new Service Project. | string | | "my-project-service-001" | -| [region](variables.tf#L39) | The region where resources will be deployed. | string | | "europe-west1" | +| [prefix](variables.tf#L21) | Optional prefix used to generate resources names. | string | ✓ | | +| [project_ids](variables.tf#L36) | Project ids, references existing project if `project_create` is null. | object({…}) | ✓ | | +| [location](variables.tf#L15) | The location where resources will be deployed. | string | | "europe" | +| [project_create](variables.tf#L27) | Provide values if project creation is needed, uses existing project if null. Parent is in 'folders/nnn' or 'organizations/nnn' format. | object({…}) | | null | +| [region](variables.tf#L44) | The region where resources will be deployed. | string | | "europe-west1" | | [vpc_ip_cidr_range](variables.tf#L50) | Ip range used in the subnet deployef in the Service Project. | string | | "10.0.0.0/20" | | [vpc_name](variables.tf#L56) | Name of the VPC created in the Service Project. | string | | "local" | | [vpc_subnet_name](variables.tf#L62) | Name of the subnet created in the Service Project. | string | | "subnet" | diff --git a/blueprints/data-solutions/cmek-via-centralized-kms/main.tf b/blueprints/data-solutions/cmek-via-centralized-kms/main.tf index fb7f9fdd16..a9357cb5a7 100644 --- a/blueprints/data-solutions/cmek-via-centralized-kms/main.tf +++ b/blueprints/data-solutions/cmek-via-centralized-kms/main.tf @@ -12,33 +12,61 @@ # See the License for the specific language governing permissions and # limitations under the License. +locals { + # Needed when you create KMS keys and encrypted resources in the same terraform state but different projects. + kms_keys = { + gce = "projects/${module.project-kms.project_id}/locations/${var.region}/keyRings/${var.region}/cryptoKeys/key-gcs" + gcs = "projects/${module.project-kms.project_id}/locations/${var.region}/keyRings/${var.region}/cryptoKeys/key-gcs" + } +} + ############################################################################### # Projects # ############################################################################### module "project-service" { source = "../../../modules/project" - name = var.project_service_name - parent = var.root_node - billing_account = var.billing_account + name = var.project_ids.service + parent = try(var.project_create.parent, null) + billing_account = try(var.project_create.billing_account_id, null) + project_create = var.project_create != null + prefix = var.project_create == null ? null : var.prefix services = [ "compute.googleapis.com", "servicenetworking.googleapis.com", - "storage-component.googleapis.com" + "storage.googleapis.com", + "storage-component.googleapis.com", + ] + service_encryption_key_ids = { + compute = [ + local.kms_keys.gce + ] + storage = [ + local.kms_keys.gcs + ] + } + service_config = { + disable_on_destroy = false, disable_dependent_services = false + } + depends_on = [ + module.kms ] - oslogin = true } module "project-kms" { source = "../../../modules/project" - name = var.project_kms_name - parent = var.root_node - billing_account = var.billing_account + name = var.project_ids.encryption + parent = try(var.project_create.parent, null) + billing_account = try(var.project_create.billing_account_id, null) + project_create = var.project_create != null + prefix = var.project_create == null ? null : var.prefix services = [ "cloudkms.googleapis.com", "servicenetworking.googleapis.com" ] - oslogin = true + service_config = { + disable_on_destroy = false, disable_dependent_services = false + } } ############################################################################### @@ -48,11 +76,11 @@ module "project-kms" { module "vpc" { source = "../../../modules/net-vpc" project_id = module.project-service.project_id - name = var.vpc_name + name = "${var.prefix}-vpc" subnets = [ { - ip_cidr_range = var.vpc_ip_cidr_range - name = var.vpc_subnet_name + ip_cidr_range = "10.0.0.0/20" + name = "${var.prefix}-${var.region}" region = var.region } ] @@ -63,7 +91,7 @@ module "vpc-firewall" { project_id = module.project-service.project_id network = module.vpc.name default_rules_config = { - admin_ranges = [var.vpc_ip_cidr_range] + admin_ranges = ["10.0.0.0/20"] } } @@ -75,22 +103,10 @@ module "kms" { source = "../../../modules/kms" project_id = module.project-kms.project_id keyring = { - name = "my-keyring", - location = var.location + name = var.region, + location = var.region } keys = { key-gce = null, key-gcs = null } - key_iam = { - key-gce = { - "roles/cloudkms.cryptoKeyEncrypterDecrypter" = [ - "serviceAccount:${module.project-service.service_accounts.robots.compute}", - ] - }, - key-gcs = { - "roles/cloudkms.cryptoKeyEncrypterDecrypter" = [ - "serviceAccount:${module.project-service.service_accounts.robots.storage}", - ] - } - } } ############################################################################### @@ -101,10 +117,10 @@ module "vm_example" { source = "../../../modules/compute-vm" project_id = module.project-service.project_id zone = "${var.region}-b" - name = "kms-vm" + name = "${var.prefix}-vm" network_interfaces = [{ network = module.vpc.self_link, - subnetwork = module.vpc.subnet_self_links["${var.region}/subnet"], + subnetwork = module.vpc.subnet_self_links["${var.region}/${var.prefix}-${var.region}"], nat = false, addresses = null }] @@ -127,7 +143,7 @@ module "vm_example" { encryption = { encrypt_boot = true disk_encryption_key_raw = null - kms_key_self_link = module.kms.key_ids.key-gce + kms_key_self_link = local.kms_keys.gce } } @@ -138,7 +154,9 @@ module "vm_example" { module "kms-gcs" { source = "../../../modules/gcs" project_id = module.project-service.project_id - prefix = "my-bucket-001" - name = "kms-gcs" - encryption_key = module.kms.keys.key-gcs.id + prefix = var.prefix + name = "${var.prefix}-bucket" + location = var.region + storage_class = "REGIONAL" + encryption_key = local.kms_keys.gcs } diff --git a/blueprints/data-solutions/cmek-via-centralized-kms/variables.tf b/blueprints/data-solutions/cmek-via-centralized-kms/variables.tf index 737bde3dd0..19ebe29ac1 100644 --- a/blueprints/data-solutions/cmek-via-centralized-kms/variables.tf +++ b/blueprints/data-solutions/cmek-via-centralized-kms/variables.tf @@ -12,28 +12,33 @@ # See the License for the specific language governing permissions and # limitations under the License. - -variable "billing_account" { - description = "Billing account id used as default for new projects." - type = string -} - variable "location" { description = "The location where resources will be deployed." type = string default = "europe" } -variable "project_kms_name" { - description = "Name for the new KMS Project." +variable "prefix" { + description = "Optional prefix used to generate resources names." type = string - default = "my-project-kms-001" + nullable = false } -variable "project_service_name" { - description = "Name for the new Service Project." - type = string - default = "my-project-service-001" +variable "project_create" { + description = "Provide values if project creation is needed, uses existing project if null. Parent is in 'folders/nnn' or 'organizations/nnn' format." + type = object({ + billing_account_id = string + parent = string + }) + default = null +} + +variable "project_ids" { + description = "Project ids, references existing project if `project_create` is null." + type = object({ + encryption = string + service = string + }) } variable "region" { @@ -42,11 +47,6 @@ variable "region" { default = "europe-west1" } -variable "root_node" { - description = "The resource name of the parent Folder or Organization. Must be of the form folders/folder_id or organizations/org_id." - type = string -} - variable "vpc_ip_cidr_range" { description = "Ip range used in the subnet deployef in the Service Project." type = string diff --git a/tests/blueprints/data_solutions/cmek_via_centralized_kms/fixture/main.tf b/tests/blueprints/data_solutions/cmek_via_centralized_kms/fixture/main.tf index 65cc20aeb2..9caad59b87 100644 --- a/tests/blueprints/data_solutions/cmek_via_centralized_kms/fixture/main.tf +++ b/tests/blueprints/data_solutions/cmek_via_centralized_kms/fixture/main.tf @@ -15,7 +15,14 @@ */ module "test" { - source = "../../../../../blueprints/data-solutions/cmek-via-centralized-kms/" - billing_account = var.billing_account - root_node = var.root_node + source = "../../../../../blueprints/data-solutions/cmek-via-centralized-kms/" + project_create = { + billing_account_id = "123456-123456-123456" + parent = "folders/12345678" + } + project_ids = { + encryption = "kms" + service = "service" + } + prefix = "prefix" } From 47c75f8862054dd82181a57661e54d84265401bb Mon Sep 17 00:00:00 2001 From: lcaggio Date: Sun, 5 Feb 2023 21:12:46 +0100 Subject: [PATCH 2/2] Implement project_config variable --- .../cmek-via-centralized-kms/README.md | 3 +-- .../cmek-via-centralized-kms/main.tf | 26 +++++++++---------- .../cmek-via-centralized-kms/variables.tf | 26 +++++++++---------- .../cmek_via_centralized_kms/fixture/main.tf | 6 +---- .../fixture/variables.tf | 26 ------------------- 5 files changed, 28 insertions(+), 59 deletions(-) delete mode 100644 tests/blueprints/data_solutions/cmek_via_centralized_kms/fixture/variables.tf diff --git a/blueprints/data-solutions/cmek-via-centralized-kms/README.md b/blueprints/data-solutions/cmek-via-centralized-kms/README.md index 2af94f8747..3813c90c2f 100644 --- a/blueprints/data-solutions/cmek-via-centralized-kms/README.md +++ b/blueprints/data-solutions/cmek-via-centralized-kms/README.md @@ -36,9 +36,8 @@ This sample creates several distinct groups of resources: | name | description | type | required | default | |---|---|:---:|:---:|:---:| | [prefix](variables.tf#L21) | Optional prefix used to generate resources names. | string | ✓ | | -| [project_ids](variables.tf#L36) | Project ids, references existing project if `project_create` is null. | object({…}) | ✓ | | +| [project_config](variables.tf#L27) | Provide 'billing_account_id' and 'parent' values if project creation is needed, uses existing 'projects_id' if null. Parent is in 'folders/nnn' or 'organizations/nnn' format. | object({…}) | ✓ | | | [location](variables.tf#L15) | The location where resources will be deployed. | string | | "europe" | -| [project_create](variables.tf#L27) | Provide values if project creation is needed, uses existing project if null. Parent is in 'folders/nnn' or 'organizations/nnn' format. | object({…}) | | null | | [region](variables.tf#L44) | The region where resources will be deployed. | string | | "europe-west1" | | [vpc_ip_cidr_range](variables.tf#L50) | Ip range used in the subnet deployef in the Service Project. | string | | "10.0.0.0/20" | | [vpc_name](variables.tf#L56) | Name of the VPC created in the Service Project. | string | | "local" | diff --git a/blueprints/data-solutions/cmek-via-centralized-kms/main.tf b/blueprints/data-solutions/cmek-via-centralized-kms/main.tf index a9357cb5a7..73f2b70184 100644 --- a/blueprints/data-solutions/cmek-via-centralized-kms/main.tf +++ b/blueprints/data-solutions/cmek-via-centralized-kms/main.tf @@ -15,8 +15,8 @@ locals { # Needed when you create KMS keys and encrypted resources in the same terraform state but different projects. kms_keys = { - gce = "projects/${module.project-kms.project_id}/locations/${var.region}/keyRings/${var.region}/cryptoKeys/key-gcs" - gcs = "projects/${module.project-kms.project_id}/locations/${var.region}/keyRings/${var.region}/cryptoKeys/key-gcs" + gce = "projects/${module.project-kms.project_id}/locations/${var.region}/keyRings/${var.prefix}-${var.region}/cryptoKeys/key-gcs" + gcs = "projects/${module.project-kms.project_id}/locations/${var.region}/keyRings/${var.prefix}-${var.region}/cryptoKeys/key-gcs" } } @@ -26,11 +26,11 @@ locals { module "project-service" { source = "../../../modules/project" - name = var.project_ids.service - parent = try(var.project_create.parent, null) - billing_account = try(var.project_create.billing_account_id, null) - project_create = var.project_create != null - prefix = var.project_create == null ? null : var.prefix + name = var.project_config.project_ids.service + parent = var.project_config.parent + billing_account = var.project_config.billing_account_id + project_create = var.project_config.billing_account_id != null + prefix = var.project_config.billing_account_id == null ? null : var.prefix services = [ "compute.googleapis.com", "servicenetworking.googleapis.com", @@ -55,11 +55,11 @@ module "project-service" { module "project-kms" { source = "../../../modules/project" - name = var.project_ids.encryption - parent = try(var.project_create.parent, null) - billing_account = try(var.project_create.billing_account_id, null) - project_create = var.project_create != null - prefix = var.project_create == null ? null : var.prefix + name = var.project_config.project_ids.encryption + parent = var.project_config.parent + billing_account = var.project_config.billing_account_id + project_create = var.project_config.billing_account_id != null + prefix = var.project_config.billing_account_id == null ? null : var.prefix services = [ "cloudkms.googleapis.com", "servicenetworking.googleapis.com" @@ -103,7 +103,7 @@ module "kms" { source = "../../../modules/kms" project_id = module.project-kms.project_id keyring = { - name = var.region, + name = "${var.prefix}-${var.region}", location = var.region } keys = { key-gce = null, key-gcs = null } diff --git a/blueprints/data-solutions/cmek-via-centralized-kms/variables.tf b/blueprints/data-solutions/cmek-via-centralized-kms/variables.tf index 19ebe29ac1..5d35351c9f 100644 --- a/blueprints/data-solutions/cmek-via-centralized-kms/variables.tf +++ b/blueprints/data-solutions/cmek-via-centralized-kms/variables.tf @@ -24,21 +24,21 @@ variable "prefix" { nullable = false } -variable "project_create" { - description = "Provide values if project creation is needed, uses existing project if null. Parent is in 'folders/nnn' or 'organizations/nnn' format." +variable "project_config" { + description = "Provide 'billing_account_id' and 'parent' values if project creation is needed, uses existing 'projects_id' if null. Parent is in 'folders/nnn' or 'organizations/nnn' format." type = object({ - billing_account_id = string - parent = string - }) - default = null -} - -variable "project_ids" { - description = "Project ids, references existing project if `project_create` is null." - type = object({ - encryption = string - service = string + billing_account_id = optional(string, null) + parent = optional(string, null) + project_ids = optional(object({ + encryption = string + service = string + }), { + encryption = "encryption", + service = "service" + } + ) }) + nullable = false } variable "region" { diff --git a/tests/blueprints/data_solutions/cmek_via_centralized_kms/fixture/main.tf b/tests/blueprints/data_solutions/cmek_via_centralized_kms/fixture/main.tf index 9caad59b87..3fee8af5f0 100644 --- a/tests/blueprints/data_solutions/cmek_via_centralized_kms/fixture/main.tf +++ b/tests/blueprints/data_solutions/cmek_via_centralized_kms/fixture/main.tf @@ -16,13 +16,9 @@ module "test" { source = "../../../../../blueprints/data-solutions/cmek-via-centralized-kms/" - project_create = { + project_config = { billing_account_id = "123456-123456-123456" parent = "folders/12345678" } - project_ids = { - encryption = "kms" - service = "service" - } prefix = "prefix" } diff --git a/tests/blueprints/data_solutions/cmek_via_centralized_kms/fixture/variables.tf b/tests/blueprints/data_solutions/cmek_via_centralized_kms/fixture/variables.tf deleted file mode 100644 index 6a534739fb..0000000000 --- a/tests/blueprints/data_solutions/cmek_via_centralized_kms/fixture/variables.tf +++ /dev/null @@ -1,26 +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 - * - * http://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. - */ - -variable "billing_account" { - type = string - default = "123456-123456-123456" -} - -variable "root_node" { - description = "The resource name of the parent Folder or Organization. Must be of the form folders/folder_id or organizations/org_id." - type = string - default = "folders/12345678" -}