From c65f27721999262bbd9755df3738171d43d63869 Mon Sep 17 00:00:00 2001 From: Al Cutter Date: Wed, 11 Sep 2024 18:16:44 +0100 Subject: [PATCH] [GCP] conformance terraform (#227) --- deployment/live/gcp/cloudbuild/README.md | 4 +- .../live/gcp/cloudbuild/prod/terragrunt.hcl | 2 + deployment/live/gcp/cloudbuild/terragrunt.hcl | 2 +- deployment/live/gcp/conformance/README.md | 21 ++- .../live/gcp/conformance/terragrunt.hcl | 14 +- deployment/modules/gcp/cloudbuild/main.tf | 127 ++++++++++++------ deployment/modules/gcp/cloudbuild/outputs.tf | 2 +- .../modules/gcp/cloudbuild/variables.tf | 12 ++ deployment/modules/gcp/conformance/main.tf | 90 ++++++++----- deployment/modules/gcp/conformance/outputs.tf | 9 ++ .../modules/gcp/conformance/variables.tf | 15 +++ deployment/modules/gcp/gcs/main.tf | 9 ++ deployment/modules/gcp/gcs/variables.tf | 6 + 13 files changed, 228 insertions(+), 85 deletions(-) create mode 100644 deployment/modules/gcp/conformance/outputs.tf diff --git a/deployment/live/gcp/cloudbuild/README.md b/deployment/live/gcp/cloudbuild/README.md index bee77c57..d040fa7e 100644 --- a/deployment/live/gcp/cloudbuild/README.md +++ b/deployment/live/gcp/cloudbuild/README.md @@ -6,8 +6,8 @@ define the necessary triggers and steps in GCB. These steps will: 1. Trigger on a change to the `main` branch of the trillian-tessera repo - 2. Build the `example-gcp` docker image from the `main` branch - 3. Publish this docker image in artifact repository + 2. Build the `cmd/gcp/conformance` docker image from the `main` branch + 3. Run conformance tests. The first time this is run for a pair of {GCP Project, GitHub Repo} you will get an error message such as the following: diff --git a/deployment/live/gcp/cloudbuild/prod/terragrunt.hcl b/deployment/live/gcp/cloudbuild/prod/terragrunt.hcl index 22da2c1b..bfa6b083 100644 --- a/deployment/live/gcp/cloudbuild/prod/terragrunt.hcl +++ b/deployment/live/gcp/cloudbuild/prod/terragrunt.hcl @@ -6,5 +6,7 @@ include "root" { inputs = merge( include.root.locals, { + kms_key_version_id = get_env("TESSERA_KMS_KEY_VERSION", "projects/${include.root.locals.project_id}/locations/${include.root.locals.region}/keyRings/ci-conformance/cryptoKeys/log-signer/cryptoKeyVersions/1") + log_origin = "ci-conformance" } ) diff --git a/deployment/live/gcp/cloudbuild/terragrunt.hcl b/deployment/live/gcp/cloudbuild/terragrunt.hcl index d1bb698b..4ebf2f97 100644 --- a/deployment/live/gcp/cloudbuild/terragrunt.hcl +++ b/deployment/live/gcp/cloudbuild/terragrunt.hcl @@ -1,5 +1,5 @@ terraform { - source = "${get_repo_root()}/deployment/modules/gcp/cloudbuild" + source = "${get_repo_root()}/deployment/modules/gcp//cloudbuild" } locals { diff --git a/deployment/live/gcp/conformance/README.md b/deployment/live/gcp/conformance/README.md index c5c5a0f5..21bba59d 100644 --- a/deployment/live/gcp/conformance/README.md +++ b/deployment/live/gcp/conformance/README.md @@ -1,4 +1,20 @@ -## Deployment +# GCP Conformance Configs + +## Prerequisites + +You'll need to have already configured/created a KMS key which can safely be used by the +conformance log. + +> [Warning] +> This key should not be used elsewhere or be in any way valuable! + +## Automatic deployment + +For the most part, this terragrunt config is automatically used as part conformance +testing by the [CloudBuild](/deployment/live/cloudbuild) pipeline, so doesn't generally +need to be manually applied. + +## Manual deployment First authenticate via `gcloud` as a principle with sufficient ACLs for the project: @@ -6,9 +22,10 @@ the project: gcloud auth application-default login ``` -Set your GCP project ID with: +Set the required environment variables: ```bash export GOOGLE_PROJECT={VALUE} +export TESSERA_KMS_KEY_VERSION={VALUE} # This should be the resource name of the key version created above ``` Optionally, customize the GCP region (defaults to "us-central1"), diff --git a/deployment/live/gcp/conformance/terragrunt.hcl b/deployment/live/gcp/conformance/terragrunt.hcl index bb0b4da7..1c77b85a 100644 --- a/deployment/live/gcp/conformance/terragrunt.hcl +++ b/deployment/live/gcp/conformance/terragrunt.hcl @@ -3,11 +3,15 @@ terraform { } locals { - 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}-conformance") - log_origin = "conformance-gcp-${local.env}" + 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}-conformance") + conformance_gcp_docker_image = "${local.location}-docker.pkg.dev/trillian-tessera/docker-${local.env}/conformance-gcp:latest" + kms_key_version_id = get_env("TESSERA_KMS_KEY_VERSION", "projects/${local.project_id}/locations/${local.location}/keyRings/${local.base_name}/cryptoKeys/log-signer/cryptoKeyVersions/1") + log_origin = local.base_name + conformance_users = ["serviceAccount:cloudbuild-prod-sa@trillian-tessera.iam.gserviceaccount.com"] + bucket_readers = ["serviceAccount:cloudbuild-prod-sa@trillian-tessera.iam.gserviceaccount.com"] } remote_state { diff --git a/deployment/modules/gcp/cloudbuild/main.tf b/deployment/modules/gcp/cloudbuild/main.tf index 52674ee5..ec33e443 100644 --- a/deployment/modules/gcp/cloudbuild/main.tf +++ b/deployment/modules/gcp/cloudbuild/main.tf @@ -1,10 +1,5 @@ terraform { - required_providers { - google = { - source = "hashicorp/google" - version = "5.41.0" - } - } + backend "gcs" {} } provider "google" { @@ -12,21 +7,16 @@ provider "google" { region = var.region } -# This will be configured by terragrunt when deploying -terraform { - backend "gcs" {} -} - resource "google_artifact_registry_repository" "docker" { repository_id = "docker-${var.env}" location = var.region - description = "Tessera example docker images" + description = "Tessera conformance docker images" format = "DOCKER" } locals { - artifact_repo = "${var.region}-docker.pkg.dev/${var.project_id}/${google_artifact_registry_repository.docker.name}" - example_gcp_docker_image = "${local.artifact_repo}/example-gcp" + artifact_repo = "${var.region}-docker.pkg.dev/${var.project_id}/${google_artifact_registry_repository.docker.name}" + conformance_gcp_docker_image = "${local.artifact_repo}/conformance-gcp" } resource "google_cloudbuild_trigger" "docker" { @@ -43,55 +33,110 @@ resource "google_cloudbuild_trigger" "docker" { } build { + ## Build the GCP conformance server docker image. + ## This will be used by the conformance terragrunt config step further down. step { + id = "docker_build_conformance_gcp" name = "gcr.io/cloud-builders/docker" args = [ "build", - "-t", "${local.example_gcp_docker_image}:$SHORT_SHA", - "-t", "${local.example_gcp_docker_image}:latest", - "-f", "./cmd/example-gcp/Dockerfile", + "-t", "${local.conformance_gcp_docker_image}:$SHORT_SHA", + "-t", "${local.conformance_gcp_docker_image}:latest", + "-f", "./cmd/conformance/gcp/Dockerfile", "." ] } + ## Push the image. step { + id = "docker_push_conformance_gcp" name = "gcr.io/cloud-builders/docker" args = [ "push", "--all-tags", - local.example_gcp_docker_image + local.conformance_gcp_docker_image ] + wait_for = ["docker_build_conformance_gcp"] } + ## Apply the deployment/live/gcp/conformance/ci terragrunt config. + ## This will bring up the conformance infrastructure, including a service + ## running the confirmance server docker image built above. + step { + id = "terraform_apply_conformance_ci" + name = "alpine/terragrunt" + entrypoint = "terragrunt" + args = [ + "--terragrunt-non-interactive", + "apply", + "-auto-approve", + ] + dir = "deployment/live/gcp/conformance/ci" + env = [ + "GOOGLE_PROJECT=${var.project_id}", + "TF_IN_AUTOMATION=1", + "TF_INPUT=false", + "TF_VAR_project_id=${var.project_id}" + ] + wait_for = ["docker_push_conformance_gcp"] + } + ## Grab some outputs from the terragrunt apply above (e.g. conformance server URL) and store + ## them in files under /workspace. These are needed for later steps. + step { + id = "terraform_outputs" + name = "alpine/terragrunt" + script = < /workspace/conformance_url + EOT + wait_for = ["terraform_apply_conformance_ci"] + } + ## Build a note verifier string which can be used for verifying checkpoint signatures on the + ## conformange logs. + step { + id = "generate_verifier" + name = "golang" + args = [ + "go", + "run", + "./cmd/conformance/gcp/kmsnote", + "--key_id=${var.kms_key_version_id}", + "--name=${var.log_origin}", + "--output=/workspace/verifier.pub" + ] + wait_for = ["terraform_apply_conformance_ci"] + } + ## Since the conformance infrastructure is not publicly accessible, we need to use bearer tokens + ## for the hammer to access them. + ## This step creates those, and stores them for later use. + step { + id = "access" + name = "gcr.io/cloud-builders/gcloud" + script = < /workspace/cb_access + curl -H "Metadata-Flavor: Google" "http://metadata/computeMetadata/v1/instance/service-accounts/${google_service_account.cloudbuild_service_account.email}/identity?audience=$(cat /workspace/conformance_url)" > /workspace/cb_identity + EOT + wait_for = ["terraform_outputs"] + } + ## Run the hammer against the conformance server. + ## We're using it in "target throughput" mode. + step { + id = "hammer" + name = "golang" + script = <