From c549739834d5734d9acd654c1ea08d393b8308cb Mon Sep 17 00:00:00 2001 From: Gus Narea Date: Mon, 15 Jan 2024 16:44:16 +0000 Subject: [PATCH] Belgium: Create MongoDB Atlas project --- .../README.md | 9 ++ .../serverless_environment_workspace/gcp.tf | 55 ++++++++++++ .../serverless_environment_workspace/main.tf | 7 ++ .../mongodb.tf | 14 +++ .../outputs.tf | 3 + .../serverless_environment_workspace/tfe.tf | 88 +++++++++++++++++++ .../variables.tf | 37 ++++++++ tf-workspace/environments.tf | 7 +- tf-workspace/terraform.tf | 4 + 9 files changed, 221 insertions(+), 3 deletions(-) create mode 100644 tf-modules/serverless_environment_workspace/README.md create mode 100644 tf-modules/serverless_environment_workspace/gcp.tf create mode 100644 tf-modules/serverless_environment_workspace/main.tf create mode 100644 tf-modules/serverless_environment_workspace/mongodb.tf create mode 100644 tf-modules/serverless_environment_workspace/outputs.tf create mode 100644 tf-modules/serverless_environment_workspace/tfe.tf create mode 100644 tf-modules/serverless_environment_workspace/variables.tf diff --git a/tf-modules/serverless_environment_workspace/README.md b/tf-modules/serverless_environment_workspace/README.md new file mode 100644 index 00000000..b7f836e4 --- /dev/null +++ b/tf-modules/serverless_environment_workspace/README.md @@ -0,0 +1,9 @@ +# Terraform Cloud workspace for a single Public Gateway environment + +We're creating separate workspaces for each environment in order to: + +1. Be able to manipulate the Terraform state when things go awry. +1. Make it easier to review Terraform plans. +1. Speed up operations such as planning. + +Unfortunately, when creating an instance of this module, you have to manually enable the VCS connection to GitHub from the Terraform Cloud web console. diff --git a/tf-modules/serverless_environment_workspace/gcp.tf b/tf-modules/serverless_environment_workspace/gcp.tf new file mode 100644 index 00000000..5927391e --- /dev/null +++ b/tf-modules/serverless_environment_workspace/gcp.tf @@ -0,0 +1,55 @@ +resource "random_id" "gcp_project_id_suffix" { + byte_length = 2 +} + +resource "google_project" "main" { + name = var.name + project_id = "gw-${var.name}-${random_id.gcp_project_id_suffix.hex}" // <= 30 chars long + folder_id = var.gcp_parent_folder + billing_account = var.gcp_billing_account +} + +resource "google_project_service" "cloudbilling" { + project = google_project.main.project_id + service = "cloudbilling.googleapis.com" + disable_dependent_services = true +} + +resource "google_project_service" "cloudresourcemanager" { + project = google_project.main.project_id + service = "cloudresourcemanager.googleapis.com" + disable_dependent_services = true +} + +resource "google_project_service" "serviceusage" { + project = google_project.main.project_id + service = "serviceusage.googleapis.com" + disable_dependent_services = true +} + +resource "google_service_account" "tfe" { + account_id = "tf-cloud" + project = google_project.main.project_id + + depends_on = [google_project_service.cloudbilling] +} + +resource "google_project_iam_binding" "tfe_owner" { + project = google_project.main.project_id + role = "roles/owner" + members = ["serviceAccount:${google_service_account.tfe.email}"] +} + +resource "google_project_iam_member" "tfe_shared_dns" { + project = var.shared_infra_gcp_project_id + role = "roles/dns.admin" + member = "serviceAccount:${google_service_account.tfe.email}" +} + +resource "google_service_account_key" "tfe" { + service_account_id = google_service_account.tfe.name +} + +resource "google_service_account_key" "main" { + service_account_id = google_service_account.tfe.name +} diff --git a/tf-modules/serverless_environment_workspace/main.tf b/tf-modules/serverless_environment_workspace/main.tf new file mode 100644 index 00000000..4443a7d6 --- /dev/null +++ b/tf-modules/serverless_environment_workspace/main.tf @@ -0,0 +1,7 @@ +terraform { + required_providers { + mongodbatlas = { + source = "mongodb/mongodbatlas" + } + } +} diff --git a/tf-modules/serverless_environment_workspace/mongodb.tf b/tf-modules/serverless_environment_workspace/mongodb.tf new file mode 100644 index 00000000..8db8e60f --- /dev/null +++ b/tf-modules/serverless_environment_workspace/mongodb.tf @@ -0,0 +1,14 @@ +resource "mongodbatlas_project" "main" { + name = "gateway-${var.name}" + org_id = var.mongodb_atlas_org_id +} + +resource "mongodbatlas_project_api_key" "main" { + project_id = mongodbatlas_project.main.id + description = "Used in Terraform Cloud workspace ${tfe_workspace.main.name}" + + project_assignment { + project_id = mongodbatlas_project.main.id + role_names = ["GROUP_OWNER"] + } +} diff --git a/tf-modules/serverless_environment_workspace/outputs.tf b/tf-modules/serverless_environment_workspace/outputs.tf new file mode 100644 index 00000000..fcb22bea --- /dev/null +++ b/tf-modules/serverless_environment_workspace/outputs.tf @@ -0,0 +1,3 @@ +output "tfe_workspace_id" { + value = tfe_workspace.main.id +} diff --git a/tf-modules/serverless_environment_workspace/tfe.tf b/tf-modules/serverless_environment_workspace/tfe.tf new file mode 100644 index 00000000..9b683769 --- /dev/null +++ b/tf-modules/serverless_environment_workspace/tfe.tf @@ -0,0 +1,88 @@ +data "terraform_remote_state" "root" { + backend = "remote" + + config = { + organization = var.tfe_organization + workspaces = { + name = var.tfe_root_workspace + } + } +} + +data "tfe_oauth_client" "main" { + oauth_client_id = var.tfe_oauth_client_id +} + +resource "tfe_workspace" "main" { + name = "gateway-${var.name}" + organization = var.tfe_organization + + working_directory = "environments/${var.name}" + trigger_prefixes = ["environments/_modules"] + + auto_apply = true + + terraform_version = var.tfe_terraform_version + + vcs_repo { + identifier = var.github_repo + oauth_token_id = data.tfe_oauth_client.main.oauth_token_id + branch = var.github_branch + } +} + +data "tfe_organization_membership" "sres" { + for_each = toset(data.terraform_remote_state.root.outputs.sre_email_addresses) + + organization = var.tfe_organization + email = each.value +} + +resource "tfe_notification_configuration" "sres" { + name = "Notify SREs to anything that needs their attention" + enabled = true + destination_type = "email" + email_user_ids = [for sre in data.tfe_organization_membership.sres : sre.user_id] + triggers = ["run:needs_attention", "run:errored"] + workspace_id = tfe_workspace.main.id +} + +resource "tfe_variable" "gcp_credentials" { + workspace_id = tfe_workspace.main.id + + category = "env" + sensitive = true + key = "GOOGLE_CREDENTIALS" + description = google_service_account.tfe.email + + // Remove new line characters as a workaround for + // https://github.com/hashicorp/terraform/issues/22796 + value = jsonencode( + jsondecode(base64decode(google_service_account_key.main.private_key)) + ) +} + +resource "tfe_variable" "gcp_project_id" { + workspace_id = tfe_workspace.main.id + + category = "terraform" + key = "gcp_project_id" + value = google_project.main.project_id +} + +resource "tfe_variable" "mongodbatlas_private_key" { + workspace_id = tfe_workspace.main.id + + category = "env" + sensitive = true + key = "MONGODB_ATLAS_PRIVATE_KEY" + value = mongodbatlas_project_api_key.main.private_key +} + +resource "tfe_variable" "mongodbatlas_public_key" { + workspace_id = tfe_workspace.main.id + + category = "env" + key = "MONGODB_ATLAS_PUBLIC_KEY" + value = mongodbatlas_project_api_key.main.public_key +} diff --git a/tf-modules/serverless_environment_workspace/variables.tf b/tf-modules/serverless_environment_workspace/variables.tf new file mode 100644 index 00000000..6f663cb4 --- /dev/null +++ b/tf-modules/serverless_environment_workspace/variables.tf @@ -0,0 +1,37 @@ +variable "name" { + description = "Environment name" +} + +variable "shared_infra_gcp_project_id" {} +variable "gcp_parent_folder" {} +variable "gcp_billing_account" {} + +variable "mongodb_atlas_org_id" { + default = null // Take from variable set +} +variable "env_mongodb_atlas_public_key" { + default = null // Take from variable set +} +variable "env_mongodb_atlas_private_key" { + default = null // Take from variable set +} + +variable "tfe_organization" { + default = "Relaycorp" +} +variable "tfe_root_workspace" { + default = "cloud-gateway" +} +variable "tfe_oauth_client_id" { + default = "oc-7jBF4Z5YhNc4QRSc" +} +variable "tfe_terraform_version" { + default = "1.2.4" +} + +variable "github_repo" { + default = "relaycorp/cloud-gateway" +} +variable "github_branch" { + default = "main" +} diff --git a/tf-workspace/environments.tf b/tf-workspace/environments.tf index 882f263e..fe24814b 100644 --- a/tf-workspace/environments.tf +++ b/tf-workspace/environments.tf @@ -10,14 +10,15 @@ module "env_frankfurt" { } module "env_belgium" { - source = "../tf-modules/environment_workspace" + source = "../tf-modules/serverless_environment_workspace" name = "belgium" tfe_terraform_version = "1.6.6" - gcp_parent_folder = var.gcp_parent_folder - gcp_billing_account = var.gcp_billing_account + gcp_parent_folder = var.gcp_parent_folder + gcp_billing_account = var.gcp_billing_account + mongodb_atlas_org_id = var.mongodb_atlas_org_id shared_infra_gcp_project_id = data.google_project.main.project_id } diff --git a/tf-workspace/terraform.tf b/tf-workspace/terraform.tf index 39a1c86e..ac1ad799 100644 --- a/tf-workspace/terraform.tf +++ b/tf-workspace/terraform.tf @@ -20,6 +20,10 @@ terraform { source = "hashicorp/tfe" version = "~> 0.32.1" } + mongodbatlas = { + source = "mongodb/mongodbatlas" + version = "~> 1.10.2" + } } required_version = ">= 1.1.2" }