From 96dbf439b3da5abe52c11416b0f041bcb92705b1 Mon Sep 17 00:00:00 2001 From: cortadocodes Date: Fri, 1 Dec 2023 16:09:00 +0000 Subject: [PATCH] OPS: Add terraform config --- .gitignore | 3 + terraform/.gitignore | 2 + terraform/artifact_registry.tf | 6 ++ terraform/iam.tf | 143 +++++++++++++++++++++++++++++++++ terraform/main.tf | 98 ++++++++++++++++++++++ terraform/secrets.tf | 17 ++++ terraform/storage.tf | 6 ++ terraform/variables.tf | 39 +++++++++ 8 files changed, 314 insertions(+) create mode 100644 terraform/.gitignore create mode 100644 terraform/artifact_registry.tf create mode 100644 terraform/iam.tf create mode 100644 terraform/main.tf create mode 100644 terraform/secrets.tf create mode 100644 terraform/storage.tf create mode 100644 terraform/variables.tf diff --git a/.gitignore b/.gitignore index 2613ec5..a2809de 100644 --- a/.gitignore +++ b/.gitignore @@ -109,3 +109,6 @@ ENV/ *.sum .DS_Store .octue + +gcp-credentials.json +.terraform* diff --git a/terraform/.gitignore b/terraform/.gitignore new file mode 100644 index 0000000..a1bcc42 --- /dev/null +++ b/terraform/.gitignore @@ -0,0 +1,2 @@ +gcp-credentials.json +.terraform* diff --git a/terraform/artifact_registry.tf b/terraform/artifact_registry.tf new file mode 100644 index 0000000..87f8e28 --- /dev/null +++ b/terraform/artifact_registry.tf @@ -0,0 +1,6 @@ +resource "google_artifact_registry_repository" "artifact_registry_repository" { + location = var.region + repository_id = "${var.service_namespace}" + description = "Docker image repository" + format = "DOCKER" +} diff --git a/terraform/iam.tf b/terraform/iam.tf new file mode 100644 index 0000000..0044442 --- /dev/null +++ b/terraform/iam.tf @@ -0,0 +1,143 @@ +# You need to start with a service account called "terraform" which has both the 'editor' and 'owner' basic permissions. +# This allows it to assign permissions to resources per https://cloud.google.com/iam/docs/understanding-roles +# +# To create domain-named storage buckets using terraform, you first have to verify ownership of the root domain, or +# "property", (eg octue.com) using the google search console. Once verified, you need to add the service account with +# which terraform acts ( eg terraform@octue-amy.iam.gserviceaccount.com ) to Google Search Console > Settings > Users +# and Permissions, with "Owner" level permission. + +resource "google_service_account" "openfast_service_service_account" { + account_id = "openfast-service" + display_name = "openfast-service" + description = "Operate the 'octue/openfast' Cloud Run service." + project = var.project +} + + +resource "google_service_account" "github_actions_service_account" { + account_id = "github-actions" + description = "Allow GitHub Actions to deploy code onto resources and run integration tests and jobs via reverse shelling." + display_name = "github-actions" + project = var.project +} + + +resource "google_service_account" "dev_cortadocodes_service_account" { + account_id = "dev-cortadocodes" + description = "Allow cortadocodes to test the cloud run instance." + display_name = "dev-cortadocodes" + project = var.project +} + + +resource "google_project_iam_binding" "iam_serviceaccountuser" { + project = var.project + role = "roles/iam.serviceAccountUser" + members = [ + "serviceAccount:${google_service_account.openfast_service_service_account.email}", + "serviceAccount:${google_service_account.github_actions_service_account.email}", + ] +} + + +resource "google_project_iam_binding" "pubsub_editor" { + project = var.project + role = "roles/pubsub.editor" + members = [ + "serviceAccount:${google_service_account.openfast_service_service_account.email}", + "serviceAccount:${google_service_account.github_actions_service_account.email}", + "serviceAccount:${google_service_account.dev_cortadocodes_service_account.email}" + ] +} + + +# Allows the GHA to call "namespaces get" for Cloud Run to determine the resulting run URLs of the services. +# This should also allow a service to get its own name by using: +# https://stackoverflow.com/questions/65628822/google-cloud-run-can-a-service-know-its-own-url/65634104#65634104 +resource "google_project_iam_binding" "run_developer" { + project = var.project + role = "roles/run.developer" + members = [ + "serviceAccount:${google_service_account.openfast_service_service_account.email}", + "serviceAccount:${google_service_account.github_actions_service_account.email}", + ] +} + + +resource "google_project_iam_binding" "artifactregistry_writer" { + project = var.project + role = "roles/artifactregistry.writer" + members = [ + "serviceAccount:${google_service_account.github_actions_service_account.email}", + ] +} + + +resource "google_project_iam_binding" "storage_objectadmin" { + project = var.project + role = "roles/storage.objectAdmin" + members = [ + "serviceAccount:${google_service_account.openfast_service_service_account.email}", + "serviceAccount:${google_service_account.github_actions_service_account.email}", + "serviceAccount:${var.project_number}@cloudbuild.gserviceaccount.com", + ] +} + + +resource "google_project_iam_binding" "errorreporting_writer" { + project = var.project + role = "roles/errorreporting.writer" + members = [ + "serviceAccount:${google_service_account.openfast_service_service_account.email}", + ] +} + + +#resource "google_project_iam_binding" "secretmanager_secretaccessor" { +# project = var.project +# role = "roles/secretmanager.secretAccessor" +# members = [ +# "serviceAccount:${google_service_account.elevations_api_service_account.email}", +# ] +#} + + +resource "google_iam_workload_identity_pool" "github_actions_pool" { + display_name = "github-actions-pool" + project = var.project + workload_identity_pool_id = "github-actions-pool" +} + + +resource "google_iam_workload_identity_pool_provider" "github_actions_provider" { + attribute_mapping = { + "attribute.actor" = "assertion.actor" + "attribute.repository" = "assertion.repository" + "attribute.repository_owner" = "assertion.repository_owner" + "google.subject" = "assertion.sub" + } + display_name = "Github Actions Provider" + project = var.project_number + workload_identity_pool_id = "github-actions-pool" + workload_identity_pool_provider_id = "github-actions-provider" + + oidc { + allowed_audiences = [] + issuer_uri = "https://token.actions.githubusercontent.com" + } +} + +data "google_iam_policy" "github_actions_workload_identity_pool_policy" { + binding { + role = "roles/iam.workloadIdentityUser" + members = [ + "principalSet://iam.googleapis.com/projects/${var.project_number}/locations/global/workloadIdentityPools/${google_iam_workload_identity_pool.github_actions_pool.workload_identity_pool_id}/attribute.repository_owner/${var.github_organisation}" + ] + } +} + +// Allow a machine under Workload Identity Federation to act as the given service account +resource "google_service_account_iam_policy" "github_actions_workload_identity_service_account_policy" { + service_account_id = google_service_account.github_actions_service_account.name + policy_data = data.google_iam_policy.github_actions_workload_identity_pool_policy.policy_data +} diff --git a/terraform/main.tf b/terraform/main.tf new file mode 100644 index 0000000..d295649 --- /dev/null +++ b/terraform/main.tf @@ -0,0 +1,98 @@ +terraform { + required_providers { + google = { + source = "hashicorp/google" + version = "4.53.1" + } + } + cloud { + organization = "octue" + workspaces { + name = "octue-openfast" + } + } +} + + +resource "google_project_service" "pub_sub" { + project = var.project + service = "pubsub.googleapis.com" + + timeouts { + create = "30m" + update = "40m" + } +} + + +resource "google_project_service" "cloud_resource_manager" { + project = var.project + service = "cloudresourcemanager.googleapis.com" + + timeouts { + create = "30m" + update = "40m" + } +} + + +resource "google_project_service" "iam" { + project = var.project + service = "iam.googleapis.com" + + timeouts { + create = "30m" + update = "40m" + } +} + + +resource "google_project_service" "artifact_registry" { + project = var.project + service = "artifactregistry.googleapis.com" + + timeouts { + create = "30m" + update = "40m" + } +} + + +resource "google_project_service" "cloud_run" { + project = var.project + service = "run.googleapis.com" + + timeouts { + create = "30m" + update = "40m" + } +} + + +resource "google_project_service" "secret_manager" { + project = var.project + service = "secretmanager.googleapis.com" + + timeouts { + create = "30m" + update = "40m" + } +} + +# +#resource "google_project_service" "cloud_build" { +# project = var.project +# service = "cloudbuild.googleapis.com" +# +# timeouts { +# create = "30m" +# update = "40m" +# } +#} + + +provider "google" { + credentials = file(var.credentials_file) + project = var.project + region = var.region +} diff --git a/terraform/secrets.tf b/terraform/secrets.tf new file mode 100644 index 0000000..571121e --- /dev/null +++ b/terraform/secrets.tf @@ -0,0 +1,17 @@ +#variable "secret_names" { +# description = "A list of secrets to be created and made accessible to the cloud run instance." +# type = list(string) +# default = [ +# "neo4j-uri", +# "neo4j-username", +# "neo4j-password", +# ] +#} +# +#resource "google_secret_manager_secret" "secrets" { +# count = length(var.secret_names) +# secret_id = "${var.service_namespace}-${var.service_name}-${var.environment}-${var.secret_names[count.index]}" +# replication { +# automatic = true +# } +#} diff --git a/terraform/storage.tf b/terraform/storage.tf new file mode 100644 index 0000000..67f9805 --- /dev/null +++ b/terraform/storage.tf @@ -0,0 +1,6 @@ +resource "google_storage_bucket" "crash_diagnostics" { + name = "${var.service_namespace}-${var.service_name}" + location = "EU" + force_destroy = true + uniform_bucket_level_access = true +} diff --git a/terraform/variables.tf b/terraform/variables.tf new file mode 100644 index 0000000..711dbc1 --- /dev/null +++ b/terraform/variables.tf @@ -0,0 +1,39 @@ +variable "project" { + type = string + default = "octue-openfast" +} + +variable "project_number" { + type = string + default = "86611255144" +} + +variable "region" { + type = string + default = "europe-west3" +} + +variable "github_organisation" { + type = string + default = "octue" +} + +variable "credentials_file" { + type = string + default = "gcp-credentials.json" +} + +variable "service_namespace" { + type = string + default = "octue" +} + +variable "service_name" { + type = string + default = "openfast-service" +} + +variable "environment" { + type = string + default = "main" +}