Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions 0-bootstrap/cb.tf
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ module "gcp_projects_state_bucket" {

module "tf_source" {
source = "terraform-google-modules/bootstrap/google//modules/tf_cloudbuild_source"
version = "~> 11.0"
version = "~> 11.0.1"

org_id = var.org_id
folder_id = google_folder.bootstrap.id
Expand Down Expand Up @@ -164,7 +164,7 @@ module "tf_private_pool" {

module "tf_cloud_builder" {
source = "terraform-google-modules/bootstrap/google//modules/tf_cloudbuild_builder"
version = "~> 11.0"
version = "~> 11.0.1"

project_id = module.tf_source.cloudbuild_project_id
dockerfile_repo_uri = module.tf_source.csr_repos[local.cloudbuilder_repo].url
Expand All @@ -178,6 +178,8 @@ module "tf_cloud_builder" {
worker_pool_id = module.tf_private_pool.private_worker_pool_id
bucket_name = "${var.bucket_prefix}-${module.tf_source.cloudbuild_project_id}-tf-cloudbuilder-build-logs"
workflow_deletion_protection = var.workflow_deletion_protection

depends_on = [module.tf_source]
}

module "bootstrap_csr_repo" {
Expand Down Expand Up @@ -216,7 +218,7 @@ module "build_terraform_image" {

module "tf_workspace" {
source = "terraform-google-modules/bootstrap/google//modules/tf_cloudbuild_workspace"
version = "~> 11.0"
version = "~> 11.0.1"
for_each = local.granular_sa

project_id = module.tf_source.cloudbuild_project_id
Expand Down
1 change: 1 addition & 0 deletions 0-bootstrap/sa.tf
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ locals {
],
"proj" = [
"roles/storage.objectAdmin",
"roles/storage.admin",
],
}

Expand Down
1 change: 1 addition & 0 deletions 3-networks-hub-and-spoke/modules/base_env/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ locals {
"cloudtrace.googleapis.com",
"composer.googleapis.com",
"compute.googleapis.com",
"confidentialcomputing.googleapis.com",
"connectgateway.googleapis.com",
"contactcenterinsights.googleapis.com",
"container.googleapis.com",
Expand Down
1 change: 1 addition & 0 deletions 3-networks-svpc/modules/base_env/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ locals {
"cloudtrace.googleapis.com",
"composer.googleapis.com",
"compute.googleapis.com",
"confidentialcomputing.googleapis.com",
"connectgateway.googleapis.com",
"contactcenterinsights.googleapis.com",
"container.googleapis.com",
Expand Down
3 changes: 1 addition & 2 deletions 4-projects/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ For an overview of the architecture and the parts, see the

The purpose of this step is to set up the folder structure, projects, and infrastructure pipelines for applications that are connected as service projects to the shared VPC created in the previous stage.

For each business unit, a shared `infra-pipeline` project is created along with Cloud Build triggers, CSRs for application infrastructure code and Google Cloud Storage buckets for state storage.
For each business unit, a shared `infra-pipeline` project is created along with Cloud Build triggers, CSRs for application infrastructure code, a Google Cloud Storage buckets for state storage, and a new Docker image will be built for the [Confidential Space](https://cloud.google.com/confidential-computing/confidential-space/docs/confidential-space-overview) environment, which will be used in the `5-app-infra` step.

This step follows the same [conventions](https://github.com/terraform-google-modules/terraform-example-foundation#branching-strategy) as the Foundation pipeline deployed in [0-bootstrap](https://github.com/terraform-google-modules/terraform-example-foundation/blob/master/0-bootstrap/README.md).
A custom [workspace](https://github.com/terraform-google-modules/terraform-google-bootstrap/blob/master/modules/tf_cloudbuild_workspace/README.md) (`bu1-example-app`) is created by this pipeline and necessary roles are granted to the Terraform Service Account of this workspace by enabling variable `sa_roles` as shown in this [example](https://github.com/terraform-google-modules/terraform-example-foundation/blob/master/4-projects/modules/base_env/example_shared_vpc_project.tf).
Expand Down Expand Up @@ -201,7 +201,6 @@ grep -rl 10.3.64.0 business_unit_2/ | xargs sed -i 's/10.3.64.0/10.4.64.0/g'
git checkout -b production
git push origin production
```

1. After production has been applied, apply development.
1. Merge changes to development. Because this is a [named environment branch](../docs/FAQ.md#what-is-a-named-branch),
pushing to this branch triggers both _terraform plan_ and _terraform apply_. Review the apply output in your Cloud Build project https://console.cloud.google.com/cloud-build/builds;region=DEFAULT_REGION?project=YOUR_CLOUD_BUILD_PROJECT_ID
Expand Down
3 changes: 3 additions & 0 deletions 4-projects/business_unit_1/development/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
|------|-------------|
| access\_context\_manager\_policy\_id | Access Context Manager Policy ID. |
| bucket | The created storage bucket. |
| confidential\_space\_project | Confidential Space project id. |
| confidential\_space\_project\_number | Confidential Space project number. |
| confidential\_space\_workload\_sa | Workload Service Account for confidential space from base\_env |
| default\_region | The default region for the project. |
| floating\_project | Project sample floating project. |
| iap\_firewall\_tags | The security tags created for IAP (SSH and RDP) firewall rules and to be used on the VM created on step 5-app-infra on the peering network project. |
Expand Down
1 change: 1 addition & 0 deletions 4-projects/business_unit_1/development/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,4 @@ module "env" {
project_deletion_policy = var.project_deletion_policy
folder_deletion_protection = var.folder_deletion_protection
}

17 changes: 17 additions & 0 deletions 4-projects/business_unit_1/development/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,20 @@ output "default_region" {
description = "The default region for the project."
value = local.default_region
}

output "confidential_space_project" {
description = "Confidential Space project id."
value = module.env.confidential_space_project
}


output "confidential_space_project_number" {
description = "Confidential Space project number."
value = module.env.confidential_space_project_number
}

output "confidential_space_workload_sa" {
description = "Workload Service Account for confidential space from base_env"
value = module.env.confidential_space_workload_sa
}

1 change: 1 addition & 0 deletions 4-projects/business_unit_1/development/remote.tf
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,4 @@ data "terraform_remote_state" "bootstrap" {
prefix = "terraform/bootstrap/state"
}
}

3 changes: 3 additions & 0 deletions 4-projects/business_unit_1/nonproduction/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
|------|-------------|
| access\_context\_manager\_policy\_id | Access Context Manager Policy ID. |
| bucket | The created storage bucket. |
| confidential\_space\_project | Confidential Space project id. |
| confidential\_space\_project\_number | Confidential Space project number. |
| confidential\_space\_workload\_sa | Workload Service Account for confidential space from base\_env |
| default\_region | The default region for the project. |
| floating\_project | Project sample floating project. |
| iap\_firewall\_tags | The security tags created for IAP (SSH and RDP) firewall rules and to be used on the VM created on step 5-app-infra on the peering network project. |
Expand Down
1 change: 1 addition & 0 deletions 4-projects/business_unit_1/nonproduction/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,4 @@ module "env" {
project_deletion_policy = var.project_deletion_policy
folder_deletion_protection = var.folder_deletion_protection
}

16 changes: 16 additions & 0 deletions 4-projects/business_unit_1/nonproduction/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,19 @@ output "default_region" {
description = "The default region for the project."
value = local.default_region
}

output "confidential_space_project" {
description = "Confidential Space project id."
value = module.env.confidential_space_project
}


output "confidential_space_project_number" {
description = "Confidential Space project number."
value = module.env.confidential_space_project_number
}

output "confidential_space_workload_sa" {
description = "Workload Service Account for confidential space from base_env"
value = module.env.confidential_space_workload_sa
}
1 change: 1 addition & 0 deletions 4-projects/business_unit_1/nonproduction/remote.tf
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,4 @@ data "terraform_remote_state" "bootstrap" {
prefix = "terraform/bootstrap/state"
}
}

3 changes: 3 additions & 0 deletions 4-projects/business_unit_1/production/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
|------|-------------|
| access\_context\_manager\_policy\_id | Access Context Manager Policy ID. |
| bucket | The created storage bucket. |
| confidential\_space\_project | Confidential Space project id. |
| confidential\_space\_project\_number | Confidential Space project number. |
| confidential\_space\_workload\_sa | Workload Service Account for confidential space from base\_env |
| default\_region | The default region for the project. |
| floating\_project | Project sample floating project. |
| iap\_firewall\_tags | The security tags created for IAP (SSH and RDP) firewall rules and to be used on the VM created on step 5-app-infra on the peering network project. |
Expand Down
1 change: 1 addition & 0 deletions 4-projects/business_unit_1/production/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,4 @@ module "env" {
project_deletion_policy = var.project_deletion_policy
folder_deletion_protection = var.folder_deletion_protection
}

15 changes: 15 additions & 0 deletions 4-projects/business_unit_1/production/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -94,3 +94,18 @@ output "default_region" {
value = local.default_region
}

output "confidential_space_project" {
description = "Confidential Space project id."
value = module.env.confidential_space_project
}


output "confidential_space_project_number" {
description = "Confidential Space project number."
value = module.env.confidential_space_project_number
}

output "confidential_space_workload_sa" {
description = "Workload Service Account for confidential space from base_env"
value = module.env.confidential_space_workload_sa
}
1 change: 1 addition & 0 deletions 4-projects/business_unit_1/production/remote.tf
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,4 @@ data "terraform_remote_state" "bootstrap" {
prefix = "terraform/bootstrap/state"
}
}

20 changes: 20 additions & 0 deletions 4-projects/business_unit_1/shared/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Copyright 2025 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

FROM alpine:latest
WORKDIR /confidential
COPY confidential_data /confidential
ENTRYPOINT ["/confidential/confidential_data"]
CMD []

3 changes: 3 additions & 0 deletions 4-projects/business_unit_1/shared/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,12 @@
|------|-------------|
| apply\_triggers\_id | CB apply triggers |
| artifact\_buckets | GCS Buckets to store Cloud Build Artifacts |
| artifact\_registry\_repository\_id | Artifact Registry ID. |
| bootstrap\_cloudbuild\_project\_id | Cloudbuild project ID. |
| cloudbuild\_project\_id | n/a |
| default\_region | Default region to create resources where applicable. |
| enable\_cloudbuild\_deploy | Enable infra deployment using Cloud Build. |
| image\_name | Image path used by confidential space instance. |
| log\_buckets | GCS Buckets to store Cloud Build logs |
| plan\_triggers\_id | CB plan triggers |
| repos | CSRs to store source code |
Expand Down
20 changes: 20 additions & 0 deletions 4-projects/business_unit_1/shared/confidential_data
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* Copyright 2025 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/


#!/bin/bash
echo "Confidential space is running!"

96 changes: 94 additions & 2 deletions 4-projects/business_unit_1/shared/example_infra_pipeline.tf
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,68 @@
*/

locals {
repo_names = ["bu1-example-app"]
repo_names = ["bu1-example-app"]
cmd_prompt = "gcloud builds submit . --tag ${local.confidential_space_image_tag} --project=${local.cloudbuild_project_id} --service-account=projects/${local.cloudbuild_project_id}/serviceAccounts/tf-cb-builder-sa@${local.cloudbuild_project_id}.iam.gserviceaccount.com --gcs-log-dir=gs://${module.infra_pipelines[0].log_buckets["bu1-example-app"]} --worker-pool=${local.cloud_build_private_worker_pool_id} || ( sleep 46 && gcloud builds submit . --tag ${local.confidential_space_image_tag} --project=${local.cloudbuild_project_id} --service-account=projects/${local.cloudbuild_project_id}/serviceAccounts/tf-cb-builder-sa@${local.cloudbuild_project_id}.iam.gserviceaccount.com --gcs-log-dir=gs://${module.infra_pipelines[0].log_buckets["bu1-example-app"]} --worker-pool=${local.cloud_build_private_worker_pool_id})"

Choose a reason for hiding this comment

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

high

This cmd_prompt local is extremely long and contains duplicated command strings, making it hard to read and maintain. The retry logic (|| ( sleep 46 && ... )) is also duplicated. Consider defining a base command and applying the retry logic separately to improve clarity.

confidential_space_image_version = "latest"
confidential_space_image_tag = "${var.default_region}-docker.pkg.dev/${local.cloudbuild_project_id}/tf-runners/confidential_space_image:${local.confidential_space_image_version}"

iam_roles_build = [
"roles/storage.objectAdmin",
"roles/cloudbuild.builds.builder",
]
}

resource "google_project_iam_member" "build_roles" {
for_each = toset(local.iam_roles_build)
project = local.cloudbuild_project_id
role = each.key
member = "serviceAccount:tf-cb-builder-sa@${local.cloudbuild_project_id}.iam.gserviceaccount.com"
}

resource "google_project_iam_member" "bucket_admin_binding" {
project = local.cloudbuild_project_id
role = "roles/storage.objectAdmin"
member = "serviceAccount:${local.projects_terraform_sa}"
}

resource "google_artifact_registry_repository_iam_member" "builder_on_artifact_registry" {
project = local.cloudbuild_project_id
location = var.default_region
repository = "tf-runners"
role = "roles/artifactregistry.repoAdmin"
member = "serviceAccount:${module.app_infra_cloudbuild_project[0].sa}"
}

resource "google_project_iam_member" "cloudbuild_logging" {
project = local.cloudbuild_project_id
role = "roles/logging.logWriter"
member = "serviceAccount:${module.app_infra_cloudbuild_project[0].sa}"
}

resource "google_project_iam_member" "workload_identity_admin" {
project = module.app_infra_cloudbuild_project[0].project_id
role = "roles/iam.workloadIdentityPoolAdmin"
member = "serviceAccount:${module.app_infra_cloudbuild_project[0].sa}"
}

resource "google_storage_bucket_iam_member" "cloudbuild_storage_read" {
bucket = module.infra_pipelines[0].log_buckets["bu1-example-app"]
role = "roles/storage.admin"
member = "serviceAccount:${module.app_infra_cloudbuild_project[0].sa}"
}

resource "google_storage_bucket_iam_member" "cloudbuild_sa_storage_admin" {
bucket = module.infra_pipelines[0].log_buckets["bu1-example-app"]
role = "roles/storage.admin"
member = "serviceAccount:tf-cb-builder-sa@${local.cloudbuild_project_id}.iam.gserviceaccount.com"
}

#resource "google_storage_bucket_iam_member" "cloudbuild_bucket_admin" {
# bucket = "${local.cloudbuild_project_id}_cloudbuild"
# role = "roles/storage.admin"
# member = "serviceAccount:${module.app_infra_cloudbuild_project[0].sa}"
#}

module "app_infra_cloudbuild_project" {
source = "../../modules/single_project"
count = local.enable_cloudbuild_deploy ? 1 : 0
Expand All @@ -37,7 +96,8 @@ module "app_infra_cloudbuild_project" {
"cloudkms.googleapis.com",
"iam.googleapis.com",
"artifactregistry.googleapis.com",
"cloudresourcemanager.googleapis.com"
"cloudresourcemanager.googleapis.com",
"confidentialcomputing.googleapis.com"
]
# Metadata
project_suffix = "infra-pipeline"
Expand All @@ -62,6 +122,36 @@ module "infra_pipelines" {
private_worker_pool_id = local.cloud_build_private_worker_pool_id
}

resource "time_sleep" "wait_iam_propagation" {
create_duration = "60s"

depends_on = [
module.infra_pipelines,
module.app_infra_cloudbuild_project,
google_project_iam_member.bucket_admin_binding,
google_storage_bucket_iam_member.cloudbuild_storage_read,
google_artifact_registry_repository_iam_member.builder_on_artifact_registry,
google_project_iam_member.cloudbuild_logging,
google_storage_bucket_iam_member.cloudbuild_sa_storage_admin,
#google_storage_bucket_iam_member.cloudbuild_bucket_admin,
]
}

module "build_confidential_space_image" {
source = "terraform-google-modules/gcloud/google"
version = "~> 3.5"
upgrade = false
module_depends_on = [time_sleep.wait_iam_propagation]

create_cmd_triggers = {
"tag_version" = local.confidential_space_image_version
"cmd_prompt" = local.cmd_prompt
}

create_cmd_entrypoint = "bash"
create_cmd_body = "${local.cmd_prompt} || ( sleep 45 && ${local.cmd_prompt})"

Choose a reason for hiding this comment

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

high

There appears to be a redundant, nested retry mechanism here. The local.cmd_prompt variable already contains a retry with sleep 46. This create_cmd_body then wraps it in another retry with sleep 45. This is confusing and should be simplified to have a single, clear retry mechanism.

}

/**
* When Jenkins CI/CD is used for deployment this resource
* is created to terraform validation works.
Expand All @@ -72,3 +162,5 @@ module "infra_pipelines" {
resource "null_resource" "jenkins_cicd" {
count = !local.enable_cloudbuild_deploy ? 1 : 0
}


15 changes: 15 additions & 0 deletions 4-projects/business_unit_1/shared/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,18 @@ output "enable_cloudbuild_deploy" {
description = "Enable infra deployment using Cloud Build."
value = local.enable_cloudbuild_deploy
}

output "artifact_registry_repository_id" {
description = "Artifact Registry ID."
value = module.infra_pipelines[0].artifact_registry_repository_id
}

output "bootstrap_cloudbuild_project_id" {
description = "Cloudbuild project ID."
value = local.cloudbuild_project_id
}

output "image_name" {
description = "Image path used by confidential space instance."
value = local.confidential_space_image_tag
}
Loading
Loading