Skip to content

Add Cloud Build for GCP CI env #58

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Nov 22, 2024
22 changes: 22 additions & 0 deletions deployment/live/gcp/cloudbuild/prod/.terraform.lock.hcl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

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

locals {
docker_env = "ci"
server_docker_image = "${include.root.locals.location}-docker.pkg.dev/${include.root.locals.project_id}/docker-${local.docker_env}/conformance-gcp:latest"
}

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

inputs = merge(
local,
include.root.locals,
)
22 changes: 22 additions & 0 deletions deployment/live/gcp/cloudbuild/terragrunt.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
locals {
env = path_relative_to_include()
project_id = get_env("GOOGLE_PROJECT", "transparency-dev")
location = get_env("GOOGLE_REGION", "us-central1")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

very nit, region to align with tessera repo

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean the location cannot be changed?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean that this local / variable is called "region" instead of "location" in the tessera repo, we might as well use the same. I think that one spanner label also have a different name. Nothing too important.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. They seem to be interchangeable. Most terraform resources use location as the arguments.

base_name = get_env("TESSERA_BASE_NAME", "${local.env}-cloudbuild")
}

remote_state {
backend = "gcs"

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

gcs_bucket_labels = {
name = "terraform_state"
env = "${local.env}"
}
}
}
159 changes: 159 additions & 0 deletions deployment/modules/gcp/cloudbuild/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
terraform {
backend "gcs" {}

required_providers {
google = {
source = "registry.terraform.io/hashicorp/google"
version = "6.1.0"
}
}
}

# Artifact Registry

resource "google_project_service" "artifact_registry_api" {
service = "artifactregistry.googleapis.com"
disable_on_destroy = false
}

resource "google_artifact_registry_repository" "docker" {
repository_id = "docker-${var.docker_env}"
location = var.location
description = "Static CT docker images"
format = "DOCKER"
depends_on = [
google_project_service.artifact_registry_api,
]
}

# Cloud Build

locals {
artifact_repo = "${var.location}-docker.pkg.dev/${var.project_id}/${google_artifact_registry_repository.docker.name}"
conformance_gcp_docker_image = "${local.artifact_repo}/conformance-gcp"
}

resource "google_project_service" "cloudbuild_api" {
service = "cloudbuild.googleapis.com"
disable_on_destroy = false
}

resource "google_service_account" "cloudbuild_service_account" {
account_id = "cloudbuild-${var.env}-sa"
display_name = "Service Account for Cloud Build (${var.env})"
}

resource "google_project_iam_member" "logging_log_writer" {
project = var.project_id
role = "roles/logging.logWriter"
member = "serviceAccount:${google_service_account.cloudbuild_service_account.email}"
}

resource "google_artifact_registry_repository_iam_member" "artifactregistry_writer" {
project = google_artifact_registry_repository.docker.project
location = google_artifact_registry_repository.docker.location
repository = google_artifact_registry_repository.docker.name
role = "roles/artifactregistry.writer"
member = "serviceAccount:${google_service_account.cloudbuild_service_account.email}"
}

# TODO: Use google_cloud_run_service_iam_member to limit the service scope.
resource "google_project_iam_member" "run_developer" {
project = var.project_id
role = "roles/run.developer"
member = "serviceAccount:${google_service_account.cloudbuild_service_account.email}"
}

resource "google_project_iam_member" "iam_service_account_user" {
project = var.project_id
role = "roles/iam.serviceAccountUser"
member = "serviceAccount:${google_service_account.cloudbuild_service_account.email}"
}
Comment on lines +41 to +71
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this all defined in overground, no need to define this here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They're useful when setting up the cloud build in other GCP projects. I'm inclined to keep these. Perhaps we can use conditional IAM resources creation or provide the terraform import command.


resource "google_cloudbuild_trigger" "build_trigger" {
name = "build-docker-${var.docker_env}"
service_account = google_service_account.cloudbuild_service_account.id
location = var.location

github {
owner = "transparency-dev"
name = "static-ct"
push {
branch = "^main$"
}
}

build {
## TODO: Destroy any pre-existing deployment/live/gcp/ci environment.
## This might happen if a previous cloud build failed for some reason.

## Build the SCTFE GCP Docker image.
## This will be used by the building the conformance Docker image which includes
## the test data.
step {
id = "docker_build_sctfe_gcp"
name = "gcr.io/cloud-builders/docker"
args = [
"build",
"-t", "sctfe-gcp:$SHORT_SHA",
"-t", "sctfe-gcp:latest",
"-f", "./cmd/gcp/Dockerfile",
"."
]
}

## Build the SCTFE GCP Conformance Docker container image.
step {
id = "docker_build_conformance_gcp"
name = "gcr.io/cloud-builders/docker"
args = [
"build",
"-t", "${local.conformance_gcp_docker_image}:$SHORT_SHA",
"-t", "${local.conformance_gcp_docker_image}:latest",
"-f", "./cmd/gcp/ci/Dockerfile",
"."
]
}

## Push the conformance Docker container image to Artifact Registry.
step {
id = "docker_push_conformance_gcp"
name = "gcr.io/cloud-builders/docker"
args = [
"push",
"--all-tags",
local.conformance_gcp_docker_image
]
wait_for = ["docker_build_conformance_gcp"]
}

## Deploy container image to Cloud Run.
## TODO: Remove this as the `terragrunt apply` will bring up the Cloud Run.
step {
id = "cloud_run_deploy"
name = "gcr.io/google.com/cloudsdktool/cloud-sdk"
entrypoint = "gcloud"
args = [
"run",
"deploy",
"${var.docker_env}-static-ct",
"--image",
"${local.conformance_gcp_docker_image}:$SHORT_SHA",
"--region",
var.location
]
wait_for = ["docker_push_conformance_gcp"]
}

## TODO: Apply the terragrunt configuration to create the CI environment.

options {
logging = "CLOUD_LOGGING_ONLY"
machine_type = "E2_HIGHCPU_8"
}
}

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

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

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

variable "docker_env" {
description = "Unique identifier for the Docker env, e.g. dev or ci or prod"
type = string
}
6 changes: 6 additions & 0 deletions deployment/modules/gcp/cloudrun/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ resource "google_service_account" "cloudrun_service_account" {
display_name = "Service Account for Cloud Run (${var.env})"
}

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

Comment on lines +22 to +27
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, and for the other membership below actually (I had missed this in a previous PR). I don't think they should live here, but in Overground rather. Then, terraform can add biding to the GCS and Spanner resources for the right users to have the right roles on these resources. Let's clean that all up in a followup PR?

Or one could argue that we want to leave them around for transparency and to show to the world what's our IAM structure, at the cost of having two sources for this... TBD speaking with the team I'd say.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, let's talk about this with the team.

resource "google_project_iam_member" "monitoring_metric_writer" {
project = var.project_id
role = "roles/monitoring.metricWriter"
Expand Down
Loading