diff --git a/foundations/business-units/README.md b/foundations/business-units/README.md index 684579bc06..70c2297cb5 100644 --- a/foundations/business-units/README.md +++ b/foundations/business-units/README.md @@ -19,7 +19,7 @@ This sample creates several distinct groups of resources: - one project in the shared folder to set up and host centralized audit log exports - one project in the shared folder to hold services used across environments like GCS, GCR, KMS, Cloud Build, etc. -The number of resources in this sample is kept to a minimum so as to make it generally applicable, more resources can be easily added by leveraging the full array of [Cloud Foundation Toolkit modules](https://github.com/terraform-google-modules), especially in the shared services project. +The number of resources in this sample is kept to a minimum so as to make it generally applicable, more resources can be easily added by leveraging other [modules from our bundle](../../modules/), or from other sources like the [CFT suite](https://github.com/terraform-google-modules). ## Shared services @@ -31,37 +31,34 @@ This sample uses a top-level folder to encapsulate projects that host resources | name | description | type | required | default | |---|---|:---: |:---:|:---:| | billing_account_id | Billing account id used as default for new projects. | string | ✓ | | -| business_unit_1_name | Business unit 1 short name. | string | ✓ | | -| business_unit_2_name | Business unit 2 short name. | string | ✓ | | -| business_unit_3_name | Business unit 3 short name. | string | ✓ | | -| environments | Environment short names. | list(string) | ✓ | | | organization_id | Organization id. | string | ✓ | | | prefix | Prefix used for resources that need unique names. | string | ✓ | | | root_node | Root node for the new hierarchy, either 'organizations/org_id' or 'folders/folder_id'. | string | ✓ | | -| *audit_viewers* | Audit project viewers, in IAM format. | list(string) | | [] | -| *gcs_location* | GCS bucket location. | string | | EU | +| *audit_filter* | Audit log filter used for the log sink. | string | | ... | +| *business_unit_bi* | Business unit BI configuration. | object({...}) | | ... | +| *business_unit_ml* | Business unit ML configuration. | object({...}) | | ... | +| *environments* | Environment short names. | map(string) | | ... | +| *gcs_defaults* | Defaults use for the state GCS buckets. | map(string) | | ... | | *generate_service_account_keys* | Generate and store service account keys in the state file. | bool | | false | +| *iam_audit_viewers* | Audit project viewers, in IAM format. | list(string) | | [] | +| *iam_billing_config* | Control granting billing user role to service accounts. Target the billing account by default. | object({...}) | | ... | +| *iam_shared_owners* | Shared services project owners, in IAM format. | list(string) | | [] | +| *iam_terraform_owners* | Terraform project owners, in IAM format. | list(string) | | [] | +| *iam_xpn_config* | Control granting Shared VPC creation roles to service accounts. Target the root node by default. | object({...}) | | ... | | *project_services* | Service APIs enabled by default in new projects. | list(string) | | ... | -| *shared_bindings_members* | List of comma-delimited IAM-format members for the additional shared project bindings. | list(string) | | [] | -| *shared_bindings_roles* | List of roles for additional shared project bindings. | list(string) | | [] | +| *service_account_keys* | Generate and store service account keys in the state file. | bool | | false | | *terraform_owners* | Terraform project owners, in IAM format. | list(string) | | [] | ## Outputs | name | description | sensitive | |---|---|:---:| -| audit_logs_bq_dataset | Bigquery dataset for the audit logs export. | | | audit_logs_project | Project that holds the audit logs export resources. | | | bootstrap_tf_gcs_bucket | GCS bucket used for the bootstrap Terraform state. | | -| business_unit_1_environment_folders_ids | Business unit 1 environment folders. | | -| business_unit_1_folder_id | Business unit 1 top-level folder ID. | | -| business_unit_2_environment_folders_ids | Business unit 2 environment folders. | | -| business_unit_2_folder_id | Business unit 2 top-level folder ID. | | -| business_unit_3_environment_folders_ids | Business unit 3 environment folders. | | -| business_unit_3_folder_id | Business unit 3 top-level folder ID. | | -| environment_service_account_keys | Service account keys used to run each environment Terraform modules. | ✓ | -| environment_service_accounts | Service accounts used to run each environment Terraform modules. | | -| environment_tf_gcs_buckets | GCS buckets used for each environment Terraform state. | | +| bu_bi | Business Unit BI attributes. | | +| bu_bi_sa_keys | Business Unit BI Service Accoutns keys. | ✓ | +| bu_ml | Business Unit ML attributes. | | +| bu_ml_sa_keys | Business Unit ML Service Accoutns keys. | ✓ | | shared_folder_id | Shared folder ID. | | | shared_resources_project | Project that holdes resources shared across business units. | | | terraform_project | Project that holds the base Terraform resources. | | diff --git a/foundations/business-units/main.tf b/foundations/business-units/main.tf index ea61923130..ec342cfd3a 100644 --- a/foundations/business-units/main.tf +++ b/foundations/business-units/main.tf @@ -1,18 +1,18 @@ -# Copyright 2019 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. - -# TODO(averbukh): simplify log-sink parameters once https://github.com/terraform-google-modules/terraform-google-log-export/issues/28 is done. +/** + * Copyright 2020 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. + */ locals { parent_numeric_id = element(split("/", var.root_node), 1) @@ -37,14 +37,14 @@ module "shared-folder" { # Terraform project module "tf-project" { - source = "../../modules/project" - name = "terraform" - parent = module.shared-folder.id - prefix = var.prefix - billing_account = var.billing_account_id - iam_nonauth_members = { "roles/owner" = var.iam_terraform_owners } - iam_nonauth_roles = ["roles/owner"] - services = var.project_services + source = "../../modules/project" + name = "terraform" + parent = module.shared-folder.id + prefix = var.prefix + billing_account = var.billing_account_id + iam_additive_members = { "roles/owner" = var.iam_terraform_owners } + iam_additive_roles = ["roles/owner"] + services = var.project_services } # Bootstrap Terraform state GCS bucket @@ -73,11 +73,13 @@ module "busines-unit-bi" { gcs_defaults = var.gcs_defaults iam_roles = var.business_unit_bi.iam_roles iam_members = var.business_unit_bi.iam_members + iam_xpn_config = var.iam_xpn_config + iam_billing_config = var.iam_billing_config organization_id = var.organization_id - parent = var.root_node + root_node = var.root_node prefix = var.prefix environments = var.environments - generate_keys = var.generate_keys + service_account_keys = var.service_account_keys } # Business unit ML @@ -92,11 +94,13 @@ module "busines-unit-ml" { gcs_defaults = var.gcs_defaults iam_roles = var.business_unit_ml.iam_roles iam_members = var.business_unit_ml.iam_members + iam_xpn_config = var.iam_xpn_config + iam_billing_config = var.iam_billing_config organization_id = var.organization_id - parent = var.root_node + root_node = var.root_node prefix = var.prefix environments = var.environments - generate_keys = var.generate_keys + service_account_keys = var.service_account_keys } ############################################################################### @@ -163,10 +167,10 @@ module "shared-project" { parent = module.shared-folder.id prefix = var.prefix billing_account = var.billing_account_id - iam_members = { + iam_additive_members = { "roles/owner" = var.iam_shared_owners } - iam_roles = [ + iam_additive_roles = [ "roles/owner" ] services = var.project_services diff --git a/foundations/business-units/outputs.tf b/foundations/business-units/outputs.tf index a1174a1876..e2e16a4b12 100644 --- a/foundations/business-units/outputs.tf +++ b/foundations/business-units/outputs.tf @@ -1,16 +1,18 @@ -# Copyright 2019 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. +/** + * Copyright 2020 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. + */ output "terraform_project" { description = "Project that holds the base Terraform resources." @@ -29,24 +31,34 @@ output "shared_folder_id" { output "bu_ml" { description = "Business Unit ML attributes." - value = module.busines-unit-ml.unit + value = { + unit_folder = module.busines-unit-ml.unit_folder, + env_gcs_buckets = module.busines-unit-ml.env_gcs_buckets + env_folders = module.busines-unit-ml.env_folders + env_service_accounts = module.busines-unit-ml.env_service_accounts + } } output "bu_ml_sa_keys" { description = "Business Unit ML Service Accoutns keys." - sensitive = true - value = module.busines-unit-ml.keys + sensitive = true + value = module.busines-unit-ml.env_sa_keys } output "bu_bi" { description = "Business Unit BI attributes." - value = module.busines-unit-bi.unit + value = { + unit_folder = module.busines-unit-bi.unit_folder, + env_gcs_buckets = module.busines-unit-bi.env_gcs_buckets + env_folders = module.busines-unit-bi.env_folders + env_service_accounts = module.busines-unit-bi.env_service_accounts + } } output "bu_bi_sa_keys" { description = "Business Unit BI Service Accoutns keys." - sensitive = true - value = module.busines-unit-bi.keys + sensitive = true + value = module.busines-unit-bi.env_sa_keys } output "audit_logs_project" { @@ -60,4 +72,4 @@ output "shared_resources_project" { } # Add further outputs here for the additional modules that manage shared -# resources, like GCR, GCS buckets, KMS, etc. \ No newline at end of file +# resources, like GCR, GCS buckets, KMS, etc. diff --git a/foundations/business-units/providers.tf b/foundations/business-units/providers.tf index b166f75dc4..d57e94c5de 100644 --- a/foundations/business-units/providers.tf +++ b/foundations/business-units/providers.tf @@ -1,15 +1,17 @@ -# Copyright 2019 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. +/** + * Copyright 2020 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. + */ -provider "google" {} \ No newline at end of file +provider "google" {} diff --git a/foundations/business-units/terraform.tfvars.sample b/foundations/business-units/terraform.tfvars.sample new file mode 100644 index 0000000000..2d05f977ae --- /dev/null +++ b/foundations/business-units/terraform.tfvars.sample @@ -0,0 +1,19 @@ +# Copyright 2019 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. + +billing_account_id = "014617-19UCBC-AF02D9" +organization_id= "500001140800" +prefix = "xyz" +root_node = "folders/9572793983696" +generate_keys = true diff --git a/foundations/business-units/variables.tf b/foundations/business-units/variables.tf index 63dda9b4aa..0a3e3e06d4 100644 --- a/foundations/business-units/variables.tf +++ b/foundations/business-units/variables.tf @@ -1,16 +1,18 @@ -# Copyright 2019 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. +/** + * Copyright 2020 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 "audit_filter" { description = "Audit log filter used for the log sink." @@ -84,8 +86,8 @@ variable "environments" { description = "Environment short names." type = map(string) default = { - dev = "Development", - test = "Testing", + dev = "Development", + test = "Testing", prod = "Production" } } @@ -147,8 +149,32 @@ variable "iam_terraform_owners" { default = [] } -variable "generate_keys" { - description = "Generate keys for service accounts." +variable "service_account_keys" { + description = "Generate and store service account keys in the state file." type = bool default = false } + +variable "iam_xpn_config" { + description = "Control granting Shared VPC creation roles to service accounts. Target the root node by default." + type = object({ + grant = bool + target_org = bool + }) + default = { + grant = true + target_org = false + } +} + +variable "iam_billing_config" { + description = "Control granting billing user role to service accounts. Target the billing account by default." + type = object({ + grant = bool + target_org = bool + }) + default = { + grant = true + target_org = false + } +} diff --git a/foundations/business-units/versions.tf b/foundations/business-units/versions.tf index 4eb1500c5a..bc4c2a9d71 100644 --- a/foundations/business-units/versions.tf +++ b/foundations/business-units/versions.tf @@ -1,17 +1,19 @@ -# Copyright 2019 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. +/** + * Copyright 2020 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. + */ terraform { - required_version = ">= 0.12" + required_version = ">= 0.12.6" } diff --git a/foundations/environments/README.md b/foundations/environments/README.md index 3e13134f20..f3451777a5 100644 --- a/foundations/environments/README.md +++ b/foundations/environments/README.md @@ -17,7 +17,7 @@ This sample creates several distinct groups of resources: - one top-level project to set up and host centralized audit log exports (optional) - one top-level shared services project -The number of resources in this sample is kept to a minimum so as to make it more generally applicable, further resources can be easily added by leveraging the full array of [Cloud Foundation Toolkit modules](https://github.com/terraform-google-modules), especially in the shared services project. +The number of resources in this sample is kept to a minimum so as to make it generally applicable, more resources can be easily added by leveraging other [modules from our bundle](../../modules/), or from other sources like the [CFT suite](https://github.com/terraform-google-modules). ## Shared services project @@ -32,20 +32,23 @@ If no shared services are needed, the shared service project module can of cours | name | description | type | required | default | |---|---|:---: |:---:|:---:| -| billing_account_id | Billing account id used as default for new projects. | string | ✓ | | +| billing_account_id | Billing account id used as to create projects. | string | ✓ | | | environments | Environment short names. | list(string) | ✓ | | -| organization_id | Organization id. | string | ✓ | | | prefix | Prefix used for resources that need unique names. | string | ✓ | | | root_node | Root node for the new hierarchy, either 'organizations/org_id' or 'folders/folder_id'. | string | ✓ | | -| *audit_viewers* | Audit project viewers, in IAM format. | list(string) | | [] | +| *audit_filter* | Audit log filter used for the log sink. | string | | ... | | *gcs_location* | GCS bucket location. | string | | EU | -| *generate_service_account_keys* | Generate and store service account keys in the state file. | bool | | false | -| *grant_xpn_folder_roles* | Grant roles needed for Shared VPC creation to service accounts at the environment folder level. | bool | | true | -| *grant_xpn_org_roles* | Grant roles needed for Shared VPC creation to service accounts at the organization level. | bool | | false | +| *iam_assets_editors* | Shared assets project editors, in IAM format. | list(string) | | [] | +| *iam_assets_owners* | Shared assets project owners, in IAM format. | list(string) | | [] | +| *iam_audit_viewers* | Audit project viewers, in IAM format. | list(string) | | [] | +| *iam_billing_config* | Control granting billing user role to service accounts. Target the billing account by default. | object({...}) | | ... | +| *iam_folder_roles* | List of roles granted to each service account on its respective folder (excluding XPN roles). | list(string) | | ... | +| *iam_sharedsvc_owners* | Shared services project owners, in IAM format. | list(string) | | [] | +| *iam_terraform_owners* | Terraform project owners, in IAM format. | list(string) | | [] | +| *iam_xpn_config* | Control granting Shared VPC creation roles to service accounts. Target the root node by default. | object({...}) | | ... | +| *organization_id* | Organization id. | string | | null | | *project_services* | Service APIs enabled by default in new projects. | list(string) | | ... | -| *shared_bindings_members* | List of comma-delimited IAM-format members for the additional shared project bindings. | list(string) | | [] | -| *shared_bindings_roles* | List of roles for additional shared project bindings. | list(string) | | [] | -| *terraform_owners* | Terraform project owners, in IAM format. | list(string) | | [] | +| *service_account_keys* | Generate and store service account keys in the state file. | bool | | true | ## Outputs @@ -59,5 +62,4 @@ If no shared services are needed, the shared service project module can of cours | environment_service_accounts | Service accounts used to run each environment Terraform modules. | | | environment_tf_gcs_buckets | GCS buckets used for each environment Terraform state. | | | shared_resources_project | Project that holdes resources shared across environments. | | -| terraform_project | Project that holds the base Terraform resources. | | diff --git a/foundations/environments/main.tf b/foundations/environments/main.tf index 6332e34596..754b461a0e 100644 --- a/foundations/environments/main.tf +++ b/foundations/environments/main.tf @@ -19,14 +19,14 @@ # Terraform project module "tf-project" { - source = "../../modules/project" - name = "terraform" - parent = var.root_node - prefix = var.prefix - billing_account = var.billing_account_id - iam_nonauth_members = { "roles/owner" = var.iam_terraform_owners } - iam_nonauth_roles = ["roles/owner"] - services = var.project_services + source = "../../modules/project" + name = "terraform" + parent = var.root_node + prefix = var.prefix + billing_account = var.billing_account_id + iam_additive_members = { "roles/owner" = var.iam_terraform_owners } + iam_additive_roles = ["roles/owner"] + services = var.project_services } # per-environment service accounts @@ -163,10 +163,10 @@ module "sharedsvc-project" { parent = var.root_node prefix = var.prefix billing_account = var.billing_account_id - iam_members = { + iam_additive_members = { "roles/owner" = var.iam_sharedsvc_owners } - iam_roles = [ + iam_additive_roles = [ "roles/owner" ] services = var.project_services diff --git a/foundations/environments/variables.tf b/foundations/environments/variables.tf index f84890a21e..6bdafadf03 100644 --- a/foundations/environments/variables.tf +++ b/foundations/environments/variables.tf @@ -95,7 +95,7 @@ variable "iam_xpn_config" { description = "Control granting Shared VPC creation roles to service accounts. Target the root node by default." type = object({ grant = bool - target_org = string + target_org = bool }) default = { grant = true diff --git a/modules/folders-unit/README.md b/modules/folders-unit/README.md index 48edcfbaf8..2524653884 100644 --- a/modules/folders-unit/README.md +++ b/modules/folders-unit/README.md @@ -1,23 +1,26 @@ # Google Cloud Unit Folders Module -This module allow creation and management of sets of folders (environments) and a common parent (unit), and their environment specific Service Accounts, IAM bindings, GCS buckets. +This module allow creation and management of a set of folders (environments) and a common parent folder (unit), their environment specific Service Accounts, IAM bindings, GCS buckets. ## Example ```hcl -module "folder" { - source = "./modules/folders-ubit" - parent = "organizations/1234567890" - name = "Magic Unit" - environments = ["dev", "test", "prod"] - iam_members = { - "Folder one" = { - "roles/owner" => ["group:users@example.com"] - } - } - iam_roles = { - "Folder one" = ["roles/owner"] +module "folders-unit" { + source = "../../modules/folders-unit" + + name = "Business Intelligence" + short_name = "bi" + automation_project_id = "automation-project-394yr923811" + billing_account_id = "015617-16GHBC-AF02D9" + organization_id = "506128240800" + root_node = "folders/93469270123701" + prefix = "unique-prefix" + environments = { + dev = "Development", + test = "Testing", + prod = "Production" } + service_account_keys = true } ``` @@ -26,21 +29,29 @@ module "folder" { | name | description | type | required | default | |---|---|:---: |:---:|:---:| -| parent | Parent in folders/folder_id or organizations/org_id format. | string | ✓ | | -| *iam_members* | List of IAM members keyed by folder name and role. | map(map(list(string))) | | null | -| *iam_roles* | List of IAM roles keyed by folder name. | map(list(string)) | | null | -| *names* | Folder names. | list(string) | | [] | +| automation_project_id | Project id used for automation service accounts. | string | ✓ | | +| billing_account_id | Country billing account account. | string | ✓ | | +| iam_members | IAM members for roles applied on the unit folder. | map(list(string)) | ✓ | | +| iam_roles | IAM roles applied on the unit folder. | list(string) | ✓ | | +| name | Top folder name. | string | ✓ | | +| organization_id | Organization id. | string | ✓ | | +| prefix | Prefix used for GCS bucket names. | string | ✓ | | +| root_node | Root node in folders/folder_id or organizations/org_id format. | string | ✓ | | +| short_name | Short name. | string | ✓ | | +| *environments* | Unit environments short names. | map(string) | | ... | +| *gcs_defaults* | Defaults use for the state GCS buckets. | map(string) | | ... | +| *iam_billing_config* | Control granting billing user role to service accounts. Target the billing account by default. | object({...}) | | ... | +| *iam_enviroment_roles* | IAM roles granted to service accounts on the environment sub-folders. | list(string) | | ... | +| *iam_xpn_config* | Control granting Shared VPC creation roles to service accounts. Target the root node by default. | object({...}) | | ... | +| *service_account_keys* | Generate and store service account keys in the state file. | bool | | false | ## Outputs | name | description | sensitive | |---|---|:---:| -| folder | Folder resource (for single use). | | -| folders | Folder resources. | | -| id | Folder id (for single use). | | -| ids | Folder ids. | | -| ids_list | List of folder ids. | | -| name | Folder name (for single use). | | -| names | Folder names. | | -| names_list | List of folder names. | | +| env_folders | Unit environments folders. | | +| env_gcs_buckets | Unit environments tfstate gcs buckets. | | +| env_sa_keys | Unit environments service account keys. | ✓ | +| env_service_accounts | Unit environments service accounts. | | +| unit_folder | Unit top level folder. | | diff --git a/modules/folders-unit/locals.tf b/modules/folders-unit/locals.tf new file mode 100644 index 0000000000..4bc6bb1c54 --- /dev/null +++ b/modules/folders-unit/locals.tf @@ -0,0 +1,61 @@ +/** + * Copyright 2020 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. + */ + +locals { + folder_roles = concat(var.iam_enviroment_roles, local.sa_xpn_folder_roles) + unit_iam_bindings = { + for role in var.iam_roles : + role => lookup(var.iam_members, role, []) + } + folder_iam_service_account_bindings = { + for pair in setproduct(keys(var.environments), local.folder_roles) : + "${pair.0}-${pair.1}" => { environment = pair.0, role = pair.1 } + } + org_iam_service_account_bindings = { + for pair in setproduct(keys(var.environments), concat( + local.sa_xpn_org_roles, + local.sa_billing_org_roles, + local.sa_billing_org_roles)) : + "${pair.0}-${pair.1}" => { environment = pair.0, role = pair.1 } + } + billing_iam_service_account_bindings = { + for pair in setproduct(keys(var.environments), local.sa_billing_account_roles) : + "${pair.0}-${pair.1}" => { environment = pair.0, role = pair.1 } + } + service_accounts = { + for key, sa in google_service_account.environment : + key => "serviceAccount:${sa.email}" + } + sa_billing_account_roles = ( + var.iam_billing_config.target_org ? [] : ["roles/billing.user"] + ) + sa_billing_org_roles = ( + ! var.iam_billing_config.target_org ? [] : ["roles/billing.user"] + ) + sa_xpn_folder_roles = ( + local.sa_xpn_target_org ? [] : ["roles/compute.xpnAdmin"] + ) + sa_xpn_org_roles = ( + local.sa_xpn_target_org + ? ["roles/compute.xpnAdmin", "roles/resourcemanager.organizationViewer"] + : ["roles/resourcemanager.organizationViewer"] + ) + sa_xpn_target_org = ( + var.iam_xpn_config.target_org + || + substr(var.root_node, 0, 13) == "organizations" + ) +} diff --git a/modules/folders-unit/main.tf b/modules/folders-unit/main.tf index 0d4a30a311..b553b11ab6 100644 --- a/modules/folders-unit/main.tf +++ b/modules/folders-unit/main.tf @@ -14,29 +14,13 @@ * limitations under the License. */ -locals { - - iam_bindings = { - for role in var.iam_roles : - role => lookup(var.iam_members, role, []) - } - iam_service_account_bindings = { - for pair in setproduct(keys(var.environments), var.iam_enviroment_roles) : - "${pair.0}-${pair.1}" => { environment = pair.0, role = pair.1 } - } - service_accounts = { - for key, sa in google_service_account.environment : - key => "serviceAccount:${sa.email}" - } -} - ################################################################################ # Folders and folder IAM # ################################################################################ resource "google_folder" "unit" { display_name = var.name - parent = var.parent + parent = var.root_node } resource "google_folder" "environment" { @@ -45,15 +29,15 @@ resource "google_folder" "environment" { parent = google_folder.unit.name } -resource "google_folder_iam_binding" "authoritative" { - for_each = local.iam_bindings +resource "google_folder_iam_binding" "unit" { + for_each = local.unit_iam_bindings folder = google_folder.unit.name role = each.key members = each.value } resource "google_folder_iam_binding" "environment" { - for_each = local.iam_service_account_bindings + for_each = local.folder_iam_service_account_bindings folder = google_folder.environment[each.value.environment].name role = each.value.role members = [ @@ -62,7 +46,25 @@ resource "google_folder_iam_binding" "environment" { } ################################################################################ -# Service Accounts and SA IAM # +# Billing Account and Org level IAM Bindings # +################################################################################ + +resource "google_organization_iam_member" "org_iam_member" { + for_each = local.org_iam_service_account_bindings + org_id = var.organization_id + role = each.value.role + member = "serviceAccount:${google_service_account.environment[each.value.environment].email}" +} + +resource "google_billing_account_iam_member" "billing_iam_member" { + for_each = local.billing_iam_service_account_bindings + billing_account_id = var.billing_account_id + role = each.value.role + member = "serviceAccount:${google_service_account.environment[each.value.environment].email}" +} + +################################################################################ +# Service Accounts # ################################################################################ resource "google_service_account" "environment" { @@ -73,20 +75,10 @@ resource "google_service_account" "environment" { } resource "google_service_account_key" "keys" { - for_each = var.generate_keys ? var.environments : {} + for_each = var.service_account_keys ? var.environments : {} service_account_id = google_service_account.environment[each.key].email } -resource "google_billing_account_iam_member" "billing-user" { - for_each = local.service_accounts - billing_account_id = var.billing_account_id - role = "roles/billing.user" - member = each.value -} - -# TODO: remember to add org-level roles if the service accounts need to manage -# Shared VPC inside the Prod/Non-prod folders - ################################################################################ # GCS and GCS IAM # ################################################################################ diff --git a/modules/folders-unit/outputs.tf b/modules/folders-unit/outputs.tf index bc526f7c15..520712f50a 100644 --- a/modules/folders-unit/outputs.tf +++ b/modules/folders-unit/outputs.tf @@ -14,35 +14,46 @@ * limitations under the License. */ -output "unit" { - description = "Unit attributes." +output "unit_folder" { + description = "Unit top level folder." value = { - name = var.name - folder = google_folder.unit.name - tf_gcs_buckets = { - for env in keys(var.environments) - : env => google_storage_bucket.tfstate[env].name - } - env_folders = { - for key, folder in google_folder.environment - : key => folder.name - } - service_accounts = { - for key, sa in google_service_account.environment - : key => sa.email - } + id = google_folder.unit.name, + name = google_folder.unit.display_name + } +} + +output "env_gcs_buckets" { + description = "Unit environments tfstate gcs buckets." + value = { + for key, bucket in google_storage_bucket.tfstate + : key => bucket.name } } -output "keys" { - description = "Service account keys." - sensitive = true - value = ( - var.generate_keys ? { - for env in keys(var.environments) : - env => lookup(google_service_account_key.keys, env, null) - } : {} - ) +output "env_folders" { + description = "Unit environments folders." + value = { + for key, folder in google_folder.environment + : key => { + id = folder.name, + name = folder.display_name + } + } } +output "env_service_accounts" { + description = "Unit environments service accounts." + value = { + for key, sa in google_service_account.environment + : key => sa.email + } +} +output "env_sa_keys" { + description = "Unit environments service account keys." + sensitive = true + value = { + for key, sa_key in google_service_account_key.keys : + key => sa_key.private_key + } +} diff --git a/modules/folders-unit/variables.tf b/modules/folders-unit/variables.tf index d78a66b8a2..9b825237c1 100644 --- a/modules/folders-unit/variables.tf +++ b/modules/folders-unit/variables.tf @@ -19,8 +19,8 @@ variable "organization_id" { type = string } -variable "parent" { - description = "Parent in folders/folder_id or organizations/org_id format." +variable "root_node" { + description = "Root node in folders/folder_id or organizations/org_id format." type = string } @@ -33,9 +33,9 @@ variable "environments" { description = "Unit environments short names." type = map(string) default = { - dev = "development", - test = "Testing", - prod = "Production" + dev = "development", + test = "Testing", + prod = "Production" } } @@ -55,8 +55,8 @@ variable "name" { } variable "short_name" { - description = "Short name." - type = string + description = "Short name." + type = string } variable "gcs_defaults" { @@ -89,8 +89,32 @@ variable "iam_enviroment_roles" { ] } -variable "generate_keys" { - description = "Generate keys for service accounts." +variable "service_account_keys" { + description = "Generate and store service account keys in the state file." type = bool default = false } + +variable "iam_xpn_config" { + description = "Control granting Shared VPC creation roles to service accounts. Target the root node by default." + type = object({ + grant = bool + target_org = bool + }) + default = { + grant = true + target_org = false + } +} + +variable "iam_billing_config" { + description = "Control granting billing user role to service accounts. Target the billing account by default." + type = object({ + grant = bool + target_org = bool + }) + default = { + grant = true + target_org = false + } +} diff --git a/modules/folders/main.tf b/modules/folders/main.tf index 3b2bbe8b97..9e55b4ce79 100644 --- a/modules/folders/main.tf +++ b/modules/folders/main.tf @@ -33,15 +33,6 @@ resource "google_folder" "folders" { parent = var.parent } -# give project creation access to service accounts -# https://cloud.google.com/resource-manager/docs/access-control-folders#granting_folder-specific_roles_to_enable_project_creation -# - external users need to have accepted the invitation email to join -# "roles/owner", -# "roles/resourcemanager.folderViewer", -# "roles/resourcemanager.projectCreator", -# "roles/compute.networkAdmin", - - resource "google_folder_iam_binding" "authoritative" { for_each = local.iam_keypairs folder = google_folder.folders[each.value.name].name @@ -51,9 +42,3 @@ resource "google_folder_iam_binding" "authoritative" { ) } -# resource "google_folder_iam_member" "non_authoritative" { -# for_each = length(var.iam_non_authoritative_roles) > 0 ? local.iam_non_authoritative : {} -# folder = google_project.project.project_id -# role = each.value.role -# member = each.value.member -# } diff --git a/modules/net-vpc/README.md b/modules/net-vpc/README.md index 6c7884f860..7259abf157 100644 --- a/modules/net-vpc/README.md +++ b/modules/net-vpc/README.md @@ -25,6 +25,7 @@ module "vpc" { subnet-2 = { ip_cidr_range = "10.0.16.0/24" region = "europe-west1" + secondary_ip_range = {} } } } diff --git a/modules/project/main.tf b/modules/project/main.tf index b684ed0cb0..e6d8bab679 100644 --- a/modules/project/main.tf +++ b/modules/project/main.tf @@ -19,14 +19,14 @@ locals { gce_service_account = "${google_project.project.number}-compute@developer.gserviceaccount.com" gcr_service_account = "service-${google_project.project.number}@containerregistry.iam.gserviceaccount.com" gke_service_account = "service-${google_project.project.number}@container-engine-robot.iam.gserviceaccount.com" - iam_nonauth_pairs = flatten([ - for role in var.iam_nonauth_roles : [ - for member in lookup(var.iam_nonauth_members, role, []) : + iam_additive_pairs = flatten([ + for role in var.iam_additive_roles : [ + for member in lookup(var.iam_additive_members, role, []) : { role = role, member = member } ] ]) - iam_nonauth = { - for pair in local.iam_nonauth_pairs : + iam_additive = { + for pair in local.iam_additive_pairs : "${pair.role}-${pair.member}" => pair } parent_type = split("/", var.parent)[0] @@ -81,7 +81,7 @@ resource "google_project_service" "project_services" { # IAM notes: # - external users need to have accepted the invitation email to join # - oslogin roles also require role to list instances -# - non-authoritative roles might fail due to dynamic values +# - additive (non-authoritative) roles might fail due to dynamic values resource "google_project_iam_binding" "authoritative" { for_each = toset(var.iam_roles) @@ -90,8 +90,8 @@ resource "google_project_iam_binding" "authoritative" { members = lookup(var.iam_members, each.value, []) } -resource "google_project_iam_member" "non_authoritative" { - for_each = length(var.iam_nonauth_roles) > 0 ? local.iam_nonauth : {} +resource "google_project_iam_member" "additive" { + for_each = length(var.iam_additive_roles) > 0 ? local.iam_additive : {} project = google_project.project.project_id role = each.value.role member = each.value.member diff --git a/modules/project/variables.tf b/modules/project/variables.tf index fb71debd6a..b9ecc8645a 100644 --- a/modules/project/variables.tf +++ b/modules/project/variables.tf @@ -44,13 +44,13 @@ variable "iam_roles" { default = [] } -variable "iam_nonauth_members" { +variable "iam_additive_members" { description = "Map of member lists used to set non authoritative bindings, keyed by role." type = map(list(string)) default = {} } -variable "iam_nonauth_roles" { +variable "iam_additive_roles" { description = "List of roles used to set non authoritative bindings." type = list(string) default = []