Project factory fixes

- Add GKE roles in the host project
- Use SA names from project module
- Add a few outputs
- Add prefix for project ids
This commit is contained in:
Julio Castillo 2022-02-07 11:33:03 +01:00 committed by Julio Castillo
parent 40142572f8
commit 82b181f34e
4 changed files with 66 additions and 53 deletions

View File

@ -218,26 +218,28 @@ vpc:
| name | description | type | required | default | | name | description | type | required | default |
|---|---|:---:|:---:|:---:| |---|---|:---:|:---:|:---:|
| [billing_account_id](variables.tf#L17) | Billing account id. | <code>string</code> | ✓ | | | [billing_account_id](variables.tf#L17) | Billing account id. | <code>string</code> | ✓ | |
| [defaults](variables.tf#L35) | Project factory default values. | <code title="object&#40;&#123;&#10; billing_account_id &#61; string&#10; billing_alert &#61; object&#40;&#123;&#10; amount &#61; number&#10; thresholds &#61; object&#40;&#123;&#10; current &#61; list&#40;number&#41;&#10; forecasted &#61; list&#40;number&#41;&#10; &#125;&#41;&#10; credit_treatment &#61; string&#10; &#125;&#41;&#10; environment_dns_zone &#61; string&#10; essential_contacts &#61; list&#40;string&#41;&#10; labels &#61; map&#40;string&#41;&#10; notification_channels &#61; list&#40;string&#41;&#10; shared_vpc_self_link &#61; string&#10; vpc_host_project &#61; string&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | ✓ | | | [folder_id](variables.tf#L69) | Folder ID for the folder where the project will be created. | <code>string</code> | ✓ | |
| [folder_id](variables.tf#L68) | Folder ID for the folder where the project will be created. | <code>string</code> | ✓ | | | [project_id](variables.tf#L119) | Project id. | <code>string</code> | ✓ | |
| [project_id](variables.tf#L111) | Project id. | <code>string</code> | ✓ | |
| [billing_alert](variables.tf#L22) | Billing alert configuration. | <code title="object&#40;&#123;&#10; amount &#61; number&#10; thresholds &#61; object&#40;&#123;&#10; current &#61; list&#40;number&#41;&#10; forecasted &#61; list&#40;number&#41;&#10; &#125;&#41;&#10; credit_treatment &#61; string&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> | | [billing_alert](variables.tf#L22) | Billing alert configuration. | <code title="object&#40;&#123;&#10; amount &#61; number&#10; thresholds &#61; object&#40;&#123;&#10; current &#61; list&#40;number&#41;&#10; forecasted &#61; list&#40;number&#41;&#10; &#125;&#41;&#10; credit_treatment &#61; string&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> |
| [dns_zones](variables.tf#L56) | DNS private zones to create as child of var.defaults.environment_dns_zone. | <code>list&#40;string&#41;</code> | | <code>&#91;&#93;</code> | | [defaults](variables.tf#L35) | Project factory default values. | <code title="object&#40;&#123;&#10; billing_account_id &#61; string&#10; billing_alert &#61; object&#40;&#123;&#10; amount &#61; number&#10; thresholds &#61; object&#40;&#123;&#10; current &#61; list&#40;number&#41;&#10; forecasted &#61; list&#40;number&#41;&#10; &#125;&#41;&#10; credit_treatment &#61; string&#10; &#125;&#41;&#10; environment_dns_zone &#61; string&#10; essential_contacts &#61; list&#40;string&#41;&#10; labels &#61; map&#40;string&#41;&#10; notification_channels &#61; list&#40;string&#41;&#10; shared_vpc_self_link &#61; string&#10; vpc_host_project &#61; string&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> |
| [essential_contacts](variables.tf#L62) | Email contacts to be used for billing and GCP notifications. | <code>list&#40;string&#41;</code> | | <code>&#91;&#93;</code> | | [dns_zones](variables.tf#L57) | DNS private zones to create as child of var.defaults.environment_dns_zone. | <code>list&#40;string&#41;</code> | | <code>&#91;&#93;</code> |
| [group_iam](variables.tf#L73) | Custom IAM settings in group => [role] format. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [essential_contacts](variables.tf#L63) | Email contacts to be used for billing and GCP notifications. | <code>list&#40;string&#41;</code> | | <code>&#91;&#93;</code> |
| [iam](variables.tf#L79) | Custom IAM settings in role => [principal] format. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [group_iam](variables.tf#L74) | Custom IAM settings in group => [role] format. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [kms_service_agents](variables.tf#L85) | KMS IAM configuration in as service => [key]. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [iam](variables.tf#L80) | Custom IAM settings in role => [principal] format. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [labels](variables.tf#L91) | Labels to be assigned at project level. | <code>map&#40;string&#41;</code> | | <code>&#123;&#125;</code> | | [kms_service_agents](variables.tf#L86) | KMS IAM configuration in as service => [key]. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [org_policies](variables.tf#L97) | Org-policy overrides at project level. | <code title="object&#40;&#123;&#10; policy_boolean &#61; map&#40;bool&#41;&#10; policy_list &#61; map&#40;object&#40;&#123;&#10; inherit_from_parent &#61; bool&#10; suggested_value &#61; string&#10; status &#61; bool&#10; values &#61; list&#40;string&#41;&#10; &#125;&#41;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> | | [labels](variables.tf#L92) | Labels to be assigned at project level. | <code>map&#40;string&#41;</code> | | <code>&#123;&#125;</code> |
| [service_accounts](variables.tf#L116) | Service accounts to be created, and roles to assign them. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [org_policies](variables.tf#L98) | Org-policy overrides at project level. | <code title="object&#40;&#123;&#10; policy_boolean &#61; map&#40;bool&#41;&#10; policy_list &#61; map&#40;object&#40;&#123;&#10; inherit_from_parent &#61; bool&#10; suggested_value &#61; string&#10; status &#61; bool&#10; values &#61; list&#40;string&#41;&#10; &#125;&#41;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> |
| [services](variables.tf#L122) | Services to be enabled for the project. | <code>list&#40;string&#41;</code> | | <code>&#91;&#93;</code> | | [prefix](variables.tf#L112) | Prefix used for the project id. | <code>string</code> | | <code>null</code> |
| [services_iam](variables.tf#L128) | Custom IAM settings for robot ServiceAccounts in service => [role] format. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [service_accounts](variables.tf#L124) | Service accounts to be created, and roles to assign them. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [vpc](variables.tf#L134) | VPC configuration for the project. | <code title="object&#40;&#123;&#10; host_project &#61; string&#10; gke_setup &#61; object&#40;&#123;&#10; enable_security_admin &#61; bool&#10; enable_host_service_agent &#61; bool&#10; &#125;&#41;&#10; subnets_iam &#61; map&#40;list&#40;string&#41;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> | | [services](variables.tf#L130) | Services to be enabled for the project. | <code>list&#40;string&#41;</code> | | <code>&#91;&#93;</code> |
| [services_iam](variables.tf#L136) | Custom IAM settings for robot ServiceAccounts in service => [role] format. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [vpc](variables.tf#L142) | VPC configuration for the project. | <code title="object&#40;&#123;&#10; host_project &#61; string&#10; gke_setup &#61; object&#40;&#123;&#10; enable_security_admin &#61; bool&#10; enable_host_service_agent &#61; bool&#10; &#125;&#41;&#10; subnets_iam &#61; map&#40;list&#40;string&#41;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> |
## Outputs ## Outputs
| name | description | sensitive | | 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. | |
<!-- END TFDOC --> <!-- END TFDOC -->

View File

@ -15,15 +15,12 @@
*/ */
locals { locals {
_gke_iam_hsau = try(var.vpc.gke_setup.enable_security_admin, false) ? { _gke_iam_hsau = try(var.vpc.gke_setup.enable_host_service_agent, false) ? {
"roles/container.hostServiceAgentUser" = [ "roles/container.hostServiceAgentUser" = "serviceAccount:${module.project.service_accounts.robots.container-engine}"
"serviceAccount:${local.service_accounts_robots["container-engine"]}" } : {}
] } : {}
_gke_iam_securityadmin = try(var.vpc.gke_setup.enable_security_admin, false) ? { _gke_iam_securityadmin = try(var.vpc.gke_setup.enable_security_admin, false) ? {
"roles/compute.securityAdmin" = [ "roles/compute.securityAdmin" = "serviceAccount:${module.project.service_accounts.robots.container-engine}"
"serviceAccount:${local.service_accounts_robots["container-engine"]}" } : {}
] } : {}
_group_iam = { _group_iam = {
for r in local._group_iam_roles : r => [ for r in local._group_iam_roles : r => [
for k, v in var.group_iam : "group:${k}" if try(index(v, r), null) != null 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_roles = distinct(flatten(values(var.services_iam)))
_services_iam = { _services_iam = {
for r in local._services_iam_roles : r => [ 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_account_id = coalesce(var.billing_account_id, try(var.defaults.billing_account_id, ""))
billing_alert = var.billing_alert == null ? var.defaults.billing_alert : var.billing_alert 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) essential_contacts = concat(try(var.defaults.essential_contacts, []), var.essential_contacts)
host_project_bindings = merge(
local._gke_iam_hsau,
local._gke_iam_securityadmin
)
iam = { iam = {
for role in distinct(concat( for role in distinct(concat(
keys(var.iam), keys(var.iam),
keys(local._group_iam), keys(local._group_iam),
keys(local._gke_iam_hsau),
keys(local._gke_iam_securityadmin),
keys(local._service_accounts_iam), keys(local._service_accounts_iam),
keys(local._services_iam), keys(local._services_iam),
)) : )) :
role => concat( role => concat(
try(var.iam[role], []), try(var.iam[role], []),
try(local._group_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._service_accounts_iam[role], []),
try(local._services_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( network_user_service_accounts = concat(
contains(local.services, "compute.googleapis.com") ? [ 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") ? [ contains(local.services, "container.googleapis.com") ? [
"serviceAccount:${local.service_accounts_robots.container-engine}", "serviceAccount:${module.project.service_accounts.robots.container-engine}",
"serviceAccount:${local.service_accounts.cloud_services}" "serviceAccount:${module.project.service_accounts.cloud_services}"
] : [], ] : [],
[]) [])
services = distinct(concat(var.services, local._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"
}
vpc_host_project = try(var.vpc.host_project, var.defaults.vpc_host_project) vpc_host_project = try(var.vpc.host_project, var.defaults.vpc_host_project)
vpc_setup = var.vpc != null vpc_setup = var.vpc != null
} }
@ -134,6 +113,7 @@ module "project" {
source = "../../../modules/project" source = "../../../modules/project"
billing_account = local.billing_account_id billing_account = local.billing_account_id
name = var.project_id name = var.project_id
prefix = var.prefix
contacts = { for c in local.essential_contacts : c => ["ALL"] } contacts = { for c in local.essential_contacts : c => ["ALL"] }
iam = local.iam iam = local.iam
labels = local.labels labels = local.labels
@ -155,6 +135,7 @@ module "service-accounts" {
project_id = module.project.project_id project_id = module.project.project_id
} }
# TODO(jccb): we should probably change this to non-authoritative bindings
resource "google_compute_subnetwork_iam_binding" "binding" { resource "google_compute_subnetwork_iam_binding" "binding" {
for_each = local.vpc_setup ? coalesce(var.vpc.subnets_iam, {}) : {} for_each = local.vpc_setup ? coalesce(var.vpc.subnets_iam, {}) : {}
project = local.vpc_host_project project = local.vpc_host_project
@ -163,3 +144,10 @@ resource "google_compute_subnetwork_iam_binding" "binding" {
role = "roles/compute.networkUser" role = "roles/compute.networkUser"
members = concat(each.value, local.network_user_service_accounts) 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
}

View File

@ -16,7 +16,23 @@
# TODO(): proper outputs # 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" { output "project_id" {
description = "Project ID." description = "Project ID."
value = module.project.project_id value = module.project.project_id
depends_on = [
google_compute_subnetwork_iam_binding.binding,
google_project_iam_member.host_project_bindings,
module.dns
]
} }

View File

@ -51,6 +51,7 @@ variable "defaults" {
shared_vpc_self_link = string shared_vpc_self_link = string
vpc_host_project = string vpc_host_project = string
}) })
default = null
} }
variable "dns_zones" { variable "dns_zones" {
@ -108,6 +109,12 @@ variable "org_policies" {
default = null default = null
} }
variable "prefix" {
description = "Prefix used for the project id."
type = string
default = null
}
variable "project_id" { variable "project_id" {
description = "Project id." description = "Project id."
type = string type = string