Skip to content

Commit 1b08c16

Browse files
chore: add local deployment instructions (#1327)
Co-authored-by: Caetano Colin <[email protected]> Co-authored-by: caetano-colin <[email protected]>
1 parent a07e6a0 commit 1b08c16

File tree

13 files changed

+442
-158
lines changed

13 files changed

+442
-158
lines changed

0-bootstrap/README.md

Lines changed: 172 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,15 @@ This repository is intended as an example to be forked, tweaked, and maintained
6464
Though this blueprint can help accelerate your foundation design and build, we assume that you have the engineering skills and teams to deploy and customize your own foundation based on your own requirements.
6565

6666
We will support:
67-
- Code is semantically valid, pinned to known good versions, and passes terraform validate and lint checks
68-
- All PR to this repo must pass integration tests to deploy all resources into a test environment before being merged
69-
- Feature requests about ease of use of the code, or feature requests that generally apply to all users, are welcome
67+
68+
- Code is semantically valid, pinned to known good versions, and passes terraform validate and lint checks
69+
- All PR to this repo must pass integration tests to deploy all resources into a test environment before being merged
70+
- Feature requests about ease of use of the code, or feature requests that generally apply to all users, are welcome
7071

7172
We will not support:
72-
- In-place upgrades from a foundation deployed with an earlier version to a more recent version, even for minor version changes, might not be feasible. Repository maintainers do not have visibility to what resources a user deploys on top of their foundation or how the foundation was customized in deployment, so we make no guarantee about avoiding breaking changes.
73-
- Feature requests that are specific to a single user's requirement and not representative of general best practices
73+
74+
- In-place upgrades from a foundation deployed with an earlier version to a more recent version, even for minor version changes, might not be feasible. Repository maintainers do not have visibility to what resources a user deploys on top of their foundation or how the foundation was customized in deployment, so we make no guarantee about avoiding breaking changes.
75+
- Feature requests that are specific to a single user's requirement and not representative of general best practices
7476

7577
## Prerequisites
7678

@@ -86,21 +88,25 @@ To run the commands described in this document, install the following:
8688
Version 1.5.7 is the last version before the license model change. To use a later version of Terraform, ensure that the Terraform version used in the Operational System to manually execute part of the steps in `3-networks` and `4-projects` is the same version configured in the following code
8789

8890
- 0-bootstrap/modules/jenkins-agent/variables.tf
91+
8992
```
9093
default = "1.5.7"
9194
```
9295

9396
- 0-bootstrap/cb.tf
97+
9498
```
9599
terraform_version = "1.5.7"
96100
```
97101

98102
- scripts/validate-requirements.sh
103+
99104
```
100105
TF_VERSION="1.5.7"
101106
```
102107

103108
- build/github-tf-apply.yaml
109+
104110
```
105111
terraform_version: '1.5.7'
106112
```
@@ -112,6 +118,7 @@ Version 1.5.7 is the last version before the license model change. To use a late
112118
```
113119

114120
- 0-bootstrap/Dockerfile
121+
115122
```
116123
ARG TERRAFORM_VERSION=1.5.7
117124
```
@@ -136,7 +143,9 @@ Set the variables in **terraform.tfvars** (`groups` block) to use the specific g
136143
# example:
137144
gcloud organizations add-iam-policy-binding ${ORG_ID} --member=user:$SUPER_ADMIN_EMAIL --role=roles/securitycenter.admin --quiet > /dev/null 1>&1
138145
```
146+
139147
1. Enable the following additional services on your current bootstrap project:
148+
140149
```bash
141150
gcloud services enable cloudresourcemanager.googleapis.com
142151
gcloud services enable cloudbilling.googleapis.com
@@ -342,11 +351,164 @@ The following steps introduce the steps to deploy with Cloud Build Alternatively
342351

343352
## Running Terraform locally
344353

345-
If you deploy using Cloud Build, the bucket information is replaced in the state
346-
backends as part of the build process when the build is executed by Cloud Build.
347-
If you want to execute Terraform locally, you need to add your Cloud
348-
Storage bucket to the `backend.tf` files.
349-
Each step has instructions for this change.
354+
The following steps will guide you through deploying without using Cloud Build.
355+
356+
1. Clone [terraform-example-foundation](https://github.com/terraform-google-modules/terraform-example-foundation) into your local environment and create to the `gcp-bootstrap` folder at the same level. Copy the `0-bootstrap` content and `.gitignore` to `gcp-bootstrap`.
357+
358+
```bash
359+
git clone https://github.com/terraform-google-modules/terraform-example-foundation.git
360+
361+
mkdir gcp-bootstrap
362+
363+
cp -R terraform-example-foundation/0-bootstrap/* gcp-bootstrap/
364+
365+
cp terraform-example-foundation/.gitignore gcp-bootstrap
366+
```
367+
368+
1. Navigate to `gcp-bootstrap` and initialize a local Git repository to manage versions locally. Then, Create the environment branches.
369+
370+
```bash
371+
cd gcp-bootstrap
372+
373+
git init
374+
git commit -m "initialize empty directory" --allow-empty
375+
git checkout -b plan
376+
377+
git checkout -b shared
378+
```
379+
380+
1. Rename `terraform.example.tfvars` to `terraform.tfvars` and update the file with values from your environment:
381+
382+
```bash
383+
mv terraform.example.tfvars terraform.tfvars
384+
```
385+
386+
1. Rename `cb.tf` to `cb.tf.example`:
387+
388+
```bash
389+
mv cb.tf cb.tf.example
390+
```
391+
392+
1. Comment Cloud Build related outputs at `outputs.tf`.
393+
394+
1. In `sa.tf` file, comment out lines related to Cloud Build. Specifically, search for `cicd_project_iam_member` and comment out the corresponding module, as well as the "depends_on" meta-argument in any modules that depend on the commented module.
395+
396+
1. In `sa.tf` file, search for `local.cicd_project_id` and comment out the corresponding code.
397+
398+
1. Use the helper script [validate-requirements.sh](../scripts/validate-requirements.sh) to validate your environment:
399+
400+
```bash
401+
../terraform-example-foundation/scripts/validate-requirements.sh -o <ORGANIZATION_ID> -b <BILLING_ACCOUNT_ID> -u <END_USER_EMAIL>
402+
```
403+
404+
**Note:** The script is not able to validate if the user is in a Cloud Identity or Google Workspace group with the required roles.
405+
406+
1. Run `terraform init` and `terraform plan` and review the output.
407+
408+
```bash
409+
git checkout plan
410+
terraform init
411+
terraform plan -input=false -out bootstrap.tfplan
412+
```
413+
414+
1. Create a new folder called gcp-policies at the same directory level as the `terraform-example-foundation` folder. Initialize a Git repository, create a branch called `main`, and copy the contents of the `policy-library` directory from the `terraform-example-foundation` folder into the gcp-policies folder.
415+
416+
```bash
417+
cd ../
418+
419+
mkdir gcp-policies
420+
421+
cd gcp-policies
422+
git init
423+
git checkout -b main
424+
cp -RT ../terraform-example-foundation/policy-library/ .
425+
```
426+
427+
1. Commit changes to the main branch of the policy repo. This way you can manage versions locally.
428+
429+
```bash
430+
git add .
431+
git commit -m 'Initialize policy library repo'
432+
```
433+
434+
1. Navigate back to `gcp-bootstrap` repo.
435+
436+
```bash
437+
cd ../gcp-bootstrap
438+
```
439+
440+
1. To validate your policies, run `gcloud beta terraform vet`. For installation instructions, see [Install Google Cloud CLI](https://cloud.google.com/docs/terraform/policy-validation/validate-policies#install).
441+
442+
1. Run the following commands and check for violations:
443+
444+
```bash
445+
export VET_PROJECT_ID=A-VALID-PROJECT-ID
446+
terraform show -json bootstrap.tfplan > bootstrap.json
447+
gcloud beta terraform vet bootstrap.json --policy-library="$(pwd)/../gcp-policies" --project ${VET_PROJECT_ID}
448+
```
449+
450+
*`A-VALID-PROJECT-ID`* must be an existing project you have access to. This is necessary because `gcloud beta terraform vet` needs to link resources to a valid Google Cloud Platform project.
451+
452+
1. Commit validated code in plan branch.
453+
454+
```bash
455+
git add .
456+
git commit -m "Initial version os gcp-bootstrap."
457+
```
458+
459+
1. Checkout `shared` branch and merge the `plan` branch into it. Then, Run `terraform apply`.
460+
461+
```bash
462+
git checkout shared
463+
git merge plan
464+
465+
terraform apply bootstrap.tfplan
466+
```
467+
468+
1. Run `terraform output` to get the email address of the terraform service accounts that will be used to run steps manually and the state bucket that will be used by step `4-projects`.
469+
470+
```bash
471+
export network_step_sa=$(terraform output -raw networks_step_terraform_service_account_email)
472+
export projects_step_sa=$(terraform output -raw projects_step_terraform_service_account_email)
473+
export projects_gcs_bucket_tfstate=$(terraform output -raw projects_gcs_bucket_tfstate)
474+
475+
echo "network step service account = ${network_step_sa}"
476+
echo "projects step service account = ${projects_step_sa}"
477+
echo "projects gcs bucket tfstate = ${projects_gcs_bucket_tfstate}"
478+
```
479+
480+
1. Copy the backend and update `backend.tf` with the name of your Google Cloud Storage bucket for Terraform's state. Also update the `backend.tf` of all steps.
481+
482+
```bash
483+
export backend_bucket=$(terraform output -raw gcs_bucket_tfstate)
484+
echo "backend_bucket = ${backend_bucket}"
485+
486+
export backend_bucket_projects=$(terraform output -raw projects_gcs_bucket_tfstate)
487+
echo "backend_bucket_projects = ${backend_bucket_projects}"
488+
489+
cp backend.tf.example backend.tf
490+
491+
cd ../
492+
493+
for i in `find . -name 'backend.tf'`; do sed -i'' -e "s/UPDATE_ME/${backend_bucket}/" $i; done
494+
for i in `find . -name 'backend.tf'`; do sed -i'' -e "s/UPDATE_PROJECTS_BACKEND/${backend_bucket_projects}/" $i; done
495+
496+
cd gcp-bootstrap
497+
```
498+
499+
1. Re-run `terraform init`. When you're prompted, agree to copy Terraform state to Cloud Storage.
500+
501+
```bash
502+
terraform init
503+
```
504+
505+
1. Commit the new code version, so you can manage versions locally.
506+
507+
```sh
508+
git add backend.tf
509+
git commit -m "Init gcs backend."
510+
cd ../
511+
```
350512

351513
<!-- BEGINNING OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
352514
## Inputs

0-bootstrap/cb.tf

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,6 @@ locals {
2222

2323
cicd_project_id = module.tf_source.cloudbuild_project_id
2424

25-
state_bucket_kms_key = "projects/${module.seed_bootstrap.seed_project_id}/locations/${var.default_region}/keyRings/${var.project_prefix}-keyring/cryptoKeys/${var.project_prefix}-key"
26-
2725
bucket_self_link_prefix = "https://www.googleapis.com/storage/v1/b/"
2826
default_state_bucket_self_link = "${local.bucket_self_link_prefix}${module.seed_bootstrap.gcs_bucket_tfstate}"
2927
gcp_projects_state_bucket_self_link = module.gcp_projects_state_bucket.bucket.self_link

0-bootstrap/main.tf

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ locals {
3232
org_admins_org_iam_permissions = var.org_policy_admin_role == true ? [
3333
"roles/orgpolicy.policyAdmin", "roles/resourcemanager.organizationAdmin", "roles/billing.user"
3434
] : ["roles/resourcemanager.organizationAdmin", "roles/billing.user"]
35+
36+
state_bucket_kms_key = "projects/${module.seed_bootstrap.seed_project_id}/locations/${var.default_region}/keyRings/${var.project_prefix}-keyring/cryptoKeys/${var.project_prefix}-key"
37+
3538
}
3639

3740
resource "google_folder" "bootstrap" {
@@ -103,4 +106,3 @@ module "seed_bootstrap" {
103106

104107
depends_on = [module.required_group]
105108
}
106-

0-bootstrap/outputs.tf

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,11 @@ output "gcs_bucket_tfstate" {
4949
value = module.seed_bootstrap.gcs_bucket_tfstate
5050
}
5151

52+
output "projects_gcs_bucket_tfstate" {
53+
description = "Bucket used for storing terraform state for stage 4-projects foundations pipelines in seed project."
54+
value = module.gcp_projects_state_bucket.bucket.name
55+
}
56+
5257
output "common_config" {
5358
description = "Common configuration data to be used in other steps."
5459
value = {
@@ -96,11 +101,6 @@ output "gcs_bucket_cloudbuild_logs" {
96101
value = { for key, value in module.tf_workspace : key => replace(value.logs_bucket, local.bucket_self_link_prefix, "") }
97102
}
98103

99-
output "projects_gcs_bucket_tfstate" {
100-
description = "Bucket used for storing terraform state for stage 4-projects foundations pipelines in seed project."
101-
value = module.gcp_projects_state_bucket.bucket.name
102-
}
103-
104104
output "cloud_builder_artifact_repo" {
105105
description = "Artifact Registry (AR) Repository created to store TF Cloud Builder images."
106106
value = "projects/${module.tf_source.cloudbuild_project_id}/locations/${var.default_region}/repositories/${module.tf_cloud_builder.artifact_repo}"
@@ -146,11 +146,6 @@ output "cloud_build_peered_network_id" {
146146
# value = module.gh_cicd.project_id
147147
# }
148148

149-
# output "projects_gcs_bucket_tfstate" {
150-
# description = "Bucket used for storing terraform state for stage 4-projects foundations pipelines in seed project."
151-
# value = module.seed_bootstrap.gcs_bucket_tfstate
152-
# }
153-
154149
/* ----------------------------------------
155150
Specific to jenkins_bootstrap module
156151
---------------------------------------- */
@@ -170,11 +165,6 @@ output "cloud_build_peered_network_id" {
170165
# value = module.jenkins_bootstrap.jenkins_agent_vpc_id
171166
# }
172167

173-
# output "projects_gcs_bucket_tfstate" {
174-
# description = "Bucket used for storing terraform state for stage 4-projects foundations pipelines in seed project."
175-
# value = module.seed_bootstrap.gcs_bucket_tfstate
176-
# }
177-
178168
# output "jenkins_agent_sa_email" {
179169
# description = "Email for privileged custom service account for Jenkins Agent GCE instance."
180170
# value = module.jenkins_bootstrap.jenkins_agent_sa_email
@@ -199,11 +189,6 @@ output "cloud_build_peered_network_id" {
199189
# value = module.gitlab_cicd.project_id
200190
# }
201191

202-
# output "projects_gcs_bucket_tfstate" {
203-
# description = "Bucket used for storing terraform state for stage 4-projects foundations pipelines in seed project."
204-
# value = module.seed_bootstrap.gcs_bucket_tfstate
205-
# }
206-
207192
/* ----------------------------------------
208193
Specific to tfc_bootstrap
209194
---------------------------------------- */

0 commit comments

Comments
 (0)