diff --git a/blueprints/data-solutions/cmek-via-centralized-kms/README.md b/blueprints/data-solutions/cmek-via-centralized-kms/README.md index 88590c74b2..3813c90c2f 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,10 @@ 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_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" | +| [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..73f2b70184 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.prefix}-${var.region}/cryptoKeys/key-gcs" + gcs = "projects/${module.project-kms.project_id}/locations/${var.region}/keyRings/${var.prefix}-${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_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", - "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_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" ] - 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.prefix}-${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..5d35351c9f 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_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 = optional(string, null) + parent = optional(string, null) + project_ids = optional(object({ + encryption = string + service = string + }), { + encryption = "encryption", + service = "service" + } + ) + }) + nullable = false } 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..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 @@ -15,7 +15,10 @@ */ 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_config = { + billing_account_id = "123456-123456-123456" + parent = "folders/12345678" + } + 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" -}