Skip to content

Commit

Permalink
Terraform for GCP CI base (#144)
Browse files Browse the repository at this point in the history
  • Loading branch information
AlCutter authored Aug 20, 2024
1 parent e75cec5 commit 38226b6
Show file tree
Hide file tree
Showing 8 changed files with 197 additions and 16 deletions.
2 changes: 1 addition & 1 deletion deployment/live/gcp/example-gcp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,6 @@ export TESSERA_BASE_NAME={VALUE}
```

Terraforming the project can be done by:
1. `cd` to the relevant `live` directory for the environment to deploy/change
1. `cd` to the relevant directory for the environment to deploy/change (e.g. `ci`)
2. Run `terragrunt apply`

16 changes: 16 additions & 0 deletions deployment/live/gcp/example-gcp/ci/terragrunt.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
terraform {
source = "${get_repo_root()}/deployment/modules/gcp//example-gcp"
}

include "root" {
path = find_in_parent_folders()
expose = true
}

inputs = merge(
include.root.locals,
{
example_gcp_docker_image = "us-central1-docker.pkg.dev/trillian-tessera/docker-prod/example-gcp:latest"
log_origin = "example-gcp"
}
)
15 changes: 6 additions & 9 deletions deployment/live/gcp/example-gcp/terragrunt.hcl
Original file line number Diff line number Diff line change
@@ -1,25 +1,22 @@
terraform {
source = "${get_repo_root()}/deployment/modules/gcp/gcs"
source = "${get_repo_root()}/deployment/modules/gcp//example-gcp"
}

locals {
project_id = get_env("GOOGLE_PROJECT", "trillian-tessera")
location = get_env("GOOGLE_REGION", "us-central1")
base_name = get_env("TESSERA_BASE_NAME", "example-gcp")
env = path_relative_to_include()
project_id = get_env("GOOGLE_PROJECT", "trillian-tessera")
location = get_env("GOOGLE_REGION", "us-central1")
base_name = get_env("TESSERA_BASE_NAME", "${local.env}-example-gcp")
}

inputs = merge(
local,
{}
)

remote_state {
backend = "gcs"

config = {
project = local.project_id
location = local.location
bucket = "${local.project_id}-${local.base_name}-terraform-state"
prefix = "${local.env}/terraform.tfstate"

gcs_bucket_labels = {
name = "terraform_state_storage"
Expand Down
133 changes: 133 additions & 0 deletions deployment/modules/gcp/example-gcp/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
terraform {
backend "gcs" {}
}

## Call the Tessera GCP module
##
## This will configure all the storage infrastructure required to run a Tessera log on GCP.
module "gcs" {
source = "..//gcs"

base_name = var.base_name
env = var.env
location = var.location
project_id = var.project_id
}

##
## Resources
##

# Enable Cloud Run API
resource "google_project_service" "cloudrun_api" {
service = "run.googleapis.com"
disable_on_destroy = false
}
resource "google_project_service" "cloudkms_googleapis_com" {
service = "cloudkms.googleapis.com"
}

##
## KMS for log signing
##
resource "google_kms_key_ring" "log_signer" {
location = var.location
name = var.base_name
}

resource "google_kms_crypto_key" "log_signer" {
key_ring = google_kms_key_ring.log_signer.id
name = "log_signer"
purpose = "ASYMMETRIC_SIGN"
version_template {
algorithm = "EC_SIGN_ED25519"
}
}
resource "google_kms_crypto_key_version" "log_signer" {
crypto_key = google_kms_crypto_key.log_signer.id
}

###
### Set up Cloud Run service
###
resource "google_service_account" "cloudrun_service_account" {
account_id = "cloudrun-${var.env}-sa"
display_name = "Service Account for Cloud Run (${var.env})"
}

resource "google_project_iam_member" "iam_act_as" {
project = var.project_id
role = "roles/iam.serviceAccountUser"
member = "serviceAccount:${google_service_account.cloudrun_service_account.email}"
}
resource "google_project_iam_member" "iam_metrics_writer" {
project = var.project_id
role = "roles/monitoring.metricWriter"
member = "serviceAccount:${google_service_account.cloudrun_service_account.email}"
}
resource "google_spanner_database_iam_binding" "iam_spanner_database_user" {
project = var.project_id
instance = module.gcs.log_spanner_instance.name
database = module.gcs.log_spanner_db.name
role = "roles/spanner.databaseUser"

members = [
"serviceAccount:${google_service_account.cloudrun_service_account.email}"
]
}
resource "google_project_iam_member" "iam_service_agent" {
project = var.project_id
role = "roles/run.serviceAgent"
member = "serviceAccount:${google_service_account.cloudrun_service_account.email}"
}

locals {
spanner_db_full = "projects/${var.project_id}/instances/${module.gcs.log_spanner_instance.name}/databases/${module.gcs.log_spanner_db.name}"
}

resource "google_cloud_run_v2_service" "default" {
name = "example-service-${var.env}"
location = var.location
launch_stage = "GA"

template {
service_account = google_service_account.cloudrun_service_account.email
containers {
image = var.example_gcp_docker_image
name = "example-gcp"
args = [
"--logtostderr",
"--v=1",
"--bucket=${module.gcs.log_bucket.id}",
"--spanner=${local.spanner_db_full}",
"--project=${var.project_id}",
"--listen=:8080",
"--kms_key=${google_kms_crypto_key_version.log_signer.id}",
"--origin=${var.log_origin}",
]
ports {
container_port = 8080
}

startup_probe {
initial_delay_seconds = 1
timeout_seconds = 1
period_seconds = 10
failure_threshold = 3
tcp_socket {
port = 8080
}
}
}
}
client = "terraform"
depends_on = [
module.gcs,
google_project_service.cloudrun_api,
google_project_iam_member.iam_act_as,
google_project_iam_member.iam_metrics_writer,
google_project_iam_member.iam_service_agent,
google_spanner_database_iam_binding.iam_spanner_database_user,
]
}

29 changes: 29 additions & 0 deletions deployment/modules/gcp/example-gcp/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
variable "project_id" {
description = "GCP project ID where the log is hosted"
type = string
}

variable "base_name" {
description = "Base name to use when naming resources"
type = string
}

variable "location" {
description = "Location in which to create resources"
type = string
}

variable "env" {
description = "Environment name, e.g ci, prod, etc."
type = string
}

variable "example_gcp_docker_image" {
description = "The full image URL (path & tag) for the example-gcp Docker image to deploy"
type = string
}

variable "log_origin" {
description = "The origin string for the example log"
type = string
}
6 changes: 1 addition & 5 deletions deployment/modules/gcp/gcs/main.tf
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
terraform {
backend "gcs" {}
}

# Services
resource "google_project_service" "serviceusage_googleapis_com" {
service = "serviceusage.googleapis.com"
Expand Down Expand Up @@ -52,7 +48,7 @@ resource "google_storage_bucket_iam_binding" "log_bucket_writer" {
resource "google_spanner_instance" "log_spanner" {
name = var.base_name
config = "regional-${var.location}"
display_name = "${var.base_name} Spanner Instance"
display_name = var.base_name
processing_units = 100
}

Expand Down
7 changes: 6 additions & 1 deletion deployment/modules/gcp/gcs/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,16 @@ output "log_bucket" {
value = google_storage_bucket.log_bucket
}

output "log_spanner" {
output "log_spanner_db" {
description = "Log Spanner database"
value = google_spanner_database.log_db
}

output "log_spanner_instance" {
description = "Log Spanner instance"
value = google_spanner_instance.log_spanner
}

output "service_account_name" {
description = "Name of the service account with write permission for storage"
value = google_service_account.log_writer.member
Expand Down
5 changes: 5 additions & 0 deletions deployment/modules/gcp/gcs/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,8 @@ variable "location" {
description = "Location in which to create resources"
type = string
}

variable "env" {
description = "Unique identifier for the env, e.g. ci or prod"
type = string
}

0 comments on commit 38226b6

Please sign in to comment.