The objective of the instructions below is to configure the infrastructure that allows you to run CI/CD deployments using
Terraform Cloud for the Terraform Example Foundation stages (0-bootstrap
, 1-org
, 2-environments
, 3-networks
, 4-projects
).
The infrastructure consists in two Google Cloud Platform projects (prj-b-seed
and prj-b-cicd-wif-tfc
).
It is a best practice to have two separate projects here (prj-b-seed
and prj-b-cicd-wif-tfc
) for separation of concerns.
On one hand, prj-b-seed
has the Service Accounts able to create / modify infrastructure.
On the other hand, the authentication infrastructure using Workload identity federation is implemented in prj-b-cicd-wif-tfc
. Unlike other deployment methods, Terraform state will be stored in Terraform Cloud instead of in a bucket in GCP.
Note: If you choose to use Terraform Cloud with Agents a private autopilot GKE cluster will be deployed in your prj-b-cicd-wif-tfc
GCP project to be used as the Agent.
To run the instructions described in this document, install the following:
- Google Cloud SDK version 393.0.0 or later
- terraform-tools component
- Git version 2.28.0 or later
- Terraform version 1.5.7 or later
- jq version 1.6.0 or later
For the manual steps described in this document, you need to use the same Terraform version used on the build pipeline. Otherwise, you might experience Terraform state snapshot lock errors.
Also make sure that you have the following:
- A Terraform Cloud account for your User or Organization.
- A Terraform Cloud organization.
- A Terraform Cloud User token or Organization token.
- Organization token is prefered since the permissions are limited to a single TFC organization.
- A supported version control system (VCS) provider connected with your Terraform Cloud account.
- The following list has the supported methods for connecting TFC to your VCS provider fully supported by this README. While it's possible to connect with providers not listed here, doing so may require some adjustments.
- Once you have any VCS provider configured you should be able to copy
OAuth Token ID
available in TFC console (https://app.terraform.io/app/YOUR-TFC-ORGANIZATION/settings/version-control).
- A private repository (or project) in your VCS provider for each one of the stages of Foundation:
- Bootstrap
- Organization
- Environments
- Networks
- Projects
- See GitHub repository creation or GitLab project creation for more details.
- A Google Cloud organization.
- A Google Cloud billing account.
- Cloud Identity or Google Workspace groups for organization and billing admins.
- For the user who will run the procedures in this document, grant the following roles:
- The
roles/resourcemanager.organizationAdmin
role on the Google Cloud organization. - The
roles/orgpolicy.policyAdmin
role on the Google Cloud organization. - The
roles/resourcemanager.projectCreator
role on the Google Cloud organization. - The
roles/billing.admin
role on the billing account. - The
roles/resourcemanager.folderCreator
role.
- The
-
Clone terraform-example-foundation into your local environment.
git clone https://github.com/terraform-google-modules/terraform-example-foundation.git
-
Clone all the private repositories (or projects) you created at the same level of the
terraform-example-foundation
folder. You must be authenticated to the VCS provider. See GitHub authentication or GitLab authentication for more details.git clone git@<VCS-SERVICE-PROVIDER>.com:<VCS-OWNER>/<VCS-BOOTSTRAP-REPO>.git gcp-bootstrap
git clone git@<VCS-SERVICE-PROVIDER>.com:<VCS-OWNER>/<VCS-ORGANIZATION-REPO>.git gcp-org
git clone git@<VCS-SERVICE-PROVIDER>.com:<VCS-OWNER>/<VCS-ENVIRONMENTS-REPO>.git gcp-environments
git clone git@<VCS-SERVICE-PROVIDER>.com:<VCS-OWNER>/<VCS-NETWORKS-REPO>.git gcp-networks
git clone git@<VCS-SERVICE-PROVIDER>.com:<VCS-OWNER>/<VCS-PROJECTS-REPO>.git gcp-projects
-
The layout should be:
gcp-bootstrap/ gcp-org/ gcp-environments/ gcp-networks/ gcp-projects/ terraform-example-foundation/
-
In your VCS repositories (or projects) it is expected to have the following branches created. Also, these branches shouldn't be empty, you need at least a single file. Run
scripts/git_create_branches_helper.sh
script to create these branches with a seed file for each repository automatically.- Bootstrap:
production
- Organization:
production
- Environments:
development
,nonproduction
andproduction
- Networks:
development
,nonproduction
andproduction
- Projects:
development
,nonproduction
andproduction
- Note:
scripts/git_create_branches_helper.sh
script and the following commands assume you are running it from the directory that has all the repos cloned (layout described in the previous step). If you run from another directory, adjust theBASE_PATH
variable at thescripts/git_create_branches_helper.sh
and adjust in the following commands.
chmod 755 ./terraform-example-foundation/0-bootstrap/scripts/git_create_branches_helper.sh ./terraform-example-foundation/0-bootstrap/scripts/git_create_branches_helper.sh
You will see some GIT logs related to the branches creation in the console and the message
"Branch creation and push completed for all repositories"
at the end of the script execution. - Bootstrap:
-
Authenticate your Terraform CLI by running the
login
command and following the instructions provided in the browser tab that should open automatically.terraform login
Note: It is required to do this step even if you already have an Organization token in order to generate your User token.
-
Navigate into the repo. All subsequent steps assume you are running them from the
gcp-bootstrap
directory. If you run them from another directory, adjust your copy paths accordingly.cd gcp-bootstrap
-
change to a nonproduction branch.
git checkout -b plan
-
Copy contents of foundation to new repo (modify accordingly based on your current directory).
mkdir -p envs/shared cp -RT ../terraform-example-foundation/0-bootstrap/ ./envs/shared cd ./envs/shared
-
In the versions file
./versions.tf
un-comment thetfe
required provider -
In the variables file
./variables.tf
un-comment variables in the sectionSpecific to tfc_bootstrap
-
In the outputs file
./outputs.tf
Comment-out outputs in the sectionSpecific to cloudbuild_module
-
In the outputs file
./outputs.tf
un-comment outputs in the sectionSpecific to tfc_bootstrap
- If you want to use Terraform Cloud with Agents, in addition to
Specific to tfc_bootstrap
, un-comment outputs in the sectionSpecific to tfc_bootstrap with Terraform Cloud Agents
and updateenable_tfc_cloud_agents
totrue
variable atterraform.tfvars
- If you want to use Terraform Cloud with Agents, in addition to
-
Rename file
./cb.tf
to./cb.tf.example
mv ./cb.tf ./cb.tf.example
-
Rename file
.terraform_cloud.tf.example
to./terraform_cloud.tf
mv ./terraform_cloud.tf.example ./terraform_cloud.tf
-
Rename file
terraform.example.tfvars
toterraform.tfvars
mv ./terraform.example.tfvars ./terraform.tfvars
-
Update the file
terraform.tfvars
with values from your Google Cloud environment -
Update the file
terraform.tfvars
with values from your VCS repositories attfc_bootstrap
section -
Update the file
terraform.tfvars
with values from your Terraform Cloud organization attfc_bootstrap
section- If you want to use Terraform Cloud with Agents update
enable_tfc_cloud_agents
variable attfc_bootstrap
section
- If you want to use Terraform Cloud with Agents update
-
To prevent saving the
tfc_token
in plain text in theterraform.tfvars
file, export the Terraform Cloud token as an environment variable:export TF_VAR_tfc_token=YOUR-TFC-TOKEN
-
To prevent saving the
vcs_oauth_token_id
in plain text in theterraform.tfvars
file, export the OAuth Token ID as an environment variable:export TF_VAR_vcs_oauth_token_id=YOUR-VCS-OAUTH-TOKEN-ID
-
Run
terraform version
to get the version of your TF and export it as environment variables.terraform_version
variable will be used by thetfe_workspace
resource in order to set the version of the TF in TFC workspaces. This is important so the state migration (from your local to TFC) works.TF_VAR_tfc_terraform_version=$(terraform --version -json | jq '.terraform_version' | sed 's/"//g') export TF_VAR_tfc_terraform_version echo "TF Version = ${TF_VAR_tfc_terraform_version}"
Note: You may need to install
jq
, if your OS doesn't have built-in. An alternative would be runterraform --version
and manually copy the number version output to be set at the environment variable. -
Use the helper script validate-requirements.sh to validate your environment:
../../../terraform-example-foundation/scripts/validate-requirements.sh -o <ORGANIZATION_ID> -b <BILLING_ACCOUNT_ID> -u <END_USER_EMAIL> -e
Note: The script is not able to validate if the user is in a Cloud Identity or Google Workspace group with the required roles.
-
Run
terraform init
andterraform plan
and review the output.terraform init terraform plan -input=false -out bootstrap.tfplan
-
Run
terraform apply
.terraform apply bootstrap.tfplan
-
If you set
enable_tfc_cloud_agents
variable totrue
onterraform.tfvars
in order to use Terraform Cloud with Agents you need to run these additional steps. If not, you should skip it.- In
provider.tf
file, un-comment kubernetes provider section; - In
terraform_cloud.tf
file, un-commentproviders
block attfc_agent_gke
module; - Run
terraform plan -input=false -out bootstrap_2.tfplan
- Run
terraform apply bootstrap_2.tfplan
- In
-
Run
terraform output
to get the email address of the terraform service accounts that will be used to run manual steps forshared
environments in steps3-networks-dual-svpc
,3-networks-hub-and-spoke
, and4-projects
.export network_step_sa=$(terraform output -raw networks_step_terraform_service_account_email) export projects_step_sa=$(terraform output -raw projects_step_terraform_service_account_email) echo "network step service account = ${network_step_sa}" echo "projects step service account = ${projects_step_sa}"
-
Run
terraform output
to get the ID of your CI/CD project:export cicd_project_id=$(terraform output -raw cicd_project_id) echo "CI/CD Project ID = ${cicd_project_id}"
-
Run
terraform output
to get the name of the TFC organization and export it as environment variables.TF_CLOUD_ORGANIZATION
variable will be used by thecloud
block in order to move the local Terraform's state to TFC andTF_VAR_tfc_org_name
will be used to run manual steps forshared
environments in steps3-networks-dual-svpc
,3-networks-hub-and-spoke
, and4-projects
export TF_CLOUD_ORGANIZATION=$(terraform output -raw tfc_org_name) export TF_VAR_tfc_org_name=$TF_CLOUD_ORGANIZATION echo "TFC Organization = ${TF_CLOUD_ORGANIZATION}"
-
You need to rename the following files in order to configure the foundation steps for TFC:
backend.tf
tobackend.tf.gcs.example
andbackend.tf.cloud.example
tobackend.tf
in order to define TFC workspace configuration and store Terraform's state in TFC.remote.tf
toremote.tf.gcs.example
andremote.tf.cloud.example
toremote.tf
in order to retrieve the state outputs from workspace in TFC .- Note: You need to do this renaming in all the steps. You can run
scripts/set-tfc-backend-and-remote.sh
script to do the renaming for all the steps automatically.
mv backend.tf.cloud.example backend.tf cd ../../../ chmod 775 ./terraform-example-foundation/scripts/set-tfc-backend-and-remote.sh ./terraform-example-foundation/scripts/set-tfc-backend-and-remote.sh cd ./gcp-bootstrap/envs/shared
-
Re-run
terraform init
. When you're prompted, agree to copy Terraform state to Terraform Cloud.terraform init
-
(Optional) Run
terraform plan
to verify that state is configured correctly. You should see no changes from the previous state. -
Save the Terraform configuration to
gcp-bootstrap
VCS repository:cd ../.. git add . git commit -m 'Initialize bootstrap repo' git push --set-upstream origin plan
-
Open a pull request (for GitHub) or a merge request (for GitLab) from the
plan
branch to theproduction
branch and review the output. -
The pull request (or merge request) will trigger a Terraform Cloud speculative plan in the
production
environment. -
Review the speculative plan output in Terraform Cloud https://app.terraform.io/app/TFC-ORGANIZATION-NAME/workspaces/0-shared/runs under
Run List
item. The output should beYour infrastructure matches the configuration
since we applied the 0-bootstrap locally. -
If the speculative plan is successful, merge the pull request in to the
production
branch. -
The merge will trigger a Terraform Cloud
Plan and Apply
run, that will run the plan again for the terraform configuration for theproduction
environment. -
Before moving to the next step, go back to the parent directory.
cd ..
Note: After the deploy, to prevent the project quota error described in the Troubleshooting guide, we recommend that you request 50 additional projects for the projects step service account created in this step.
-
Navigate into the repo. All subsequent steps assume you are running them from the
gcp-org
directory. If you run them from another directory, adjust your copy paths accordingly.cd gcp-org
-
change to a nonproduction branch.
git checkout -b plan
-
Copy contents of foundation to new repo.
cp -RT ../terraform-example-foundation/1-org/ .
-
Rename
./envs/shared/terraform.example.tfvars
to./envs/shared/terraform.tfvars
mv ./envs/shared/terraform.example.tfvars ./envs/shared/terraform.tfvars
-
Update the file
envs/shared/terraform.tfvars
with values from your GCP environment. See the shared folder README.md for additional information on the values in theterraform.tfvars
file. -
Un-comment the variable
create_access_context_manager_access_policy = false
if your organization already has an Access Context Manager Policy.export ORGANIZATION_ID=$(terraform -chdir="../gcp-bootstrap/envs/shared" output -json common_config | jq '.org_id' --raw-output) export ACCESS_CONTEXT_MANAGER_ID=$(gcloud access-context-manager policies list --organization ${ORGANIZATION_ID} --format="value(name)") echo "access_context_manager_policy_id = ${ACCESS_CONTEXT_MANAGER_ID}" if [ ! -z "${ACCESS_CONTEXT_MANAGER_ID}" ]; then sed -i "s=//create_access_context_manager_access_policy=create_access_context_manager_access_policy=" ./envs/shared/terraform.tfvars; fi
-
Check if a Security Command Center Notification with the default name, scc-notify, already exists in your organization.
export ORG_STEP_SA=$(terraform -chdir="../gcp-bootstrap/envs/shared" output -raw organization_step_terraform_service_account_email) gcloud scc notifications describe "scc-notify" --format="value(name)" --organization=${ORGANIZATION_ID} --impersonate-service-account=${ORG_STEP_SA}
-
If the notification exists the output will be:
organizations/ORGANIZATION_ID/notificationConfigs/scc-notify
-
If the notification does not exist the output will be:
ERROR: (gcloud.scc.notifications.describe) NOT_FOUND: Requested entity was not found.
-
If the notification exists, choose a different value for the
scc_notification_name
variable in the./envs/shared/terraform.tfvars
file. -
Commit changes.
git add . git commit -m 'Initialize org repo'
-
Push your plan branch.
git push --set-upstream origin plan
-
Open a pull request (for GitHub) or a merge request (for GitLab) from the
plan
branch to theproduction
branch and review the output. -
The pull request (or merge request) will trigger a Terraform Cloud speculative plan in the
production
environment. -
Review the speculative plan output in Terraform Cloud https://app.terraform.io/app/TFC-ORGANIZATION-NAME/workspaces/1-shared/runs under
Run List
item. -
If the speculative plan is successful, merge the pull request in to the
production
branch. -
The merge will trigger a Terraform Cloud
Plan and Apply
run, that will run the plan and apply the terraform configuration for theproduction
environment. You need to approve the apply in theRuns
menu. -
Review apply output in Terraform Cloud https://app.terraform.io/app/TFC-ORGANIZATION-NAME/workspaces/1-shared/runs under
Run List
item. -
Before moving to the next step, go back to the parent directory.
cd ..
-
Navigate into the repo. All subsequent steps assume you are running them from the
gcp-environments
directory. If you run them from another directory, adjust your copy paths accordingly.cd gcp-environments
-
change to a nonproduction branch.
git checkout -b plan
-
Copy contents of foundation to new repo.
cp -RT ../terraform-example-foundation/2-environments/ .
-
Rename
terraform.example.tfvars
toterraform.tfvars
.mv terraform.example.tfvars terraform.tfvars
-
Update the file with values from your GCP environment. See any of the envs folder README.md files for additional information on the values in the
terraform.tfvars
file. -
Commit changes.
git add . git commit -m 'Initialize environments repo'
-
Push your plan branch.
git push --set-upstream origin plan
-
Open a pull request (for GitHub) or a merge request (for GitLab) from the
plan
branch to thedevelopment
branch and review the output. -
The pull request (or merge request) will trigger a Terraform Cloud speculative plan in the
development
environment. -
Review the speculative plan output in Terraform Cloud https://app.terraform.io/app/TFC-ORGANIZATION-NAME/workspaces/2-development/runs under
Run List
item. -
If the speculative plan is successful, merge the pull request in to the
development
branch. -
The merge will trigger a Terraform Cloud
Plan and Apply
run, that will run the plan and apply the terraform configuration for thedevelopment
environment. You need to approve the apply in theRuns
menu. -
Review apply output in Terraform Cloud https://app.terraform.io/app/TFC-ORGANIZATION-NAME/workspaces/2-development/runs under
Run List
item. -
If the TFC Apply is successful, you can open the pull request (or merge request) for the next environment.
-
Open a pull request (for GitHub) or a merge request (for GitLab) from the
development
branch to thenonproduction
branch and review the output. -
The pull request (or merge request) will trigger a Terraform Cloud speculative plan in the
nonproduction
environment. -
Review the speculative plan output in Terraform Cloud https://app.terraform.io/app/TFC-ORGANIZATION-NAME/workspaces/2-nonproduction/runs under
Run List
item. -
If the speculative plan is successful, merge the pull request in to the
nonproduction
branch. -
The merge will trigger a Terraform Cloud
Plan and Apply
run, that will run the plan and apply the terraform configuration for thenonproduction
environment. You need to approve the apply in theRuns
menu. -
Review apply output in Terraform Cloud https://app.terraform.io/app/TFC-ORGANIZATION-NAME/workspaces/2-nonproduction/runs under
Run List
item. -
If the TFC Apply is successful, you can open the pull request (or merge request) for the next environment.
-
Open a pull request (for GitHub) or a merge request (for GitLab) from the
nonproduction
branch to theproduction
branch and review the output. -
The pull request (or merge request) will trigger a Terraform Cloud speculative plan in the
production
environment. -
Review the speculative plan output in Terraform Cloud https://app.terraform.io/app/TFC-ORGANIZATION-NAME/workspaces/2-production/runs under
Run List
item. -
If the speculative plan is successful, merge the pull request in to the
production
branch. -
The merge will trigger a Terraform Cloud
Plan and Apply
run, that will run the plan and apply the terraform configuration for theproduction
environment. You need to approve the apply in theRuns
menu. -
Review apply output in Terraform Cloud https://app.terraform.io/app/TFC-ORGANIZATION-NAME/workspaces/2-production/runs under
Run List
item. -
You can now move to the instructions in the network stage. To use the Dual Shared VPC network mode go to Deploying step 3-networks-dual-svpc, or go to Deploying step 3-networks-hub-and-spoke to use the Hub and Spoke network mode.
-
Before moving to the next step, go back to the parent directory.
cd ..
Note: For all purposes we treat shared
environment as production
environment due to the possible impacts into production
. So 3-production
TFC workspace have a Run Trigger sourcing 3-shared
TFC workspace, which means that every time you successfully run an apply job in 3-shared
TFC workspace, a Plan and apply
job will be triggered automatically for 3-production
TFC workspace. (All the applies will continue requiring manual approvals in TFC console).
-
Navigate into the repo. All subsequent steps assume you are running them from the
gcp-networks
directory. If you run them from another directory, adjust your copy paths accordingly.cd gcp-networks
-
change to a nonproduction branch.
git checkout -b plan
-
Copy contents of foundation to new repo.
cp -RT ../terraform-example-foundation/3-networks-dual-svpc/ . cp -RT ../terraform-example-foundation/policy-library/ ./policy-library cp ../terraform-example-foundation/build/tf-wrapper.sh . chmod 755 ./tf-wrapper.sh
-
Rename
common.auto.example.tfvars
tocommon.auto.tfvars
, renameshared.auto.example.tfvars
toshared.auto.tfvars
and renameaccess_context.auto.example.tfvars
toaccess_context.auto.tfvars
.mv common.auto.example.tfvars common.auto.tfvars mv shared.auto.example.tfvars shared.auto.tfvars mv access_context.auto.example.tfvars access_context.auto.tfvars
-
Update the file
shared.auto.tfvars
with the values for thetarget_name_server_addresses
. -
Update the file
access_context.auto.tfvars
with the organization'saccess_context_manager_policy_id
.export ORGANIZATION_ID=$(terraform -chdir="../gcp-bootstrap/envs/shared/" output -json common_config | jq '.org_id' --raw-output) export ACCESS_CONTEXT_MANAGER_ID=$(gcloud access-context-manager policies list --organization ${ORGANIZATION_ID} --format="value(name)") echo "access_context_manager_policy_id = ${ACCESS_CONTEXT_MANAGER_ID}" sed -i "s/ACCESS_CONTEXT_MANAGER_ID/${ACCESS_CONTEXT_MANAGER_ID}/" ./access_context.auto.tfvars
-
Update
common.auto.tfvars
file with values from your GCP environment. See any of the envs folder README.md files for additional information on the values in thecommon.auto.tfvars
file. -
You must add your user email in the variable
perimeter_additional_members
to be able to see the resources created in the restricted project. -
You must manually plan and apply the
shared
environment from your (only once) since thedevelopment
,nonproduction
andproduction
environments depend on it. -
In order to manually run the apply for shared workspace from your local we need to temporary unset the TFC backend by renaming
envs/shared/backend.tf
toenvs/shared/backend.tf.temporary_disabled
.mv envs/shared/backend.tf envs/shared/backend.tf.temporary_disabled
-
Use
terraform output
to get the CI/CD project ID and the networks step Terraform Service Account from gcp-bootstrap output. -
The CI/CD project ID will be used in the validation of the Terraform configuration
export CICD_PROJECT_ID=$(terraform -chdir="../gcp-bootstrap/envs/shared/" output -raw cicd_project_id) echo ${CICD_PROJECT_ID}
-
Use
terraform output
to get the name of the TFC organization from gcp-bootstrap output and export it as environment variables. The TFC organization will be used during the manual apply process bytfe_outputs
resource in order to grab the outputs from previous steps.export TF_VAR_tfc_org_name=$(terraform -chdir="../gcp-bootstrap/envs/shared/" output -raw tfc_org_name) echo "TFC Organization = ${TF_VAR_tfc_org_name}"
-
The networks step Terraform Service Account will be used for Service Account impersonation in the following steps. An environment variable
GOOGLE_IMPERSONATE_SERVICE_ACCOUNT
will be set with the Terraform Service Account to enable impersonation.export GOOGLE_IMPERSONATE_SERVICE_ACCOUNT=$(terraform -chdir="../gcp-bootstrap/envs/shared/" output -raw networks_step_terraform_service_account_email) echo ${GOOGLE_IMPERSONATE_SERVICE_ACCOUNT}
-
Run
init
andplan
and review output for environment shared../tf-wrapper.sh init shared ./tf-wrapper.sh plan shared
-
To use the
validate
option of thetf-wrapper.sh
script, please follow the instructions to install the terraform-tools component. -
Run
validate
and check for violations../tf-wrapper.sh validate shared $(pwd)/policy-library ${CICD_PROJECT_ID}
-
Run
apply
shared../tf-wrapper.sh apply shared
Note: Because we are running an apply locally instead of in the TFC workspace, this apply to shared won't be triggerring the TFC Run Trigger for
3-production
TFC workspace. -
In order to set the TFC backend for shared workspace we now can rename
envs/shared/backend.tf.temporary_disabled
toenvs/shared/backend.tf
and runterraform init
. When you're prompted, agree to copy Terraform state to Terraform Cloud.cd envs/shared/ mv backend.tf.temporary_disabled backend.tf terraform init cd ../..
-
Commit changes
git add . git commit -m 'Initialize networks repo'
-
Push your plan branch.
git push --set-upstream origin plan
-
Open a pull request (for GitHub) or a merge request (for GitLab) from the
plan
branch to thedevelopment
branch and review the output. -
The pull request (or merge request) will trigger a Terraform Cloud speculative plan in the
development
environment. -
Review the speculative plan output in Terraform Cloud https://app.terraform.io/app/TFC-ORGANIZATION-NAME/workspaces/3-development/runs under
Run List
item. -
If the speculative plan is successful, merge the pull request in to the
development
branch. -
The merge will trigger a Terraform Cloud
Plan and Apply
run, that will run the plan and apply the terraform configuration for thedevelopment
environment. You need to approve the apply in theRuns
menu. -
Review apply output in Terraform Cloud https://app.terraform.io/app/TFC-ORGANIZATION-NAME/workspaces/3-development/runs under
Run List
item. -
If the TFC Apply is successful, you can open the pull request (or merge request) for the next environment.
-
Open a pull request (for GitHub) or a merge request (for GitLab) from the
development
branch to thenonproduction
branch and review the output. -
The pull request (or merge request) will trigger a Terraform Cloud speculative plan in the
nonproduction
environment. -
Review the speculative plan output in Terraform Cloud https://app.terraform.io/app/TFC-ORGANIZATION-NAME/workspaces/3-nonproduction/runs under
Run List
item. -
If the speculative plan is successful, merge the pull request in to the
nonproduction
branch. -
The merge will trigger a Terraform Cloud
Plan and Apply
run, that will run the plan and apply the terraform configuration for thenonproduction
environment. You need to approve the apply in theRuns
menu. -
Review apply output in Terraform Cloud https://app.terraform.io/app/TFC-ORGANIZATION-NAME/workspaces/3-nonproduction/runs under
Run List
item. -
If the TFC Apply is successful, you can open the pull request (or merge request) for the next environment.
-
Open a pull request (for GitHub) or a merge request (for GitLab) from the
nonproduction
branch to theproduction
branch and review the output. -
The pull request (or merge request) will trigger a Terraform Cloud speculative plan in the
production
environment. -
Review the speculative plan output in Terraform Cloud https://app.terraform.io/app/TFC-ORGANIZATION-NAME/workspaces/3-production/runs under
Run List
item. -
If the speculative plan is successful, merge the pull request in to the
production
branch. -
The merge will trigger a Terraform Cloud
Plan and Apply
run, that will run the plan and apply the terraform configuration for theproduction
environment. You need to approve the apply in theRuns
menu. -
Review apply output in Terraform Cloud https://app.terraform.io/app/TFC-ORGANIZATION-NAME/workspaces/3-production/runs under
Run List
item. -
Before executing the next steps, unset the
GOOGLE_IMPERSONATE_SERVICE_ACCOUNT
environment variable.unset GOOGLE_IMPERSONATE_SERVICE_ACCOUNT
-
Before moving to the next step, go back to the parent directory.
cd ..
-
You can now move to the instructions in the 4-projects stage.
Note: For all purposes we treat shared
environment as production
environment due to the possible impacts into production
. So 3-production
TFC workspace have a Run Trigger sourcing 3-shared
TFC workspace, which means that every time you successfully run an apply job in 3-shared
TFC workspace, a Plan and apply
job will be triggered automatically for 3-production
TFC workspace. (All the applies will continue requiring manual approvals in TFC console).
-
Navigate into the repo. All subsequent steps assume you are running them from the
gcp-networks
directory. If you run them from another directory, adjust your copy paths accordingly.cd gcp-networks
-
change to a nonproduction branch.
git checkout -b plan
-
Copy contents of foundation to new repo.
cp -RT ../terraform-example-foundation/3-networks-hub-and-spoke/ . cp -RT ../terraform-example-foundation/policy-library/ ./policy-library cp ../terraform-example-foundation/build/tf-wrapper.sh . chmod 755 ./tf-wrapper.sh
-
Rename
common.auto.example.tfvars
tocommon.auto.tfvars
, renameshared.auto.example.tfvars
toshared.auto.tfvars
and renameaccess_context.auto.example.tfvars
toaccess_context.auto.tfvars
.mv common.auto.example.tfvars common.auto.tfvars mv shared.auto.example.tfvars shared.auto.tfvars mv access_context.auto.example.tfvars access_context.auto.tfvars
-
Update
common.auto.tfvars
file with values from your GCP environment. See any of the envs folder README.md files for additional information on the values in thecommon.auto.tfvars
file. -
You must add your user email in the variable
perimeter_additional_members
to be able to see the resources created in the restricted project. -
You must manually plan and apply the
shared
environment (only once) since thedevelopment
,nonproduction
andproduction
environments depend on it. -
In order to manually run the apply for shared workspace from your local we need to temporary unset the TFC backend by renaming
envs/shared/backend.tf
toenvs/shared/backend.tf.temporary_disabled
.mv envs/shared/backend.tf envs/shared/backend.tf.temporary_disabled
-
Use
terraform output
to get the CI/CD project ID and the networks step Terraform Service Account from gcp-bootstrap output. -
The CI/CD project ID will be used in the validation of the Terraform configuration
export CICD_PROJECT_ID=$(terraform -chdir="../gcp-bootstrap/envs/shared/" output -raw cicd_project_id) echo ${CICD_PROJECT_ID}
-
Use
terraform output
to get the name of the TFC organization from gcp-bootstrap output and export it as environment variables. The TFC organization will be used during the manual apply process bytfe_outputs
resource in order to grab the outputs from previous steps.export TF_VAR_tfc_org_name=$(terraform -chdir="../gcp-bootstrap/envs/shared/" output -raw tfc_org_name) echo "TFC Organization = ${TF_VAR_tfc_org_name}"
-
The networks step Terraform Service Account will be used for Service Account impersonation in the following steps. An environment variable
GOOGLE_IMPERSONATE_SERVICE_ACCOUNT
will be set with the Terraform Service Account to enable impersonation.export GOOGLE_IMPERSONATE_SERVICE_ACCOUNT=$(terraform -chdir="../gcp-bootstrap/envs/shared/" output -raw networks_step_terraform_service_account_email) echo ${GOOGLE_IMPERSONATE_SERVICE_ACCOUNT}
-
Run
init
andplan
and review output for environment shared../tf-wrapper.sh init shared ./tf-wrapper.sh plan shared
-
To use the
validate
option of thetf-wrapper.sh
script, please follow the instructions to install the terraform-tools component. -
Run
validate
and check for violations../tf-wrapper.sh validate shared $(pwd)/policy-library ${CICD_PROJECT_ID}
-
Run
apply
shared../tf-wrapper.sh apply shared
Note: Because we are running an apply locally instead of in the TFC workspace, this apply to shared won't be triggerring the TFC Run Trigger for
3-production
TFC workspace. -
In order to set the TFC backend for shared workspace we now can rename
envs/shared/backend.tf.temporary_disabled
toenvs/shared/backend.tf
and runterraform init
. When you're prompted, agree to copy Terraform state to Terraform Cloud.cd envs/shared/ mv backend.tf.temporary_disabled backend.tf terraform init cd ../..
-
Commit changes
git add . git commit -m 'Initialize networks repo'
-
Push your plan branch.
git push --set-upstream origin plan
-
Open a pull request (for GitHub) or a merge request (for GitLab) from the
plan
branch to thedevelopment
branch and review the output. -
The pull request (or merge request) will trigger a Terraform Cloud speculative plan in the
development
environment. -
Review the speculative plan output in Terraform Cloud https://app.terraform.io/app/TFC-ORGANIZATION-NAME/workspaces/3-development/runs under
Run List
item. -
If the speculative plan is successful, merge the pull request in to the
development
branch. -
The merge will trigger a Terraform Cloud
Plan and Apply
run, that will run the plan and apply the terraform configuration for thedevelopment
environment. You need to approve the apply in theRuns
menu. -
Review apply output in Terraform Cloud https://app.terraform.io/app/TFC-ORGANIZATION-NAME/workspaces/3-development/runs under
Run List
item. -
If the TFC Apply is successful, you can open the pull request (or merge request) for the next environment.
-
Open a pull request (for GitHub) or a merge request (for GitLab) from the
development
branch to thenonproduction
branch and review the output. -
The pull request (or merge request) will trigger a Terraform Cloud speculative plan in the
nonproduction
environment. -
Review the speculative plan output in Terraform Cloud https://app.terraform.io/app/TFC-ORGANIZATION-NAME/workspaces/3-nonproduction/runs under
Run List
item. -
If the speculative plan is successful, merge the pull request in to the
nonproduction
branch. -
The merge will trigger a Terraform Cloud
Plan and Apply
run, that will run the plan and apply the terraform configuration for thenonproduction
environment. You need to approve the apply in theRuns
menu. -
Review apply output in Terraform Cloud https://app.terraform.io/app/TFC-ORGANIZATION-NAME/workspaces/3-nonproduction/runs under
Run List
item. -
If the TFC Apply is successful, you can open the pull request (or merge request) for the next environment.
-
Open a pull request (for GitHub) or a merge request (for GitLab) from the
nonproduction
branch to theproduction
branch and review the output. -
The pull request (or merge request) will trigger a Terraform Cloud speculative plan in the
production
environment. -
Review the speculative plan output in Terraform Cloud https://app.terraform.io/app/TFC-ORGANIZATION-NAME/workspaces/3-production/runs under
Run List
item. -
If the speculative plan is successful, merge the pull request in to the
production
branch. -
The merge will trigger a Terraform Cloud
Plan and Apply
run, that will run the plan and apply the terraform configuration for theproduction
environment. You need to approve the apply in theRuns
menu. -
Review apply output in Terraform Cloud https://app.terraform.io/app/TFC-ORGANIZATION-NAME/workspaces/3-production/runs under
Run List
item. -
Before executing the next steps, unset the
GOOGLE_IMPERSONATE_SERVICE_ACCOUNT
environment variable.unset GOOGLE_IMPERSONATE_SERVICE_ACCOUNT
-
Before moving to the next step, go back to the parent directory.
cd ..
-
You can now move to the instructions in the 4-projects stage.
Note: For all purposes we treat shared
environment as production
environment due to the possible impacts into production
. So 4-<business_unit>-production
TFC workspace have a Run Trigger sourcing 4-<business_unit>-shared
TFC workspace, which means that every time you successfully run an apply job in 4-<business_unit>-shared
TFC workspace, a Plan and apply
job will be triggered automatically for 4-<business_unit>-production
TFC workspace. (All the applies will continue requiring manual approvals in TFC console).
-
Navigate into the repo. All subsequent steps assume you are running them from the
gcp-projects
directory. If you run them from another directory, adjust your copy paths accordingly.cd gcp-projects
-
change to a nonproduction branch.
git checkout -b plan
-
Copy contents of foundation to new repo.
cp -RT ../terraform-example-foundation/4-projects/ . cp -RT ../terraform-example-foundation/policy-library/ ./policy-library cp ../terraform-example-foundation/build/tf-wrapper.sh . chmod 755 ./tf-wrapper.sh
-
Rename
auto.example.tfvars
files toauto.tfvars
.mv common.auto.example.tfvars common.auto.tfvars mv shared.auto.example.tfvars shared.auto.tfvars mv development.auto.example.tfvars development.auto.tfvars mv nonproduction.auto.example.tfvars nonproduction.auto.tfvars mv production.auto.example.tfvars production.auto.tfvars
-
See any of the envs folder README.md files for additional information on the values in the
common.auto.tfvars
,development.auto.tfvars
,nonproduction.auto.tfvars
, andproduction.auto.tfvars
files. -
See any of the shared folder README.md files for additional information on the values in the
shared.auto.tfvars
file. -
You need to manually plan and apply only once the
business_unit_1/shared
andbusiness_unit_2/shared
environments sincedevelopment
,nonproduction
, andproduction
depend on them. -
In order to manually run the apply for shared workspace from your local we need to temporary unset the TFC backend by renaming
envs/shared/backend.tf
toenvs/shared/backend.tf.temporary_disabled
.mv business_unit_1/shared/backend.tf business_unit_1/shared/backend.tf.temporary_disabled mv business_unit_2/shared/backend.tf business_unit_2/shared/backend.tf.temporary_disabled
-
Use
terraform output
to get the CI/CD project ID and the projects step Terraform Service Account from gcp-bootstrap output. -
The CI/CD project ID will be used in the validation of the Terraform configuration
export CICD_PROJECT_ID=$(terraform -chdir="../gcp-bootstrap/envs/shared/" output -raw cicd_project_id) echo ${CICD_PROJECT_ID}
-
Use
terraform output
to get the name of the TFC organization from gcp-bootstrap output and export it as environment variables. The TFC organization will be used during the manual apply process bytfe_outputs
resource in order to grab the outputs from previous steps.export TF_VAR_tfc_org_name=$(terraform -chdir="../gcp-bootstrap/envs/shared/" output -raw tfc_org_name) echo "TFC Organization = ${TF_VAR_tfc_org_name}"
-
The projects step Terraform Service Account will be used for Service Account impersonation in the following steps. An environment variable
GOOGLE_IMPERSONATE_SERVICE_ACCOUNT
will be set with the Terraform Service Account to enable impersonation.export GOOGLE_IMPERSONATE_SERVICE_ACCOUNT=$(terraform -chdir="../gcp-bootstrap/envs/shared/" output -raw projects_step_terraform_service_account_email) echo ${GOOGLE_IMPERSONATE_SERVICE_ACCOUNT}
-
Run
init
andplan
and review output for environment shared../tf-wrapper.sh init shared ./tf-wrapper.sh plan shared
-
To use the
validate
option of thetf-wrapper.sh
script, please follow the instructions to install the terraform-tools component. -
Run
validate
and check for violations../tf-wrapper.sh validate shared $(pwd)/policy-library ${CICD_PROJECT_ID}
-
Run
apply
shared../tf-wrapper.sh apply shared
Note: Because we are running an apply locally instead of in the TFC workspace, this apply to shared won't be triggerring the TFC Run Trigger for
4-<business_unit>-production
TFC workspace. -
In order to set the TFC backend for shared workspace we now can rename
envs/shared/backend.tf.temporary_disabled
toenvs/shared/backend.tf
and runterraform init
. When you're prompted, agree to copy Terraform state to Terraform Cloud.mv business_unit_1/shared/backend.tf.temporary_disabled business_unit_1/shared/backend.tf mv business_unit_2/shared/backend.tf.temporary_disabled business_unit_2/shared/backend.tf terraform -chdir="business_unit_1/shared/" init terraform -chdir="business_unit_2/shared/" init
-
(Optional) If you want additional subfolders for separate business units or entities, make additional copies of the folder
business_unit_1
and modify any values that vary across business unit likebusiness_code
,business_unit
, orsubnet_ip_range
.
For example, to create a new business unit similar to business_unit_1, run the following:
#copy the business_unit_1 folder and it's contents to a new folder business_unit_2
cp -r business_unit_1 business_unit_2
# search all files under the folder `business_unit_2` and replace strings for business_unit_1 with strings for business_unit_2
grep -rl bu1 business_unit_2/ | xargs sed -i 's/bu1/bu2/g'
grep -rl business_unit_1 business_unit_2/ | xargs sed -i 's/business_unit_1/business_unit_2/g'
-
Commit changes
git add . git commit -m 'Initialize networks repo'
-
Push your plan branch.
git push --set-upstream origin plan
-
Open a pull request (for GitHub) or a merge request (for GitLab) from the
plan
branch to thedevelopment
branch and review the output. -
The pull request (or merge request) will trigger a Terraform Cloud speculative plan in the
development
environment. -
Review the speculative plan output in Terraform Cloud https://app.terraform.io/app/TFC-ORGANIZATION-NAME/workspaces/4-development/runs under
Run List
item. -
If the speculative plan is successful, merge the pull request in to the
development
branch. -
The merge will trigger a Terraform Cloud
Plan and Apply
run, that will run the plan and apply the terraform configuration for thedevelopment
environment. You need to approve the apply in theRuns
menu. -
Review apply output in Terraform Cloud https://app.terraform.io/app/TFC-ORGANIZATION-NAME/workspaces/4-development/runs under
Run List
item. -
If the TFC Apply is successful, you can open the pull request (or merge request) for the next environment.
-
Open a pull request (for GitHub) or a merge request (for GitLab) from the
development
branch to thenonproduction
branch and review the output. -
The pull request (or merge request) will trigger a Terraform Cloud speculative plan in the
nonproduction
environment. -
Review the speculative plan output in Terraform Cloud https://app.terraform.io/app/TFC-ORGANIZATION-NAME/workspaces/4-nonproduction/runs under
Run List
item. -
If the speculative plan is successful, merge the pull request in to the
nonproduction
branch. -
The merge will trigger a Terraform Cloud
Plan and Apply
run, that will run the plan and apply the terraform configuration for thenonproduction
environment. You need to approve the apply in theRuns
menu. -
Review apply output in Terraform Cloud https://app.terraform.io/app/TFC-ORGANIZATION-NAME/workspaces/4-nonproduction/runs under
Run List
item. -
If the TFC Apply is successful, you can open the pull request (or merge request) for the next environment.
-
Open a pull request (for GitHub) or a merge request (for GitLab) from the
nonproduction
branch to theproduction
branch and review the output. -
The pull request (or merge request) will trigger a Terraform Cloud speculative plan in the
production
environment. -
Review the speculative plan output in Terraform Cloud https://app.terraform.io/app/TFC-ORGANIZATION-NAME/workspaces/4-production/runs under
Run List
item. -
If the speculative plan is successful, merge the pull request in to the
production
branch. -
The merge will trigger a Terraform Cloud
Plan and Apply
run, that will run the plan and apply the terraform configuration for theproduction
environment. You need to approve the apply in theRuns
menu. -
Review apply output in Terraform Cloud https://app.terraform.io/app/TFC-ORGANIZATION-NAME/workspaces/4-production/runs under
Run List
item. -
Unset the
GOOGLE_IMPERSONATE_SERVICE_ACCOUNT
environment variable.unset GOOGLE_IMPERSONATE_SERVICE_ACCOUNT