4-appfactory/modules/app-group-baseline/main.tf (247 lines of code) (raw):

/** * Copyright 2024 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 { admin_project_id = var.create_admin_project ? module.app_admin_project[0].project_id : var.admin_project_id cloudbuild_sa_roles = merge(var.create_infra_project ? { for env in keys(var.envs) : env => { project_id = module.app_infra_project[env].project_id roles = var.cloudbuild_sa_roles[env].roles } } : {}, { "admin" : { project_id = local.admin_project_id roles = [ "roles/browser", "roles/serviceusage.serviceUsageAdmin", "roles/storage.admin", "roles/iam.serviceAccountAdmin", "roles/artifactregistry.admin", "roles/clouddeploy.admin", "roles/cloudbuild.builds.editor", "roles/privilegedaccessmanager.projectServiceAgent", "roles/iam.serviceAccountUser", "roles/source.admin", "roles/cloudbuild.connectionAdmin" ] } }, { for cluster_project_id in var.cluster_projects_ids : cluster_project_id => { project_id = cluster_project_id roles = ["roles/privilegedaccessmanager.projectServiceAgent"] } } ) org_ids = distinct([for env in var.envs : env.org_id]) use_csr = var.cloudbuildv2_repository_config.repo_type == "CSR" service_repo_name = var.cloudbuildv2_repository_config.repositories[var.service_name].repository_name worker_pool_project = element(split("/", var.workerpool_id), index(split("/", var.workerpool_id), "projects") + 1, ) secret_id = var.cloudbuildv2_repository_config.github_secret_id != null ? var.cloudbuildv2_repository_config.github_secret_id : var.cloudbuildv2_repository_config.gitlab_authorizer_credential_secret_id secret_project_number = regex("projects/([^/]*)/", local.secret_id)[0] } data "google_project" "admin_project" { project_id = local.admin_project_id } data "google_project" "workerpool_project" { project_id = local.worker_pool_project } data "google_project" "clusters_projects" { for_each = toset(var.cluster_projects_ids) project_id = each.value } module "cloudbuild_repositories" { count = local.use_csr ? 0 : 1 source = "terraform-google-modules/bootstrap/google//modules/cloudbuild_repo_connection" version = "~> 11.0" project_id = local.admin_project_id connection_config = { connection_type = var.cloudbuildv2_repository_config.repo_type github_secret_id = var.cloudbuildv2_repository_config.github_secret_id github_app_id_secret_id = var.cloudbuildv2_repository_config.github_app_id_secret_id gitlab_read_authorizer_credential_secret_id = var.cloudbuildv2_repository_config.gitlab_read_authorizer_credential_secret_id gitlab_authorizer_credential_secret_id = var.cloudbuildv2_repository_config.gitlab_authorizer_credential_secret_id gitlab_webhook_secret_id = var.cloudbuildv2_repository_config.gitlab_webhook_secret_id gitlab_enterprise_host_uri = var.cloudbuildv2_repository_config.gitlab_enterprise_host_uri gitlab_enterprise_service_directory = var.cloudbuildv2_repository_config.gitlab_enterprise_service_directory gitlab_enterprise_ca_certificate = var.cloudbuildv2_repository_config.gitlab_enterprise_ca_certificate } cloud_build_repositories = var.cloudbuildv2_repository_config.repositories depends_on = [time_sleep.wait_propagation] } resource "time_sleep" "wait_propagation" { create_duration = "120s" depends_on = [ google_access_context_manager_service_perimeter_egress_policy.cloudbuild_egress_policy, google_access_context_manager_service_perimeter_dry_run_egress_policy.cloudbuild_egress_policy, google_access_context_manager_service_perimeter_egress_policy.service_directory_policy ] } module "app_admin_project" { count = var.create_admin_project ? 1 : 0 source = "terraform-google-modules/project-factory/google" version = "~> 18.0" random_project_id = true random_project_id_length = 4 billing_account = var.billing_account name = substr("${var.acronym}-${var.service_name}-admin", 0, 25) # max length 30 chars org_id = var.org_id folder_id = var.folder_id deletion_policy = "DELETE" default_service_account = "KEEP" activate_apis = [ "apikeys.googleapis.com", "iam.googleapis.com", "compute.googleapis.com", "cloudbilling.googleapis.com", "cloudbuild.googleapis.com", "clouddeploy.googleapis.com", "cloudfunctions.googleapis.com", "cloudresourcemanager.googleapis.com", "secretmanager.googleapis.com", "servicenetworking.googleapis.com", "serviceusage.googleapis.com", "sourcerepo.googleapis.com", ] disable_services_on_destroy = false disable_dependent_services = false vpc_service_control_attach_dry_run = var.service_perimeter_name != null && var.service_perimeter_mode == "DRY_RUN" vpc_service_control_attach_enabled = var.service_perimeter_name != null && var.service_perimeter_mode == "ENFORCE" vpc_service_control_perimeter_name = var.service_perimeter_name activate_api_identities = [ { api = "compute.googleapis.com", roles = [] }, { api = "cloudbuild.googleapis.com", roles = [ "roles/cloudbuild.builds.builder", "roles/cloudbuild.connectionAdmin", ] }, { api = "workflows.googleapis.com", roles = ["roles/workflows.serviceAgent"] }, { api = "config.googleapis.com", roles = ["roles/cloudconfig.serviceAgent"] }, { api = "container.googleapis.com", roles = ["roles/compute.networkUser", "roles/serviceusage.serviceUsageConsumer", "roles/container.serviceAgent"] }, ] } resource "google_sourcerepo_repository" "app_infra_repo" { // conditionally create the cloud source repo if the user did not define a cloud build 2nd gen repository. count = local.use_csr ? 1 : 0 project = local.admin_project_id name = "${var.service_name}-i-r" create_ignore_already_exists = true } module "tf_cloudbuild_workspace" { source = "terraform-google-modules/bootstrap/google//modules/tf_cloudbuild_workspace" version = "~> 11.0" project_id = local.admin_project_id tf_repo_uri = local.use_csr ? google_sourcerepo_repository.app_infra_repo[0].url : module.cloudbuild_repositories[0].cloud_build_repositories_2nd_gen_repositories[var.service_name].id tf_repo_type = local.use_csr ? "CLOUD_SOURCE_REPOSITORIES" : "CLOUDBUILD_V2_REPOSITORY" location = var.location trigger_location = var.trigger_location artifacts_bucket_name = "${var.bucket_prefix}-${local.admin_project_id}-${var.service_name}-build" create_state_bucket_name = "${var.bucket_prefix}-${local.admin_project_id}-${var.service_name}-state" log_bucket_name = "${var.bucket_prefix}-${local.admin_project_id}-${var.service_name}-logs" buckets_force_destroy = var.bucket_force_destroy cloudbuild_sa_roles = local.cloudbuild_sa_roles substitutions = merge({ "_GAR_REGION" = var.location "_GAR_PROJECT_ID" = var.gar_project_id "_GAR_REPOSITORY" = var.gar_repository_name "_DOCKER_TAG_VERSION_TERRAFORM" = var.docker_tag_version_terraform "_PRIVATE_POOL" = var.workerpool_id }) cloudbuild_plan_filename = "cloudbuild-tf-plan.yaml" cloudbuild_apply_filename = "cloudbuild-tf-apply.yaml" tf_apply_branches = var.tf_apply_branches } resource "google_project_iam_member" "worker_pool_builder_logging_writer" { member = "serviceAccount:${reverse(split("/", module.tf_cloudbuild_workspace.cloudbuild_sa))[0]}" project = local.worker_pool_project role = "roles/logging.logWriter" } resource "google_project_iam_member" "worker_pool_roles_privilegedaccessmanager_projectServiceAgent" { member = "serviceAccount:${reverse(split("/", module.tf_cloudbuild_workspace.cloudbuild_sa))[0]}" project = local.worker_pool_project role = "roles/privilegedaccessmanager.projectServiceAgent" } resource "google_project_iam_member" "cloud_build_builder" { member = "serviceAccount:${reverse(split("/", module.tf_cloudbuild_workspace.cloudbuild_sa))[0]}" project = local.worker_pool_project role = "roles/cloudbuild.builds.builder" } resource "google_project_iam_member" "workerPoolUser_cb_sa" { member = "serviceAccount:${reverse(split("/", module.tf_cloudbuild_workspace.cloudbuild_sa))[0]}" project = local.worker_pool_project role = "roles/cloudbuild.workerPoolUser" } resource "google_project_iam_member" "connection_admin_cb_sa" { member = "serviceAccount:${reverse(split("/", module.tf_cloudbuild_workspace.cloudbuild_sa))[0]}" project = local.admin_project_id role = "roles/cloudbuild.connectionAdmin" } resource "google_project_iam_member" "log_writer_cb_si" { member = "serviceAccount:${data.google_project.admin_project.number}@cloudbuild.gserviceaccount.com" project = local.worker_pool_project role = "roles/logging.logWriter" } resource "google_project_iam_member" "service_agent_cb_si" { member = "serviceAccount:${data.google_project.admin_project.number}@cloudbuild.gserviceaccount.com" project = local.worker_pool_project role = "roles/cloudbuild.builds.builder" } resource "google_project_iam_member" "cloud_build_sa_roles" { for_each = toset(["roles/storage.objectUser", "roles/artifactregistry.reader"]) member = "serviceAccount:${reverse(split("/", module.tf_cloudbuild_workspace.cloudbuild_sa))[0]}" project = var.gar_project_id role = each.value } resource "google_service_account_iam_member" "account_access" { for_each = toset(["roles/iam.serviceAccountUser", "roles/iam.serviceAccountTokenCreator"]) service_account_id = module.tf_cloudbuild_workspace.cloudbuild_sa role = each.value member = "serviceAccount:${reverse(split("/", module.tf_cloudbuild_workspace.cloudbuild_sa))[0]}" } resource "google_organization_iam_member" "builder_organization_browser" { for_each = toset(local.org_ids) member = "serviceAccount:${reverse(split("/", module.tf_cloudbuild_workspace.cloudbuild_sa))[0]}" org_id = each.value role = "roles/browser" } // Create infra project module "app_infra_project" { source = "terraform-google-modules/project-factory/google" version = "~> 18.0" for_each = var.create_infra_project ? var.envs : {} random_project_id = true random_project_id_length = 4 billing_account = each.value.billing_account name = substr("eab-${var.acronym}-${var.service_name}-${each.key}", 0, 25) # max length 30 chars org_id = each.value.org_id folder_id = each.value.folder_id activate_apis = var.infra_project_apis deletion_policy = "DELETE" default_service_account = "KEEP" vpc_service_control_attach_dry_run = var.service_perimeter_name != null && var.service_perimeter_mode == "DRY_RUN" vpc_service_control_attach_enabled = var.service_perimeter_name != null && var.service_perimeter_mode == "ENFORCE" vpc_service_control_perimeter_name = var.service_perimeter_name svpc_host_project_id = each.value.network_project_id } resource "google_project_iam_member" "secretManager_admin" { project = var.cloudbuildv2_repository_config.secret_project_id role = "roles/secretmanager.admin" member = "serviceAccount:${reverse(split("/", module.tf_cloudbuild_workspace.cloudbuild_sa))[0]}" }