This repo is part of a multi-part guide that shows how to configure and deploy the example.com reference architecture described in Google Cloud security foundations guide. The following table lists the parts of the guide.
0-bootstrap | Bootstraps a Google Cloud organization, creating all the required resources and permissions to start using the Cloud Foundation Toolkit (CFT). This step also configures a CI/CD Pipeline for foundations code in subsequent stages. |
1-org | Sets up top-level shared folders, networking projects, organization-level logging, and baseline security settings through organizational policies. |
2-environments | Sets up development, nonproduction, and production environments within the Google Cloud organization that you've created. |
3-networks-dual-svpc | Sets up base and restricted shared VPCs with default DNS, NAT (optional), Private Service networking, VPC service controls, on-premises Dedicated Interconnect, and baseline firewall rules for each environment. It also sets up the global DNS hub. |
3-networks-hub-and-spoke | Sets up base and restricted shared VPCs with all the default configuration found on step 3-networks-dual-svpc, but here the architecture will be based on the Hub and Spoke network model. It also sets up the global DNS hub |
4-projects | Sets up a folder structure, projects, and an application infrastructure pipeline for applications, which are connected as service projects to the shared VPC created in the previous stage. |
5-app-infra (this file) | Deploy a simple [Compute Engine](https://cloud.google.com/compute/) instance in one of the business unit projects using the infra pipeline set up in 4-projects. |
For an overview of the architecture and the parts, see the terraform-example-foundation README file.
The purpose of this step is to deploy a simple Compute Engine instance in one of the business unit projects using the infra pipeline set up in 4-projects.
The infra pipeline is created in step 4-projects
within the shared env and has a Cloud Build pipeline configured to manage infrastructure within projects.
There is also a Source Repository configured with build triggers similar to the CI/CD Pipeline setup in 0-bootstrap
.
This Compute Engine instance is created using the base network from step 3-networks
and is used to access private services.
- 0-bootstrap executed successfully.
- 1-org executed successfully.
- 2-environments executed successfully.
- 3-networks executed successfully.
- 4-projects executed successfully.
Please refer to troubleshooting if you run into issues during this step.
Note: If you are using MacOS, replace cp -RT
with cp -R
in the relevant
commands. The -T
flag is needed for Linux, but causes problems for MacOS.
-
Clone the
gcp-policies
repo based on the Terraform output from the0-bootstrap
step. Clone the repo at the same level of theterraform-example-foundation
folder, the following instructions assume this layout. Runterraform output cloudbuild_project_id
in the0-bootstrap
folder to get the Cloud Build Project ID.export INFRA_PIPELINE_PROJECT_ID=$(terraform -chdir="gcp-projects/business_unit_1/shared/" output -raw cloudbuild_project_id) echo ${INFRA_PIPELINE_PROJECT_ID} gcloud source repos clone gcp-policies gcp-policies-app-infra --project=${INFRA_PIPELINE_PROJECT_ID}
Note:
gcp-policies
repo has the same name as the repo created in step1-org
. In order to prevent a collision, the previous command will clone this repo in the foldergcp-policies-app-infra
. -
Navigate into the repo and copy contents of policy-library to new repo. All subsequent steps assume you are running them from the gcp-policies-app-infra directory. If you run them from another directory, adjust your copy paths accordingly.
cd gcp-policies-app-infra git checkout -b main cp -RT ../terraform-example-foundation/policy-library/ .
-
Commit changes and push your main branch to the new repo.
git add . git commit -m 'Initialize policy library repo' git push --set-upstream origin main
-
Navigate out of the repo.
cd ..
-
Clone the
bu1-example-app
repo.gcloud source repos clone bu1-example-app --project=${INFRA_PIPELINE_PROJECT_ID}
-
Navigate into the repo, change to non-main branch and copy contents of foundation to new repo. All subsequent steps assume you are running them from the bu1-example-app directory. If you run them from another directory, adjust your copy paths accordingly.
cd bu1-example-app git checkout -b plan cp -RT ../terraform-example-foundation/5-app-infra/ . cp ../terraform-example-foundation/build/cloudbuild-tf-* . cp ../terraform-example-foundation/build/tf-wrapper.sh . chmod 755 ./tf-wrapper.sh
-
Rename
common.auto.example.tfvars
tocommon.auto.tfvars
.mv common.auto.example.tfvars common.auto.tfvars
-
Update the file with values from your environment and 0-bootstrap. See any of the business unit 1 envs folders README.md files for additional information on the values in the
common.auto.tfvars
file.export remote_state_bucket=$(terraform -chdir="../terraform-example-foundation/0-bootstrap/" output -raw projects_gcs_bucket_tfstate) echo "remote_state_bucket = ${remote_state_bucket}" sed -i'' -e "s/REMOTE_STATE_BUCKET/${remote_state_bucket}/" ./common.auto.tfvars
-
Commit changes.
git add . git commit -m 'Initialize bu1 example app repo'
-
Push your plan branch to trigger a plan for all environments. Because the plan branch is not a named environment branch, pushing your plan branch triggers terraform plan but not terraform apply. Review the plan output in your Cloud Build project https://console.cloud.google.com/cloud-build/builds;region=DEFAULT_REGION?project=YOUR_INFRA_PIPELINE_PROJECT_ID
git push --set-upstream origin plan
-
Merge changes to development. Because this is a named environment 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_INFRA_PIPELINE_PROJECT_ID
git checkout -b development git push origin development
-
Merge changes to nonproduction. Because this is a named environment 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_INFRA_PIPELINE_PROJECT_ID
git checkout -b nonproduction git push origin nonproduction
-
Merge changes to production branch. Because this is a named environment 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_INFRA_PIPELINE_PROJECT_ID
git checkout -b production git push origin production
-
The next instructions assume that you are at the same level of the
terraform-example-foundation
folder. Change into5-app-infra
folder, copy the Terraform wrapper script and ensure it can be executed.cd terraform-example-foundation/5-app-infra cp ../build/tf-wrapper.sh . chmod 755 ./tf-wrapper.sh
-
Rename
common.auto.example.tfvars
files tocommon.auto.tfvars
.mv common.auto.example.tfvars common.auto.tfvars
-
Update
common.auto.tfvars
file with values from your environment. -
Use
terraform output
to get the project backend bucket value from 0-bootstrap.export remote_state_bucket=$(terraform -chdir="../0-bootstrap/" output -raw projects_gcs_bucket_tfstate) echo "remote_state_bucket = ${remote_state_bucket}" sed -i'' -e "s/REMOTE_STATE_BUCKET/${remote_state_bucket}/" ./common.auto.tfvars
-
Provide the user that will be running
./tf-wrapper.sh
the Service Account Token Creator role to the bu1 Terraform service account. -
Provide the user permissions to run the terraform locally with the
serviceAccountTokenCreator
permission.member="user:$(gcloud auth list --filter="status=ACTIVE" --format="value(account)")" echo ${member} project_id=$(terraform -chdir="../4-projects/business_unit_1/shared/" output -raw cloudbuild_project_id) echo ${project_id} terraform_sa=$(terraform -chdir="../4-projects/business_unit_1/shared/" output -json terraform_service_accounts | jq '."bu1-example-app"' --raw-output) echo ${terraform_sa} gcloud iam service-accounts add-iam-policy-binding ${terraform_sa} --project ${project_id} --member="${member}" --role="roles/iam.serviceAccountTokenCreator"
-
Update
backend.tf
with your bucket from the infra pipeline output.export backend_bucket=$(terraform -chdir="../4-projects/business_unit_1/shared/" output -json state_buckets | jq '."bu1-example-app"' --raw-output) echo "backend_bucket = ${backend_bucket}" for i in `find . -name 'backend.tf'`; do sed -i'' -e "s/UPDATE_APP_INFRA_BUCKET/${backend_bucket}/" $i; done
We will now deploy each of our environments (development/production/nonproduction) using this script.
When using Cloud Build or Jenkins as your CI/CD tool, each environment corresponds to a branch in the repository for the 5-app-infra
step. Only the corresponding environment is applied.
To use the validate
option of the tf-wrapper.sh
script, please follow the instructions to install the terraform-tools component.
-
Use
terraform output
to get the Infra Pipeline Project ID from 4-projects output.export INFRA_PIPELINE_PROJECT_ID=$(terraform -chdir="../4-projects/business_unit_1/shared/" output -raw cloudbuild_project_id) echo ${INFRA_PIPELINE_PROJECT_ID} export GOOGLE_IMPERSONATE_SERVICE_ACCOUNT=$(terraform -chdir="../4-projects/business_unit_1/shared/" output -json terraform_service_accounts | jq '."bu1-example-app"' --raw-output) echo ${GOOGLE_IMPERSONATE_SERVICE_ACCOUNT}
-
Run
init
andplan
and review output for environment production../tf-wrapper.sh init production ./tf-wrapper.sh plan production
-
Run
validate
and check for violations../tf-wrapper.sh validate production $(pwd)/../policy-library ${INFRA_PIPELINE_PROJECT_ID}
-
Run
apply
production../tf-wrapper.sh apply production
-
Run
init
andplan
and review output for environment nonproduction../tf-wrapper.sh init nonproduction ./tf-wrapper.sh plan nonproduction
-
Run
validate
and check for violations../tf-wrapper.sh validate nonproduction $(pwd)/../policy-library ${INFRA_PIPELINE_PROJECT_ID}
-
Run
apply
nonproduction../tf-wrapper.sh apply nonproduction
-
Run
init
andplan
and review output for environment development../tf-wrapper.sh init development ./tf-wrapper.sh plan development
-
Run
validate
and check for violations../tf-wrapper.sh validate development $(pwd)/../policy-library ${INFRA_PIPELINE_PROJECT_ID}
-
Run
apply
development../tf-wrapper.sh apply development
If you received any errors or made any changes to the Terraform config or common.auto.tfvars
you must re-run ./tf-wrapper.sh plan <env>
before running ./tf-wrapper.sh apply <env>
.
After executing this stage, unset the GOOGLE_IMPERSONATE_SERVICE_ACCOUNT
environment variable.
unset GOOGLE_IMPERSONATE_SERVICE_ACCOUNT