From a1c61f089df9829fc773a6bce6557cf578f8bd72 Mon Sep 17 00:00:00 2001 From: Lorenzo Caggioni Date: Mon, 20 Jun 2022 15:21:03 +0200 Subject: [PATCH 1/8] Add location support --- fast/stages/03-data-platform/dev/main.tf | 1 + fast/stages/03-data-platform/dev/variables.tf | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/fast/stages/03-data-platform/dev/main.tf b/fast/stages/03-data-platform/dev/main.tf index 536e1873..f26a5288 100644 --- a/fast/stages/03-data-platform/dev/main.tf +++ b/fast/stages/03-data-platform/dev/main.tf @@ -24,6 +24,7 @@ module "data-platform" { data_catalog_tags = var.data_catalog_tags folder_id = var.folder_ids.data-platform groups = var.groups + location = var.location network_config = { host_project = var.host_project_ids.dev-spoke-0 network_self_link = var.vpc_self_links.dev-spoke-0 diff --git a/fast/stages/03-data-platform/dev/variables.tf b/fast/stages/03-data-platform/dev/variables.tf index 3b1645e4..c41befdd 100644 --- a/fast/stages/03-data-platform/dev/variables.tf +++ b/fast/stages/03-data-platform/dev/variables.tf @@ -79,6 +79,12 @@ variable "host_project_ids" { }) } +variable "location" { + description = "Location used for multi-regional resources." + type = string + default = "eu" +} + variable "network_config_composer" { description = "Network configurations to use for Composer." type = object({ From c464a3c8cc0d6d674e87a8aadf2ef1067644654c Mon Sep 17 00:00:00 2001 From: Lorenzo Caggioni Date: Mon, 20 Jun 2022 17:13:25 +0200 Subject: [PATCH 2/8] Improve KMS: add custom role to handle keys --- fast/stages/00-bootstrap/organization.tf | 6 ++++++ fast/stages/00-bootstrap/variables.tf | 2 ++ fast/stages/02-security/core-dev.tf | 3 ++- fast/stages/02-security/core-prod.tf | 3 ++- fast/stages/02-security/main.tf | 1 + fast/stages/02-security/variables.tf | 11 +++++++++++ 6 files changed, 24 insertions(+), 2 deletions(-) diff --git a/fast/stages/00-bootstrap/organization.tf b/fast/stages/00-bootstrap/organization.tf index ea7c2e58..935f9ca0 100644 --- a/fast/stages/00-bootstrap/organization.tf +++ b/fast/stages/00-bootstrap/organization.tf @@ -171,6 +171,12 @@ module "organization" { "dns.networks.bindPrivateDNSZone", "resourcemanager.projects.get", ] + (var.custom_role_names.cloud_kms_key_role_editor) = [ + "cloudkms.cryptoKeys.get", + "cloudkms.cryptoKeys.list", + "cloudkms.cryptoKeys.getIamPolicy", + "cloudkms.cryptoKeys.setIamPolicy" + ] } logging_sinks = { for name, attrs in var.log_sinks : name => { diff --git a/fast/stages/00-bootstrap/variables.tf b/fast/stages/00-bootstrap/variables.tf index a08fedb1..7d4d9d9f 100644 --- a/fast/stages/00-bootstrap/variables.tf +++ b/fast/stages/00-bootstrap/variables.tf @@ -79,10 +79,12 @@ variable "custom_role_names" { type = object({ organization_iam_admin = string service_project_network_admin = string + cloud_kms_key_role_editor = string }) default = { organization_iam_admin = "organizationIamAdmin" service_project_network_admin = "serviceProjectNetworkAdmin" + cloud_kms_key_role_editor = "cloudKmsKeyAdmin" } } diff --git a/fast/stages/02-security/core-dev.tf b/fast/stages/02-security/core-dev.tf index 92fcaec0..9cc7b917 100644 --- a/fast/stages/02-security/core-dev.tf +++ b/fast/stages/02-security/core-dev.tf @@ -27,7 +27,8 @@ module "dev-sec-project" { prefix = var.prefix billing_account = var.billing_account.id iam = { - "roles/cloudkms.viewer" = local.dev_kms_restricted_admins + (local.custom_roles.cloud_kms_key_role_editor) = ["serviceAccount:${var.service_accounts.data-platform-dev}"] + "roles/cloudkms.viewer" = local.dev_kms_restricted_admins } labels = { environment = "dev", team = "security" } services = local.project_services diff --git a/fast/stages/02-security/core-prod.tf b/fast/stages/02-security/core-prod.tf index d00c724d..9456cbb4 100644 --- a/fast/stages/02-security/core-prod.tf +++ b/fast/stages/02-security/core-prod.tf @@ -27,7 +27,8 @@ module "prod-sec-project" { prefix = var.prefix billing_account = var.billing_account.id iam = { - "roles/cloudkms.viewer" = local.prod_kms_restricted_admins + (local.custom_roles.cloud_kms_key_role_editor) = ["serviceAccount:${var.service_accounts.data-platform-prod}"] + "roles/cloudkms.viewer" = local.prod_kms_restricted_admins } labels = { environment = "prod", team = "security" } services = local.project_services diff --git a/fast/stages/02-security/main.tf b/fast/stages/02-security/main.tf index 13078d12..c1e1aa0f 100644 --- a/fast/stages/02-security/main.tf +++ b/fast/stages/02-security/main.tf @@ -15,6 +15,7 @@ */ locals { + custom_roles = coalesce(var.custom_roles, {}) kms_keys = { for k, v in var.kms_keys : k => { iam = coalesce(v.iam, {}) diff --git a/fast/stages/02-security/variables.tf b/fast/stages/02-security/variables.tf index 352f4f39..4276b4d2 100644 --- a/fast/stages/02-security/variables.tf +++ b/fast/stages/02-security/variables.tf @@ -31,6 +31,15 @@ variable "billing_account" { }) } +variable "custom_roles" { + # tfdoc:variable:source 00-bootstrap + description = "Custom roles defined at the org level, in key => id format." + type = object({ + cloud_kms_key_role_editor = string + }) + default = null +} + variable "folder_ids" { # tfdoc:variable:source 01-resman description = "Folder name => id mappings, the 'security' folder name must exist." @@ -81,6 +90,8 @@ variable "service_accounts" { # tfdoc:variable:source 01-resman description = "Automation service accounts that can assign the encrypt/decrypt roles on keys." type = object({ + data-platform-dev = string + data-platform-prod = string project-factory-dev = string project-factory-prod = string }) From 6edc80e2826b230c786318db1bde63b0d802d5f0 Mon Sep 17 00:00:00 2001 From: Lorenzo Caggioni Date: Mon, 20 Jun 2022 17:27:28 +0200 Subject: [PATCH 3/8] Update READMEs --- fast/stages/00-bootstrap/README.md | 18 +++++++++--------- fast/stages/03-data-platform/dev/README.md | 19 ++++++++++--------- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/fast/stages/00-bootstrap/README.md b/fast/stages/00-bootstrap/README.md index 3fcfb66c..96db9b53 100644 --- a/fast/stages/00-bootstrap/README.md +++ b/fast/stages/00-bootstrap/README.md @@ -441,17 +441,17 @@ The remaining configuration is manual, as it regards the repositories themselves | name | description | type | required | default | producer | |---|---|:---:|:---:|:---:|:---:| | [billing_account](variables.tf#L17) | Billing account id and organization id ('nnnnnnnn' or null). | object({…}) | ✓ | | | -| [organization](variables.tf#L152) | Organization details. | object({…}) | ✓ | | | -| [prefix](variables.tf#L167) | Prefix used for resources that need unique names. Use 9 characters or less. | string | ✓ | | | +| [organization](variables.tf#L154) | Organization details. | object({…}) | ✓ | | | +| [prefix](variables.tf#L169) | Prefix used for resources that need unique names. Use 9 characters or less. | string | ✓ | | | | [bootstrap_user](variables.tf#L25) | Email of the nominal user running this stage for the first time. | string | | null | | | [cicd_repositories](variables.tf#L31) | CI/CD repository configuration. Identity providers reference keys in the `federated_identity_providers` variable. Set to null to disable, or set individual repositories to null if not needed. | object({…}) | | null | | -| [custom_role_names](variables.tf#L77) | Names of custom roles defined at the org level. | object({…}) | | {…} | | -| [federated_identity_providers](variables.tf#L89) | Workload Identity Federation pools. The `cicd_repositories` variable references keys here. | map(object({…})) | | {} | | -| [groups](variables.tf#L99) | Group names to grant organization-level permissions. | map(string) | | {…} | | -| [iam](variables.tf#L113) | Organization-level custom IAM settings in role => [principal] format. | map(list(string)) | | {} | | -| [iam_additive](variables.tf#L119) | Organization-level custom IAM settings in role => [principal] format for non-authoritative bindings. | map(list(string)) | | {} | | -| [log_sinks](variables.tf#L127) | Org-level log sinks, in name => {type, filter} format. | map(object({…})) | | {…} | | -| [outputs_location](variables.tf#L161) | Enable writing provider, tfvars and CI/CD workflow files to local filesystem. Leave null to disable | string | | null | | +| [custom_role_names](variables.tf#L77) | Names of custom roles defined at the org level. | object({…}) | | {…} | | +| [federated_identity_providers](variables.tf#L91) | Workload Identity Federation pools. The `cicd_repositories` variable references keys here. | map(object({…})) | | {} | | +| [groups](variables.tf#L101) | Group names to grant organization-level permissions. | map(string) | | {…} | | +| [iam](variables.tf#L115) | Organization-level custom IAM settings in role => [principal] format. | map(list(string)) | | {} | | +| [iam_additive](variables.tf#L121) | Organization-level custom IAM settings in role => [principal] format for non-authoritative bindings. | map(list(string)) | | {} | | +| [log_sinks](variables.tf#L129) | Org-level log sinks, in name => {type, filter} format. | map(object({…})) | | {…} | | +| [outputs_location](variables.tf#L163) | Enable writing provider, tfvars and CI/CD workflow files to local filesystem. Leave null to disable | string | | null | | ## Outputs diff --git a/fast/stages/03-data-platform/dev/README.md b/fast/stages/03-data-platform/dev/README.md index 7bc41760..f32c3327 100644 --- a/fast/stages/03-data-platform/dev/README.md +++ b/fast/stages/03-data-platform/dev/README.md @@ -159,19 +159,20 @@ You can find examples in the `[demo](../../../../examples/data-solutions/data-pl | [billing_account](variables.tf#L17) | Billing account id and organization id ('nnnnnnnn' or null). | object({…}) | ✓ | | 00-globals | | [folder_ids](variables.tf#L56) | Folder to be used for the networking resources in folders/nnnn format. | object({…}) | ✓ | | 01-resman | | [host_project_ids](variables.tf#L74) | Shared VPC project ids. | object({…}) | ✓ | | 02-networking | -| [organization](variables.tf#L100) | Organization details. | object({…}) | ✓ | | 00-globals | -| [prefix](variables.tf#L116) | Unique prefix used for resource names. Not used for projects if 'project_create' is null. | string | ✓ | | 00-globals | +| [organization](variables.tf#L106) | Organization details. | object({…}) | ✓ | | 00-globals | +| [prefix](variables.tf#L122) | Unique prefix used for resource names. Not used for projects if 'project_create' is null. | string | ✓ | | 00-globals | | [composer_config](variables.tf#L26) | | object({…}) | | {…} | | | [data_catalog_tags](variables.tf#L39) | List of Data Catalog Policy tags to be created with optional IAM binging configuration in {tag => {ROLE => [MEMBERS]}} format. | map(map(list(string))) | | {…} | | | [data_force_destroy](variables.tf#L50) | Flag to set 'force_destroy' on data services like BigQery or Cloud Storage. | bool | | false | | | [groups](variables.tf#L64) | Groups. | map(string) | | {…} | | -| [network_config_composer](variables.tf#L82) | Network configurations to use for Composer. | object({…}) | | {…} | | -| [outputs_location](variables.tf#L110) | Path where providers, tfvars files, and lists for the following stages are written. Leave empty to disable. | string | | null | | -| [project_services](variables.tf#L122) | List of core services enabled on all projects. | list(string) | | […] | | -| [region](variables.tf#L133) | Region used for regional resources. | string | | "europe-west1" | | -| [service_encryption_keys](variables.tf#L139) | Cloud KMS to use to encrypt different services. Key location should match service region. | object({…}) | | null | | -| [subnet_self_links](variables.tf#L151) | Shared VPC subnet self links. | object({…}) | | null | 02-networking | -| [vpc_self_links](variables.tf#L160) | Shared VPC self links. | object({…}) | | null | 02-networking | +| [location](variables.tf#L82) | Location used for multi-regional resources. | string | | "eu" | | +| [network_config_composer](variables.tf#L88) | Network configurations to use for Composer. | object({…}) | | {…} | | +| [outputs_location](variables.tf#L116) | Path where providers, tfvars files, and lists for the following stages are written. Leave empty to disable. | string | | null | | +| [project_services](variables.tf#L128) | List of core services enabled on all projects. | list(string) | | […] | | +| [region](variables.tf#L139) | Region used for regional resources. | string | | "europe-west1" | | +| [service_encryption_keys](variables.tf#L145) | Cloud KMS to use to encrypt different services. Key location should match service region. | object({…}) | | null | | +| [subnet_self_links](variables.tf#L157) | Shared VPC subnet self links. | object({…}) | | null | 02-networking | +| [vpc_self_links](variables.tf#L166) | Shared VPC self links. | object({…}) | | null | 02-networking | ## Outputs From 7625773deafe7d1bab210e98b507606b91a683a5 Mon Sep 17 00:00:00 2001 From: Lorenzo Caggioni Date: Mon, 20 Jun 2022 22:05:19 +0200 Subject: [PATCH 4/8] Fix tests --- fast/stages/02-security/README.md | 31 ++++++++++--------- .../fast/stages/s02_security/fixture/main.tf | 5 +++ 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/fast/stages/02-security/README.md b/fast/stages/02-security/README.md index 872d727e..5847cba3 100644 --- a/fast/stages/02-security/README.md +++ b/fast/stages/02-security/README.md @@ -288,21 +288,22 @@ Some references that might be useful in setting up this stage: |---|---|:---:|:---:|:---:|:---:| | [automation](variables.tf#L17) | Automation resources created by the bootstrap stage. | object({…}) | ✓ | | 00-bootstrap | | [billing_account](variables.tf#L25) | Billing account id and organization id ('nnnnnnnn' or null). | object({…}) | ✓ | | 00-bootstrap | -| [folder_ids](variables.tf#L34) | Folder name => id mappings, the 'security' folder name must exist. | object({…}) | ✓ | | 01-resman | -| [organization](variables.tf#L89) | Organization details. | object({…}) | ✓ | | 00-bootstrap | -| [prefix](variables.tf#L105) | Prefix used for resources that need unique names. Use 9 characters or less. | string | ✓ | | 00-bootstrap | -| [service_accounts](variables.tf#L80) | Automation service accounts that can assign the encrypt/decrypt roles on keys. | object({…}) | ✓ | | 01-resman | -| [groups](variables.tf#L42) | Group names to grant organization-level permissions. | map(string) | | {…} | 00-bootstrap | -| [kms_defaults](variables.tf#L57) | Defaults used for KMS keys. | object({…}) | | {…} | | -| [kms_keys](variables.tf#L69) | KMS keys to create, keyed by name. Null attributes will be interpolated with defaults. | map(object({…})) | | {} | | -| [outputs_location](variables.tf#L99) | Path where providers, tfvars files, and lists for the following stages are written. Leave empty to disable. | string | | null | | -| [vpc_sc_access_levels](variables.tf#L116) | VPC SC access level definitions. | map(object({…})) | | {} | | -| [vpc_sc_egress_policies](variables.tf#L131) | VPC SC egress policy defnitions. | map(object({…})) | | {} | | -| [vpc_sc_ingress_policies](variables.tf#L149) | VPC SC ingress policy defnitions. | map(object({…})) | | {} | | -| [vpc_sc_perimeter_access_levels](variables.tf#L169) | VPC SC perimeter access_levels. | object({…}) | | null | | -| [vpc_sc_perimeter_egress_policies](variables.tf#L179) | VPC SC egress policies per perimeter, values reference keys defined in the `vpc_sc_ingress_policies` variable. | object({…}) | | null | | -| [vpc_sc_perimeter_ingress_policies](variables.tf#L189) | VPC SC ingress policies per perimeter, values reference keys defined in the `vpc_sc_ingress_policies` variable. | object({…}) | | null | | -| [vpc_sc_perimeter_projects](variables.tf#L199) | VPC SC perimeter resources. | object({…}) | | null | | +| [folder_ids](variables.tf#L43) | Folder name => id mappings, the 'security' folder name must exist. | object({…}) | ✓ | | 01-resman | +| [organization](variables.tf#L100) | Organization details. | object({…}) | ✓ | | 00-bootstrap | +| [prefix](variables.tf#L116) | Prefix used for resources that need unique names. Use 9 characters or less. | string | ✓ | | 00-bootstrap | +| [service_accounts](variables.tf#L89) | Automation service accounts that can assign the encrypt/decrypt roles on keys. | object({…}) | ✓ | | 01-resman | +| [custom_roles](variables.tf#L34) | Custom roles defined at the org level, in key => id format. | object({…}) | | null | 00-bootstrap | +| [groups](variables.tf#L51) | Group names to grant organization-level permissions. | map(string) | | {…} | 00-bootstrap | +| [kms_defaults](variables.tf#L66) | Defaults used for KMS keys. | object({…}) | | {…} | | +| [kms_keys](variables.tf#L78) | KMS keys to create, keyed by name. Null attributes will be interpolated with defaults. | map(object({…})) | | {} | | +| [outputs_location](variables.tf#L110) | Path where providers, tfvars files, and lists for the following stages are written. Leave empty to disable. | string | | null | | +| [vpc_sc_access_levels](variables.tf#L127) | VPC SC access level definitions. | map(object({…})) | | {} | | +| [vpc_sc_egress_policies](variables.tf#L142) | VPC SC egress policy defnitions. | map(object({…})) | | {} | | +| [vpc_sc_ingress_policies](variables.tf#L160) | VPC SC ingress policy defnitions. | map(object({…})) | | {} | | +| [vpc_sc_perimeter_access_levels](variables.tf#L180) | VPC SC perimeter access_levels. | object({…}) | | null | | +| [vpc_sc_perimeter_egress_policies](variables.tf#L190) | VPC SC egress policies per perimeter, values reference keys defined in the `vpc_sc_ingress_policies` variable. | object({…}) | | null | | +| [vpc_sc_perimeter_ingress_policies](variables.tf#L200) | VPC SC ingress policies per perimeter, values reference keys defined in the `vpc_sc_ingress_policies` variable. | object({…}) | | null | | +| [vpc_sc_perimeter_projects](variables.tf#L210) | VPC SC perimeter resources. | object({…}) | | null | | ## Outputs diff --git a/tests/fast/stages/s02_security/fixture/main.tf b/tests/fast/stages/s02_security/fixture/main.tf index 9947fc49..fd65319e 100644 --- a/tests/fast/stages/s02_security/fixture/main.tf +++ b/tests/fast/stages/s02_security/fixture/main.tf @@ -23,6 +23,9 @@ module "stage" { id = "000000-111111-222222" organization_id = 123456789012 } + custom_roles = { + cloud_kms_key_role_editor = "cloudKmsKeyAdmin" + } folder_ids = { security = null } @@ -44,6 +47,8 @@ module "stage" { } service_accounts = { security = "foobar@iam.gserviceaccount.com" + data-platform-dev = "foobar@iam.gserviceaccount.com" + data-platform-prod = "foobar@iam.gserviceaccount.com" project-factory-dev = "foobar@iam.gserviceaccount.com" project-factory-prod = "foobar@iam.gserviceaccount.com" } From 2ce4b002f1457154d55aa2469ce1c83b4735a432 Mon Sep 17 00:00:00 2001 From: Lorenzo Caggioni Date: Mon, 20 Jun 2022 22:23:18 +0200 Subject: [PATCH 5/8] Rename role --- fast/stages/00-bootstrap/README.md | 2 +- fast/stages/00-bootstrap/organization.tf | 2 +- fast/stages/00-bootstrap/variables.tf | 4 ++-- fast/stages/02-security/README.md | 2 +- fast/stages/02-security/core-dev.tf | 4 ++-- fast/stages/02-security/core-prod.tf | 4 ++-- fast/stages/02-security/variables.tf | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/fast/stages/00-bootstrap/README.md b/fast/stages/00-bootstrap/README.md index 96db9b53..eb89f866 100644 --- a/fast/stages/00-bootstrap/README.md +++ b/fast/stages/00-bootstrap/README.md @@ -445,7 +445,7 @@ The remaining configuration is manual, as it regards the repositories themselves | [prefix](variables.tf#L169) | Prefix used for resources that need unique names. Use 9 characters or less. | string | ✓ | | | | [bootstrap_user](variables.tf#L25) | Email of the nominal user running this stage for the first time. | string | | null | | | [cicd_repositories](variables.tf#L31) | CI/CD repository configuration. Identity providers reference keys in the `federated_identity_providers` variable. Set to null to disable, or set individual repositories to null if not needed. | object({…}) | | null | | -| [custom_role_names](variables.tf#L77) | Names of custom roles defined at the org level. | object({…}) | | {…} | | +| [custom_role_names](variables.tf#L77) | Names of custom roles defined at the org level. | object({…}) | | {…} | | | [federated_identity_providers](variables.tf#L91) | Workload Identity Federation pools. The `cicd_repositories` variable references keys here. | map(object({…})) | | {} | | | [groups](variables.tf#L101) | Group names to grant organization-level permissions. | map(string) | | {…} | | | [iam](variables.tf#L115) | Organization-level custom IAM settings in role => [principal] format. | map(list(string)) | | {} | | diff --git a/fast/stages/00-bootstrap/organization.tf b/fast/stages/00-bootstrap/organization.tf index 935f9ca0..e18a1f13 100644 --- a/fast/stages/00-bootstrap/organization.tf +++ b/fast/stages/00-bootstrap/organization.tf @@ -171,7 +171,7 @@ module "organization" { "dns.networks.bindPrivateDNSZone", "resourcemanager.projects.get", ] - (var.custom_role_names.cloud_kms_key_role_editor) = [ + (var.custom_role_names.cloud_kms_key_editor) = [ "cloudkms.cryptoKeys.get", "cloudkms.cryptoKeys.list", "cloudkms.cryptoKeys.getIamPolicy", diff --git a/fast/stages/00-bootstrap/variables.tf b/fast/stages/00-bootstrap/variables.tf index 7d4d9d9f..428fe4da 100644 --- a/fast/stages/00-bootstrap/variables.tf +++ b/fast/stages/00-bootstrap/variables.tf @@ -79,12 +79,12 @@ variable "custom_role_names" { type = object({ organization_iam_admin = string service_project_network_admin = string - cloud_kms_key_role_editor = string + cloud_kms_key_editor = string }) default = { organization_iam_admin = "organizationIamAdmin" service_project_network_admin = "serviceProjectNetworkAdmin" - cloud_kms_key_role_editor = "cloudKmsKeyAdmin" + cloud_kms_key_editor = "cloudKmsKeyAdmin" } } diff --git a/fast/stages/02-security/README.md b/fast/stages/02-security/README.md index 5847cba3..a1b21445 100644 --- a/fast/stages/02-security/README.md +++ b/fast/stages/02-security/README.md @@ -292,7 +292,7 @@ Some references that might be useful in setting up this stage: | [organization](variables.tf#L100) | Organization details. | object({…}) | ✓ | | 00-bootstrap | | [prefix](variables.tf#L116) | Prefix used for resources that need unique names. Use 9 characters or less. | string | ✓ | | 00-bootstrap | | [service_accounts](variables.tf#L89) | Automation service accounts that can assign the encrypt/decrypt roles on keys. | object({…}) | ✓ | | 01-resman | -| [custom_roles](variables.tf#L34) | Custom roles defined at the org level, in key => id format. | object({…}) | | null | 00-bootstrap | +| [custom_roles](variables.tf#L34) | Custom roles defined at the org level, in key => id format. | object({…}) | | null | 00-bootstrap | | [groups](variables.tf#L51) | Group names to grant organization-level permissions. | map(string) | | {…} | 00-bootstrap | | [kms_defaults](variables.tf#L66) | Defaults used for KMS keys. | object({…}) | | {…} | | | [kms_keys](variables.tf#L78) | KMS keys to create, keyed by name. Null attributes will be interpolated with defaults. | map(object({…})) | | {} | | diff --git a/fast/stages/02-security/core-dev.tf b/fast/stages/02-security/core-dev.tf index 9cc7b917..75bde41c 100644 --- a/fast/stages/02-security/core-dev.tf +++ b/fast/stages/02-security/core-dev.tf @@ -27,8 +27,8 @@ module "dev-sec-project" { prefix = var.prefix billing_account = var.billing_account.id iam = { - (local.custom_roles.cloud_kms_key_role_editor) = ["serviceAccount:${var.service_accounts.data-platform-dev}"] - "roles/cloudkms.viewer" = local.dev_kms_restricted_admins + (local.custom_roles.cloud_kms_key_editor) = ["serviceAccount:${var.service_accounts.data-platform-dev}"] + "roles/cloudkms.viewer" = local.dev_kms_restricted_admins } labels = { environment = "dev", team = "security" } services = local.project_services diff --git a/fast/stages/02-security/core-prod.tf b/fast/stages/02-security/core-prod.tf index 9456cbb4..83802636 100644 --- a/fast/stages/02-security/core-prod.tf +++ b/fast/stages/02-security/core-prod.tf @@ -27,8 +27,8 @@ module "prod-sec-project" { prefix = var.prefix billing_account = var.billing_account.id iam = { - (local.custom_roles.cloud_kms_key_role_editor) = ["serviceAccount:${var.service_accounts.data-platform-prod}"] - "roles/cloudkms.viewer" = local.prod_kms_restricted_admins + (local.custom_roles.cloud_kms_key_editor) = ["serviceAccount:${var.service_accounts.data-platform-prod}"] + "roles/cloudkms.viewer" = local.prod_kms_restricted_admins } labels = { environment = "prod", team = "security" } services = local.project_services diff --git a/fast/stages/02-security/variables.tf b/fast/stages/02-security/variables.tf index 4276b4d2..3ec80f7e 100644 --- a/fast/stages/02-security/variables.tf +++ b/fast/stages/02-security/variables.tf @@ -35,7 +35,7 @@ variable "custom_roles" { # tfdoc:variable:source 00-bootstrap description = "Custom roles defined at the org level, in key => id format." type = object({ - cloud_kms_key_role_editor = string + cloud_kms_key_editor = string }) default = null } From bcfa324825ebd2d7daa77c3be3f0dfcb5c5b46eb Mon Sep 17 00:00:00 2001 From: Lorenzo Caggioni Date: Mon, 20 Jun 2022 22:39:29 +0200 Subject: [PATCH 6/8] Fix test --- tests/fast/stages/s02_security/fixture/main.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/fast/stages/s02_security/fixture/main.tf b/tests/fast/stages/s02_security/fixture/main.tf index fd65319e..fe22c292 100644 --- a/tests/fast/stages/s02_security/fixture/main.tf +++ b/tests/fast/stages/s02_security/fixture/main.tf @@ -24,7 +24,7 @@ module "stage" { organization_id = 123456789012 } custom_roles = { - cloud_kms_key_role_editor = "cloudKmsKeyAdmin" + cloud_kms_key_editor = "cloudKmsKeyAdmin" } folder_ids = { security = null From ceb611bb819cced9f35ee19031584197caafddd1 Mon Sep 17 00:00:00 2001 From: Lorenzo Caggioni Date: Thu, 23 Jun 2022 07:04:35 +0200 Subject: [PATCH 7/8] Remove custom role and rely on conditions. --- fast/stages/00-bootstrap/README.md | 4 +-- fast/stages/00-bootstrap/organization.tf | 6 ---- fast/stages/00-bootstrap/variables.tf | 2 -- fast/stages/02-security/README.md | 31 +++++++++---------- fast/stages/02-security/core-dev.tf | 9 +++--- fast/stages/02-security/core-prod.tf | 8 ++--- fast/stages/02-security/main.tf | 1 - fast/stages/02-security/variables.tf | 9 ------ fast/stages/03-data-platform/dev/README.md | 19 ++++++------ .../fast/stages/s02_security/fixture/main.tf | 3 -- 10 files changed, 35 insertions(+), 57 deletions(-) diff --git a/fast/stages/00-bootstrap/README.md b/fast/stages/00-bootstrap/README.md index 7280a34b..93bb47cc 100644 --- a/fast/stages/00-bootstrap/README.md +++ b/fast/stages/00-bootstrap/README.md @@ -371,7 +371,7 @@ federated_identity_providers = { custom_settings = { issuer_uri = "https://gitlab.fast.example.com" allowed_audiences = ["https://gitlab.fast.example.com"] - } + } } } ``` @@ -397,7 +397,7 @@ cicd_repositories = { identity_provider = "github-sample" name = "my-gh-org/fast-cicd" type = "github" - } + } resman = { branch = "main" identity_provider = "github-sample" diff --git a/fast/stages/00-bootstrap/organization.tf b/fast/stages/00-bootstrap/organization.tf index e18a1f13..ea7c2e58 100644 --- a/fast/stages/00-bootstrap/organization.tf +++ b/fast/stages/00-bootstrap/organization.tf @@ -171,12 +171,6 @@ module "organization" { "dns.networks.bindPrivateDNSZone", "resourcemanager.projects.get", ] - (var.custom_role_names.cloud_kms_key_editor) = [ - "cloudkms.cryptoKeys.get", - "cloudkms.cryptoKeys.list", - "cloudkms.cryptoKeys.getIamPolicy", - "cloudkms.cryptoKeys.setIamPolicy" - ] } logging_sinks = { for name, attrs in var.log_sinks : name => { diff --git a/fast/stages/00-bootstrap/variables.tf b/fast/stages/00-bootstrap/variables.tf index 25ee77a4..f2f1edcd 100644 --- a/fast/stages/00-bootstrap/variables.tf +++ b/fast/stages/00-bootstrap/variables.tf @@ -85,12 +85,10 @@ variable "custom_role_names" { type = object({ organization_iam_admin = string service_project_network_admin = string - cloud_kms_key_editor = string }) default = { organization_iam_admin = "organizationIamAdmin" service_project_network_admin = "serviceProjectNetworkAdmin" - cloud_kms_key_editor = "cloudKmsKeyAdmin" } } diff --git a/fast/stages/02-security/README.md b/fast/stages/02-security/README.md index a1b21445..e61918bb 100644 --- a/fast/stages/02-security/README.md +++ b/fast/stages/02-security/README.md @@ -288,22 +288,21 @@ Some references that might be useful in setting up this stage: |---|---|:---:|:---:|:---:|:---:| | [automation](variables.tf#L17) | Automation resources created by the bootstrap stage. | object({…}) | ✓ | | 00-bootstrap | | [billing_account](variables.tf#L25) | Billing account id and organization id ('nnnnnnnn' or null). | object({…}) | ✓ | | 00-bootstrap | -| [folder_ids](variables.tf#L43) | Folder name => id mappings, the 'security' folder name must exist. | object({…}) | ✓ | | 01-resman | -| [organization](variables.tf#L100) | Organization details. | object({…}) | ✓ | | 00-bootstrap | -| [prefix](variables.tf#L116) | Prefix used for resources that need unique names. Use 9 characters or less. | string | ✓ | | 00-bootstrap | -| [service_accounts](variables.tf#L89) | Automation service accounts that can assign the encrypt/decrypt roles on keys. | object({…}) | ✓ | | 01-resman | -| [custom_roles](variables.tf#L34) | Custom roles defined at the org level, in key => id format. | object({…}) | | null | 00-bootstrap | -| [groups](variables.tf#L51) | Group names to grant organization-level permissions. | map(string) | | {…} | 00-bootstrap | -| [kms_defaults](variables.tf#L66) | Defaults used for KMS keys. | object({…}) | | {…} | | -| [kms_keys](variables.tf#L78) | KMS keys to create, keyed by name. Null attributes will be interpolated with defaults. | map(object({…})) | | {} | | -| [outputs_location](variables.tf#L110) | Path where providers, tfvars files, and lists for the following stages are written. Leave empty to disable. | string | | null | | -| [vpc_sc_access_levels](variables.tf#L127) | VPC SC access level definitions. | map(object({…})) | | {} | | -| [vpc_sc_egress_policies](variables.tf#L142) | VPC SC egress policy defnitions. | map(object({…})) | | {} | | -| [vpc_sc_ingress_policies](variables.tf#L160) | VPC SC ingress policy defnitions. | map(object({…})) | | {} | | -| [vpc_sc_perimeter_access_levels](variables.tf#L180) | VPC SC perimeter access_levels. | object({…}) | | null | | -| [vpc_sc_perimeter_egress_policies](variables.tf#L190) | VPC SC egress policies per perimeter, values reference keys defined in the `vpc_sc_ingress_policies` variable. | object({…}) | | null | | -| [vpc_sc_perimeter_ingress_policies](variables.tf#L200) | VPC SC ingress policies per perimeter, values reference keys defined in the `vpc_sc_ingress_policies` variable. | object({…}) | | null | | -| [vpc_sc_perimeter_projects](variables.tf#L210) | VPC SC perimeter resources. | object({…}) | | null | | +| [folder_ids](variables.tf#L34) | Folder name => id mappings, the 'security' folder name must exist. | object({…}) | ✓ | | 01-resman | +| [organization](variables.tf#L91) | Organization details. | object({…}) | ✓ | | 00-bootstrap | +| [prefix](variables.tf#L107) | Prefix used for resources that need unique names. Use 9 characters or less. | string | ✓ | | 00-bootstrap | +| [service_accounts](variables.tf#L80) | Automation service accounts that can assign the encrypt/decrypt roles on keys. | object({…}) | ✓ | | 01-resman | +| [groups](variables.tf#L42) | Group names to grant organization-level permissions. | map(string) | | {…} | 00-bootstrap | +| [kms_defaults](variables.tf#L57) | Defaults used for KMS keys. | object({…}) | | {…} | | +| [kms_keys](variables.tf#L69) | KMS keys to create, keyed by name. Null attributes will be interpolated with defaults. | map(object({…})) | | {} | | +| [outputs_location](variables.tf#L101) | Path where providers, tfvars files, and lists for the following stages are written. Leave empty to disable. | string | | null | | +| [vpc_sc_access_levels](variables.tf#L118) | VPC SC access level definitions. | map(object({…})) | | {} | | +| [vpc_sc_egress_policies](variables.tf#L133) | VPC SC egress policy defnitions. | map(object({…})) | | {} | | +| [vpc_sc_ingress_policies](variables.tf#L151) | VPC SC ingress policy defnitions. | map(object({…})) | | {} | | +| [vpc_sc_perimeter_access_levels](variables.tf#L171) | VPC SC perimeter access_levels. | object({…}) | | null | | +| [vpc_sc_perimeter_egress_policies](variables.tf#L181) | VPC SC egress policies per perimeter, values reference keys defined in the `vpc_sc_ingress_policies` variable. | object({…}) | | null | | +| [vpc_sc_perimeter_ingress_policies](variables.tf#L191) | VPC SC ingress policies per perimeter, values reference keys defined in the `vpc_sc_ingress_policies` variable. | object({…}) | | null | | +| [vpc_sc_perimeter_projects](variables.tf#L201) | VPC SC perimeter resources. | object({…}) | | null | | ## Outputs diff --git a/fast/stages/02-security/core-dev.tf b/fast/stages/02-security/core-dev.tf index 75bde41c..b917a5cc 100644 --- a/fast/stages/02-security/core-dev.tf +++ b/fast/stages/02-security/core-dev.tf @@ -16,7 +16,8 @@ locals { dev_kms_restricted_admins = [ - "serviceAccount:${var.service_accounts.project-factory-dev}" + "serviceAccount:${var.service_accounts.project-factory-dev}", + "serviceAccount:${var.service_accounts.data-platform-dev}" ] } @@ -27,8 +28,7 @@ module "dev-sec-project" { prefix = var.prefix billing_account = var.billing_account.id iam = { - (local.custom_roles.cloud_kms_key_editor) = ["serviceAccount:${var.service_accounts.data-platform-dev}"] - "roles/cloudkms.viewer" = local.dev_kms_restricted_admins + "roles/cloudkms.viewer" = local.dev_kms_restricted_admins } labels = { environment = "dev", team = "security" } services = local.project_services @@ -50,7 +50,6 @@ module "dev-sec-kms" { } # TODO(ludo): add support for conditions to Fabric modules -# TODO(ludo): grant delegated role at key instead of project level resource "google_project_iam_member" "dev_key_admin_delegated" { for_each = toset(local.dev_kms_restricted_admins) @@ -61,7 +60,7 @@ resource "google_project_iam_member" "dev_key_admin_delegated" { title = "kms_sa_delegated_grants" description = "Automation service account delegated grants." expression = format( - "api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly([%s])", + "api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly([%s]) && resource.type == 'cloudkms.googleapis.com/CryptoKey'", join(",", formatlist("'%s'", [ "roles/cloudkms.cryptoKeyEncrypterDecrypter", "roles/cloudkms.cryptoKeyEncrypterDecrypterViaDelegation" diff --git a/fast/stages/02-security/core-prod.tf b/fast/stages/02-security/core-prod.tf index 83802636..f792671f 100644 --- a/fast/stages/02-security/core-prod.tf +++ b/fast/stages/02-security/core-prod.tf @@ -16,7 +16,8 @@ locals { prod_kms_restricted_admins = [ - "serviceAccount:${var.service_accounts.project-factory-prod}" + "serviceAccount:${var.service_accounts.project-factory-prod}", + "serviceAccount:${var.service_accounts.data-platform-prod}" ] } @@ -27,8 +28,7 @@ module "prod-sec-project" { prefix = var.prefix billing_account = var.billing_account.id iam = { - (local.custom_roles.cloud_kms_key_editor) = ["serviceAccount:${var.service_accounts.data-platform-prod}"] - "roles/cloudkms.viewer" = local.prod_kms_restricted_admins + "roles/cloudkms.viewer" = local.prod_kms_restricted_admins } labels = { environment = "prod", team = "security" } services = local.project_services @@ -60,7 +60,7 @@ resource "google_project_iam_member" "prod_key_admin_delegated" { title = "kms_sa_delegated_grants" description = "Automation service account delegated grants." expression = format( - "api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly([%s])", + "api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly([%s]) && resource.type == 'cloudkms.googleapis.com/CryptoKey'", join(",", formatlist("'%s'", [ "roles/cloudkms.cryptoKeyEncrypterDecrypter", "roles/cloudkms.cryptoKeyEncrypterDecrypterViaDelegation" diff --git a/fast/stages/02-security/main.tf b/fast/stages/02-security/main.tf index c1e1aa0f..13078d12 100644 --- a/fast/stages/02-security/main.tf +++ b/fast/stages/02-security/main.tf @@ -15,7 +15,6 @@ */ locals { - custom_roles = coalesce(var.custom_roles, {}) kms_keys = { for k, v in var.kms_keys : k => { iam = coalesce(v.iam, {}) diff --git a/fast/stages/02-security/variables.tf b/fast/stages/02-security/variables.tf index 3ec80f7e..ff0edc77 100644 --- a/fast/stages/02-security/variables.tf +++ b/fast/stages/02-security/variables.tf @@ -31,15 +31,6 @@ variable "billing_account" { }) } -variable "custom_roles" { - # tfdoc:variable:source 00-bootstrap - description = "Custom roles defined at the org level, in key => id format." - type = object({ - cloud_kms_key_editor = string - }) - default = null -} - variable "folder_ids" { # tfdoc:variable:source 01-resman description = "Folder name => id mappings, the 'security' folder name must exist." diff --git a/fast/stages/03-data-platform/dev/README.md b/fast/stages/03-data-platform/dev/README.md index 9174ae6e..d62a1c00 100644 --- a/fast/stages/03-data-platform/dev/README.md +++ b/fast/stages/03-data-platform/dev/README.md @@ -170,19 +170,20 @@ You can find examples in the `[demo](../../../../examples/data-solutions/data-pl | [billing_account](variables.tf#L25) | Billing account id and organization id ('nnnnnnnn' or null). | object({…}) | ✓ | | 00-globals | | [folder_ids](variables.tf#L64) | Folder to be used for the networking resources in folders/nnnn format. | object({…}) | ✓ | | 01-resman | | [host_project_ids](variables.tf#L82) | Shared VPC project ids. | object({…}) | ✓ | | 02-networking | -| [organization](variables.tf#L108) | Organization details. | object({…}) | ✓ | | 00-globals | -| [prefix](variables.tf#L124) | Unique prefix used for resource names. Not used for projects if 'project_create' is null. | string | ✓ | | 00-globals | +| [organization](variables.tf#L114) | Organization details. | object({…}) | ✓ | | 00-globals | +| [prefix](variables.tf#L130) | Unique prefix used for resource names. Not used for projects if 'project_create' is null. | string | ✓ | | 00-globals | | [composer_config](variables.tf#L34) | | object({…}) | | {…} | | | [data_catalog_tags](variables.tf#L47) | List of Data Catalog Policy tags to be created with optional IAM binging configuration in {tag => {ROLE => [MEMBERS]}} format. | map(map(list(string))) | | {…} | | | [data_force_destroy](variables.tf#L58) | Flag to set 'force_destroy' on data services like BigQery or Cloud Storage. | bool | | false | | | [groups](variables.tf#L72) | Groups. | map(string) | | {…} | | -| [network_config_composer](variables.tf#L90) | Network configurations to use for Composer. | object({…}) | | {…} | | -| [outputs_location](variables.tf#L118) | Path where providers, tfvars files, and lists for the following stages are written. Leave empty to disable. | string | | null | | -| [project_services](variables.tf#L130) | List of core services enabled on all projects. | list(string) | | […] | | -| [region](variables.tf#L141) | Region used for regional resources. | string | | "europe-west1" | | -| [service_encryption_keys](variables.tf#L147) | Cloud KMS to use to encrypt different services. Key location should match service region. | object({…}) | | null | | -| [subnet_self_links](variables.tf#L159) | Shared VPC subnet self links. | object({…}) | | null | 02-networking | -| [vpc_self_links](variables.tf#L168) | Shared VPC self links. | object({…}) | | null | 02-networking | +| [location](variables.tf#L90) | Location used for multi-regional resources. | string | | "eu" | | +| [network_config_composer](variables.tf#L96) | Network configurations to use for Composer. | object({…}) | | {…} | | +| [outputs_location](variables.tf#L124) | Path where providers, tfvars files, and lists for the following stages are written. Leave empty to disable. | string | | null | | +| [project_services](variables.tf#L136) | List of core services enabled on all projects. | list(string) | | […] | | +| [region](variables.tf#L147) | Region used for regional resources. | string | | "europe-west1" | | +| [service_encryption_keys](variables.tf#L153) | Cloud KMS to use to encrypt different services. Key location should match service region. | object({…}) | | null | | +| [subnet_self_links](variables.tf#L165) | Shared VPC subnet self links. | object({…}) | | null | 02-networking | +| [vpc_self_links](variables.tf#L174) | Shared VPC self links. | object({…}) | | null | 02-networking | ## Outputs diff --git a/tests/fast/stages/s02_security/fixture/main.tf b/tests/fast/stages/s02_security/fixture/main.tf index fe22c292..67173eb8 100644 --- a/tests/fast/stages/s02_security/fixture/main.tf +++ b/tests/fast/stages/s02_security/fixture/main.tf @@ -23,9 +23,6 @@ module "stage" { id = "000000-111111-222222" organization_id = 123456789012 } - custom_roles = { - cloud_kms_key_editor = "cloudKmsKeyAdmin" - } folder_ids = { security = null } From b10d091a9836730932bbbe1b82ee881cf7e4906b Mon Sep 17 00:00:00 2001 From: Lorenzo Caggioni Date: Thu, 23 Jun 2022 07:16:59 +0200 Subject: [PATCH 8/8] Fix README --- fast/stages/00-bootstrap/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fast/stages/00-bootstrap/README.md b/fast/stages/00-bootstrap/README.md index 93bb47cc..7280a34b 100644 --- a/fast/stages/00-bootstrap/README.md +++ b/fast/stages/00-bootstrap/README.md @@ -371,7 +371,7 @@ federated_identity_providers = { custom_settings = { issuer_uri = "https://gitlab.fast.example.com" allowed_audiences = ["https://gitlab.fast.example.com"] - } + } } } ``` @@ -397,7 +397,7 @@ cicd_repositories = { identity_provider = "github-sample" name = "my-gh-org/fast-cicd" type = "github" - } + } resman = { branch = "main" identity_provider = "github-sample"