0-bootstrap/builders/tf.cloud/terraform_cloud.tf (259 lines of code) (raw):

/** * Copyright 2023 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 "tfe" { token = var.tfc_token } locals { cicd_project_id = module.tfc_cicd.project_id tfc_org_name = var.tfc_org_name tfc_projects = { "bootstrap" = { vcs_repo = var.vcs_repos.bootstrap, }, "org" = { vcs_repo = var.vcs_repos.organization, }, "env" = { vcs_repo = var.vcs_repos.environments, }, "net" = { vcs_repo = var.vcs_repos.networks, }, "proj" = { vcs_repo = var.vcs_repos.projects, }, } tfc_workspaces = { "bootstrap" = { "0-shared" = { vcs_branch = "production", directory = "/envs/shared" } }, "org" = { "1-shared" = { vcs_branch = "production", directory = "/envs/shared" } }, "env" = { "2-production" = { vcs_branch = "production", directory = "/envs/production" }, "2-nonproduction" = { vcs_branch = "nonproduction", directory = "/envs/nonproduction" }, "2-development" = { vcs_branch = "development", directory = "/envs/development" }, }, "net" = { "3-production" = { vcs_branch = "production", directory = "/envs/production" }, "3-nonproduction" = { vcs_branch = "nonproduction", directory = "/envs/nonproduction" }, "3-development" = { vcs_branch = "development", directory = "/envs/development" }, "3-shared" = { vcs_branch = "production", directory = "/envs/shared" }, }, "proj" = { "4-bu1-production" = { vcs_branch = "production", directory = "/business_unit_1/production" }, "4-bu1-nonproduction" = { vcs_branch = "nonproduction", directory = "/business_unit_1/nonproduction" }, "4-bu1-development" = { vcs_branch = "development", directory = "/business_unit_1/development" }, "4-bu1-shared" = { vcs_branch = "production", directory = "/business_unit_1/shared" }, "4-bu2-production" = { vcs_branch = "production", directory = "/business_unit_2/production" }, "4-bu2-nonproduction" = { vcs_branch = "nonproduction", directory = "/business_unit_2/nonproduction" }, "4-bu2-development" = { vcs_branch = "development", directory = "/business_unit_2/development" }, "4-bu2-shared" = { vcs_branch = "production", directory = "/business_unit_2/shared" }, }, } tfc_workspaces_flat = flatten([ for project, workspaces in local.tfc_workspaces : [ for name, config in workspaces : { name = name project = project working_directory = config["directory"] branch = config["vcs_branch"] } ] ] ) tfc_workspace_map = { for v in local.tfc_workspaces_flat : v.name => v } sa_mapping = { for k, v in local.tfc_projects : k => { sa_name = google_service_account.terraform-env-sa[k].name sa_email = google_service_account.terraform-env-sa[k].email attribute = "*" } } tfc_agent_pool = "${var.tfc_agent_pool_name}-${random_string.suffix.result}" workspaces_execution_mode = var.enable_tfc_cloud_agents == true ? "agent" : "remote" workspaces_agent_pool_id = var.enable_tfc_cloud_agents == true ? tfe_agent_pool.tfc_agent_pool[0].id : "" } resource "tfe_project" "main" { for_each = local.tfc_projects organization = local.tfc_org_name name = each.key } resource "tfe_workspace" "main" { for_each = local.tfc_workspace_map organization = local.tfc_org_name name = each.value.name working_directory = each.value.working_directory project_id = tfe_project.main[each.value.project].id global_remote_state = true terraform_version = var.tfc_terraform_version agent_pool_id = local.workspaces_agent_pool_id execution_mode = local.workspaces_execution_mode vcs_repo { identifier = local.tfc_projects[each.value.project].vcs_repo branch = each.value.branch oauth_token_id = var.vcs_oauth_token_id } } data "tfe_workspace" "main" { for_each = local.tfc_workspace_map name = each.value.name organization = local.tfc_org_name depends_on = [tfe_workspace.main] } resource "tfe_variable_set" "main" { name = "Terraform Cloud Keys Varset" description = "A resource that allows you to reuse the same variables across multiple workspaces" global = false organization = local.tfc_org_name } resource "tfe_variable" "tfc_oauth_id_vcs" { key = "vcs_oauth_token_id" value = var.vcs_oauth_token_id category = "terraform" description = "The VCS Connection OAuth Connection Token ID" workspace_id = tfe_workspace.main["0-shared"].id sensitive = true } resource "tfe_variable" "tfc_token" { key = "tfc_token" value = var.tfc_token category = "terraform" description = "The token used to authenticate with Terraform Cloud" workspace_id = tfe_workspace.main["0-shared"].id sensitive = true } resource "tfe_variable" "tfc_terraform_version" { key = "tfc_terraform_version" value = var.tfc_terraform_version category = "terraform" description = "TF version desired for TFC workspaces" workspace_id = tfe_workspace.main["0-shared"].id } resource "tfe_variable" "tfc_organization_name" { key = "tfc_org_name" value = var.tfc_org_name category = "terraform" description = "Name of the TFC organization" variable_set_id = tfe_variable_set.main.id } resource "tfe_variable" "gcp_provider_auth" { key = "TFC_GCP_PROVIDER_AUTH" value = "true" category = "env" description = "If true TFC will attempt to use dynamic credentials to authenticate to GCP" variable_set_id = tfe_variable_set.main.id } resource "tfe_variable" "gcp_workload_provider_name" { key = "TFC_GCP_WORKLOAD_PROVIDER_NAME" value = module.tfc-oidc.provider_name category = "env" description = "The canonical name of the workload identity provider." variable_set_id = tfe_variable_set.main.id } resource "tfe_variable" "service_account_email" { for_each = local.tfc_workspace_map key = "TFC_GCP_RUN_SERVICE_ACCOUNT_EMAIL" value = google_service_account.terraform-env-sa[each.value.project].email category = "env" description = "The service account email to use for the plan phase of a run." workspace_id = tfe_workspace.main[each.key].id } resource "tfe_workspace_variable_set" "main" { for_each = local.tfc_workspace_map variable_set_id = tfe_variable_set.main.id workspace_id = tfe_workspace.main[each.key].id } resource "tfe_run_trigger" "networks_shared_production" { workspace_id = tfe_workspace.main["3-production"].id sourceable_id = tfe_workspace.main["3-shared"].id } resource "tfe_run_trigger" "projects_bu1_shared_production" { workspace_id = tfe_workspace.main["4-bu1-production"].id sourceable_id = tfe_workspace.main["4-bu1-shared"].id } resource "tfe_run_trigger" "projects_bu2_shared_production" { workspace_id = tfe_workspace.main["4-bu2-production"].id sourceable_id = tfe_workspace.main["4-bu2-shared"].id } module "tfc_cicd" { source = "terraform-google-modules/project-factory/google" version = "~> 12.0" name = "${var.project_prefix}-b-cicd-wif-tfc" random_project_id = true org_id = var.org_id folder_id = google_folder.bootstrap.id billing_account = var.billing_account activate_apis = [ "compute.googleapis.com", "admin.googleapis.com", "iam.googleapis.com", "billingbudgets.googleapis.com", "cloudbilling.googleapis.com", "serviceusage.googleapis.com", "cloudresourcemanager.googleapis.com", "iamcredentials.googleapis.com", "container.googleapis.com", "gkeconnect.googleapis.com", "gkehub.googleapis.com", "connectgateway.googleapis.com" ] } module "tfc-oidc" { source = "GoogleCloudPlatform/tf-cloud-agents/google//modules/tfc-oidc" version = "0.1.0" project_id = module.tfc_cicd.project_id pool_id = "foundation-pool" provider_id = "foundation-tfc-provider" sa_mapping = local.sa_mapping tfc_organization_name = local.tfc_org_name attribute_condition = "assertion.sub.startsWith(\"organization:${local.tfc_org_name}:\")" } data "google_client_config" "default" { } resource "random_string" "suffix" { length = 4 special = false upper = false } # Create a new agent pool in organization resource "tfe_agent_pool" "tfc_agent_pool" { count = var.enable_tfc_cloud_agents == true ? 1 : 0 name = local.tfc_agent_pool organization = local.tfc_org_name } # Create a new token for the agent pool resource "tfe_agent_token" "tfc_agent_token" { count = var.enable_tfc_cloud_agents == true ? 1 : 0 agent_pool_id = tfe_agent_pool.tfc_agent_pool[0].id description = var.tfc_agent_pool_token_description } # Create the infrastructure for the agent to run module "tfc_agent_gke" { source = "./modules/tfc-agent-gke" count = var.enable_tfc_cloud_agents == true ? 1 : 0 project_id = module.tfc_cicd.project_id project_number = module.tfc_cicd.project_number tfc_agent_token = tfe_agent_token.tfc_agent_token[0].token create_service_account = false service_account_email = google_service_account.terraform-env-sa["bootstrap"].email service_account_id = google_service_account.terraform-env-sa["bootstrap"].id //If you are using Terraform Cloud Agents, un-comment this block after the first apply according README instructions # providers = { # kubernetes = kubernetes # } } resource "google_service_account_iam_member" "self_impersonate" { for_each = local.granular_sa service_account_id = google_service_account.terraform-env-sa[each.key].id role = "roles/iam.serviceAccountTokenCreator" member = "serviceAccount:${google_service_account.terraform-env-sa[each.key].email}" }