diff --git a/examples/factories/project-factory/README.md b/examples/factories/project-factory/README.md index 268c173f..8cc45c00 100644 --- a/examples/factories/project-factory/README.md +++ b/examples/factories/project-factory/README.md @@ -218,26 +218,28 @@ vpc: | name | description | type | required | default | |---|---|:---:|:---:|:---:| | [billing_account_id](variables.tf#L17) | Billing account id. | string | ✓ | | -| [defaults](variables.tf#L35) | Project factory default values. | object({…}) | ✓ | | -| [folder_id](variables.tf#L68) | Folder ID for the folder where the project will be created. | string | ✓ | | -| [project_id](variables.tf#L111) | Project id. | string | ✓ | | +| [folder_id](variables.tf#L69) | Folder ID for the folder where the project will be created. | string | ✓ | | +| [project_id](variables.tf#L119) | Project id. | string | ✓ | | | [billing_alert](variables.tf#L22) | Billing alert configuration. | object({…}) | | null | -| [dns_zones](variables.tf#L56) | DNS private zones to create as child of var.defaults.environment_dns_zone. | list(string) | | [] | -| [essential_contacts](variables.tf#L62) | Email contacts to be used for billing and GCP notifications. | list(string) | | [] | -| [group_iam](variables.tf#L73) | Custom IAM settings in group => [role] format. | map(list(string)) | | {} | -| [iam](variables.tf#L79) | Custom IAM settings in role => [principal] format. | map(list(string)) | | {} | -| [kms_service_agents](variables.tf#L85) | KMS IAM configuration in as service => [key]. | map(list(string)) | | {} | -| [labels](variables.tf#L91) | Labels to be assigned at project level. | map(string) | | {} | -| [org_policies](variables.tf#L97) | Org-policy overrides at project level. | object({…}) | | null | -| [service_accounts](variables.tf#L116) | Service accounts to be created, and roles to assign them. | map(list(string)) | | {} | -| [services](variables.tf#L122) | Services to be enabled for the project. | list(string) | | [] | -| [services_iam](variables.tf#L128) | Custom IAM settings for robot ServiceAccounts in service => [role] format. | map(list(string)) | | {} | -| [vpc](variables.tf#L134) | VPC configuration for the project. | object({…}) | | null | +| [defaults](variables.tf#L35) | Project factory default values. | object({…}) | | null | +| [dns_zones](variables.tf#L57) | DNS private zones to create as child of var.defaults.environment_dns_zone. | list(string) | | [] | +| [essential_contacts](variables.tf#L63) | Email contacts to be used for billing and GCP notifications. | list(string) | | [] | +| [group_iam](variables.tf#L74) | Custom IAM settings in group => [role] format. | map(list(string)) | | {} | +| [iam](variables.tf#L80) | Custom IAM settings in role => [principal] format. | map(list(string)) | | {} | +| [kms_service_agents](variables.tf#L86) | KMS IAM configuration in as service => [key]. | map(list(string)) | | {} | +| [labels](variables.tf#L92) | Labels to be assigned at project level. | map(string) | | {} | +| [org_policies](variables.tf#L98) | Org-policy overrides at project level. | object({…}) | | null | +| [prefix](variables.tf#L112) | Prefix used for the project id. | string | | null | +| [service_accounts](variables.tf#L124) | Service accounts to be created, and roles to assign them. | map(list(string)) | | {} | +| [services](variables.tf#L130) | Services to be enabled for the project. | list(string) | | [] | +| [services_iam](variables.tf#L136) | Custom IAM settings for robot ServiceAccounts in service => [role] format. | map(list(string)) | | {} | +| [vpc](variables.tf#L142) | VPC configuration for the project. | object({…}) | | null | ## Outputs | name | description | sensitive | |---|---|:---:| -| [project_id](outputs.tf#L19) | Project ID. | | +| [project](outputs.tf#L19) | The project resource as return by the `project` module | | +| [project_id](outputs.tf#L30) | Project ID. | | diff --git a/examples/factories/project-factory/main.tf b/examples/factories/project-factory/main.tf index c4928371..df449edb 100644 --- a/examples/factories/project-factory/main.tf +++ b/examples/factories/project-factory/main.tf @@ -15,15 +15,12 @@ */ locals { - _gke_iam_hsau = try(var.vpc.gke_setup.enable_security_admin, false) ? { - "roles/container.hostServiceAgentUser" = [ - "serviceAccount:${local.service_accounts_robots["container-engine"]}" - ] } : {} - + _gke_iam_hsau = try(var.vpc.gke_setup.enable_host_service_agent, false) ? { + "roles/container.hostServiceAgentUser" = "serviceAccount:${module.project.service_accounts.robots.container-engine}" + } : {} _gke_iam_securityadmin = try(var.vpc.gke_setup.enable_security_admin, false) ? { - "roles/compute.securityAdmin" = [ - "serviceAccount:${local.service_accounts_robots["container-engine"]}" - ] } : {} + "roles/compute.securityAdmin" = "serviceAccount:${module.project.service_accounts.robots.container-engine}" + } : {} _group_iam = { for r in local._group_iam_roles : r => [ for k, v in var.group_iam : "group:${k}" if try(index(v, r), null) != null @@ -47,59 +44,41 @@ locals { _services_iam_roles = distinct(flatten(values(var.services_iam))) _services_iam = { for r in local._services_iam_roles : r => [ - for k, v in var.services_iam : "serviceAccount:${local.service_accounts_robots[k]}" if try(index(v, r), null) != null + for k, v in var.services_iam : "serviceAccount:${module.project.service_accounts.robots[k]}" if try(index(v, r), null) != null ] } - billing_account_id = coalesce(var.billing_account_id, var.defaults.billing_account_id) - billing_alert = var.billing_alert == null ? var.defaults.billing_alert : var.billing_alert + billing_account_id = coalesce(var.billing_account_id, try(var.defaults.billing_account_id, "")) + billing_alert = var.billing_alert == null ? try(var.defaults.billing_alert, null) : var.billing_alert essential_contacts = concat(try(var.defaults.essential_contacts, []), var.essential_contacts) + host_project_bindings = merge( + local._gke_iam_hsau, + local._gke_iam_securityadmin + ) iam = { for role in distinct(concat( keys(var.iam), keys(local._group_iam), - keys(local._gke_iam_hsau), - keys(local._gke_iam_securityadmin), keys(local._service_accounts_iam), keys(local._services_iam), )) : role => concat( try(var.iam[role], []), try(local._group_iam[role], []), - try(local._gke_iam_hsau[role], []), - try(local._gke_iam_securityadmin[role], []), try(local._service_accounts_iam[role], []), try(local._services_iam[role], []), ) } - labels = merge(coalesce(var.labels, {}), coalesce(var.defaults.labels, {})) + labels = merge(coalesce(var.labels, {}), coalesce(try(var.defaults.labels, {}), {})) network_user_service_accounts = concat( contains(local.services, "compute.googleapis.com") ? [ - "serviceAccount:${local.service_accounts_robots.compute}" + "serviceAccount:${module.project.service_accounts.robots.compute}" ] : [], contains(local.services, "container.googleapis.com") ? [ - "serviceAccount:${local.service_accounts_robots.container-engine}", - "serviceAccount:${local.service_accounts.cloud_services}" + "serviceAccount:${module.project.service_accounts.robots.container-engine}", + "serviceAccount:${module.project.service_accounts.cloud_services}" ] : [], []) - services = distinct(concat(var.services, local._services)) - service_accounts_robots = { - for service, name in local.service_accounts_robot_services : - service => "${service == "bq" ? "bq" : "service"}-${module.project.number}@${name}.iam.gserviceaccount.com" - } - service_accounts_robot_services = { - cloudasset = "gcp-sa-cloudasset" - cloudbuild = "gcp-sa-cloudbuild" - compute = "compute-system" - container-engine = "container-engine-robot" - containerregistry = "containerregistry" - dataflow = "dataflow-service-producer-prod" - dataproc = "dataproc-accounts" - gae-flex = "gae-api-prod" - gcf = "gcf-admin-robot" - pubsub = "gcp-sa-pubsub" - secretmanager = "gcp-sa-secretmanager" - storage = "gs-project-accounts" - } + services = distinct(concat(var.services, local._services)) vpc_host_project = try(var.vpc.host_project, var.defaults.vpc_host_project) vpc_setup = var.vpc != null } @@ -134,6 +113,7 @@ module "project" { source = "../../../modules/project" billing_account = local.billing_account_id name = var.project_id + prefix = var.prefix contacts = { for c in local.essential_contacts : c => ["ALL"] } iam = local.iam labels = local.labels @@ -155,6 +135,7 @@ module "service-accounts" { project_id = module.project.project_id } +# TODO(jccb): we should probably change this to non-authoritative bindings resource "google_compute_subnetwork_iam_binding" "binding" { for_each = local.vpc_setup ? coalesce(var.vpc.subnets_iam, {}) : {} project = local.vpc_host_project @@ -163,3 +144,10 @@ resource "google_compute_subnetwork_iam_binding" "binding" { role = "roles/compute.networkUser" members = concat(each.value, local.network_user_service_accounts) } + +resource "google_project_iam_member" "host_project_bindings" { + for_each = local.host_project_bindings + project = local.vpc_host_project + role = each.key + member = each.value +} diff --git a/examples/factories/project-factory/outputs.tf b/examples/factories/project-factory/outputs.tf index 1ee734ed..7504eda5 100644 --- a/examples/factories/project-factory/outputs.tf +++ b/examples/factories/project-factory/outputs.tf @@ -16,7 +16,23 @@ # TODO(): proper outputs +output "project" { + description = "The project resource as return by the `project` module" + value = module.project + + depends_on = [ + google_compute_subnetwork_iam_binding.binding, + google_project_iam_member.host_project_bindings, + module.dns + ] +} + output "project_id" { description = "Project ID." value = module.project.project_id + depends_on = [ + google_compute_subnetwork_iam_binding.binding, + google_project_iam_member.host_project_bindings, + module.dns + ] } diff --git a/examples/factories/project-factory/variables.tf b/examples/factories/project-factory/variables.tf index adae051a..777dce71 100644 --- a/examples/factories/project-factory/variables.tf +++ b/examples/factories/project-factory/variables.tf @@ -51,6 +51,7 @@ variable "defaults" { shared_vpc_self_link = string vpc_host_project = string }) + default = null } variable "dns_zones" { @@ -108,6 +109,12 @@ variable "org_policies" { default = null } +variable "prefix" { + description = "Prefix used for the project id." + type = string + default = null +} + variable "project_id" { description = "Project id." type = string