Skip to content

Commit

Permalink
chore: add local deployment instructions (#1327)
Browse files Browse the repository at this point in the history
Co-authored-by: Caetano Colin <164910343+caetano-colin@users.noreply.github.com>
Co-authored-by: caetano-colin <ccolin@ciandt.com>
  • Loading branch information
3 people authored Dec 23, 2024
1 parent a07e6a0 commit 1b08c16
Show file tree
Hide file tree
Showing 13 changed files with 442 additions and 158 deletions.
182 changes: 172 additions & 10 deletions 0-bootstrap/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,15 @@ This repository is intended as an example to be forked, tweaked, and maintained
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.

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

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

We will not support:
- 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.
- Feature requests that are specific to a single user's requirement and not representative of general best practices

- 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.
- Feature requests that are specific to a single user's requirement and not representative of general best practices

## Prerequisites

Expand All @@ -86,21 +88,25 @@ To run the commands described in this document, install the following:
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

- 0-bootstrap/modules/jenkins-agent/variables.tf

```
default = "1.5.7"
```

- 0-bootstrap/cb.tf

```
terraform_version = "1.5.7"
```

- scripts/validate-requirements.sh

```
TF_VERSION="1.5.7"
```

- build/github-tf-apply.yaml

```
terraform_version: '1.5.7'
```
Expand All @@ -112,6 +118,7 @@ Version 1.5.7 is the last version before the license model change. To use a late
```

- 0-bootstrap/Dockerfile

```
ARG TERRAFORM_VERSION=1.5.7
```
Expand All @@ -136,7 +143,9 @@ Set the variables in **terraform.tfvars** (`groups` block) to use the specific g
# example:
gcloud organizations add-iam-policy-binding ${ORG_ID} --member=user:$SUPER_ADMIN_EMAIL --role=roles/securitycenter.admin --quiet > /dev/null 1>&1
```

1. Enable the following additional services on your current bootstrap project:

```bash
gcloud services enable cloudresourcemanager.googleapis.com
gcloud services enable cloudbilling.googleapis.com
Expand Down Expand Up @@ -342,11 +351,164 @@ The following steps introduce the steps to deploy with Cloud Build Alternatively

## Running Terraform locally

If you deploy using Cloud Build, the bucket information is replaced in the state
backends as part of the build process when the build is executed by Cloud Build.
If you want to execute Terraform locally, you need to add your Cloud
Storage bucket to the `backend.tf` files.
Each step has instructions for this change.
The following steps will guide you through deploying without using Cloud Build.

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`.

```bash
git clone https://github.com/terraform-google-modules/terraform-example-foundation.git
mkdir gcp-bootstrap
cp -R terraform-example-foundation/0-bootstrap/* gcp-bootstrap/
cp terraform-example-foundation/.gitignore gcp-bootstrap
```

1. Navigate to `gcp-bootstrap` and initialize a local Git repository to manage versions locally. Then, Create the environment branches.

```bash
cd gcp-bootstrap
git init
git commit -m "initialize empty directory" --allow-empty
git checkout -b plan
git checkout -b shared
```

1. Rename `terraform.example.tfvars` to `terraform.tfvars` and update the file with values from your environment:

```bash
mv terraform.example.tfvars terraform.tfvars
```

1. Rename `cb.tf` to `cb.tf.example`:

```bash
mv cb.tf cb.tf.example
```

1. Comment Cloud Build related outputs at `outputs.tf`.

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.

1. In `sa.tf` file, search for `local.cicd_project_id` and comment out the corresponding code.

1. Use the helper script [validate-requirements.sh](../scripts/validate-requirements.sh) to validate your environment:

```bash
../terraform-example-foundation/scripts/validate-requirements.sh -o <ORGANIZATION_ID> -b <BILLING_ACCOUNT_ID> -u <END_USER_EMAIL>
```

**Note:** The script is not able to validate if the user is in a Cloud Identity or Google Workspace group with the required roles.

1. Run `terraform init` and `terraform plan` and review the output.

```bash
git checkout plan
terraform init
terraform plan -input=false -out bootstrap.tfplan
```

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.

```bash
cd ../
mkdir gcp-policies
cd gcp-policies
git init
git checkout -b main
cp -RT ../terraform-example-foundation/policy-library/ .
```

1. Commit changes to the main branch of the policy repo. This way you can manage versions locally.

```bash
git add .
git commit -m 'Initialize policy library repo'
```

1. Navigate back to `gcp-bootstrap` repo.

```bash
cd ../gcp-bootstrap
```

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).

1. Run the following commands and check for violations:

```bash
export VET_PROJECT_ID=A-VALID-PROJECT-ID
terraform show -json bootstrap.tfplan > bootstrap.json
gcloud beta terraform vet bootstrap.json --policy-library="$(pwd)/../gcp-policies" --project ${VET_PROJECT_ID}
```

*`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.

1. Commit validated code in plan branch.

```bash
git add .
git commit -m "Initial version os gcp-bootstrap."
```

1. Checkout `shared` branch and merge the `plan` branch into it. Then, Run `terraform apply`.

```bash
git checkout shared
git merge plan
terraform apply bootstrap.tfplan
```

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`.

```bash
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)
export projects_gcs_bucket_tfstate=$(terraform output -raw projects_gcs_bucket_tfstate)
echo "network step service account = ${network_step_sa}"
echo "projects step service account = ${projects_step_sa}"
echo "projects gcs bucket tfstate = ${projects_gcs_bucket_tfstate}"
```

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.
```bash
export backend_bucket=$(terraform output -raw gcs_bucket_tfstate)
echo "backend_bucket = ${backend_bucket}"
export backend_bucket_projects=$(terraform output -raw projects_gcs_bucket_tfstate)
echo "backend_bucket_projects = ${backend_bucket_projects}"
cp backend.tf.example backend.tf
cd ../
for i in `find . -name 'backend.tf'`; do sed -i'' -e "s/UPDATE_ME/${backend_bucket}/" $i; done
for i in `find . -name 'backend.tf'`; do sed -i'' -e "s/UPDATE_PROJECTS_BACKEND/${backend_bucket_projects}/" $i; done
cd gcp-bootstrap
```
1. Re-run `terraform init`. When you're prompted, agree to copy Terraform state to Cloud Storage.

```bash
terraform init
```

1. Commit the new code version, so you can manage versions locally.

```sh
git add backend.tf
git commit -m "Init gcs backend."
cd ../
```

<!-- BEGINNING OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
## Inputs
Expand Down
2 changes: 0 additions & 2 deletions 0-bootstrap/cb.tf
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@ locals {

cicd_project_id = module.tf_source.cloudbuild_project_id

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"

bucket_self_link_prefix = "https://www.googleapis.com/storage/v1/b/"
default_state_bucket_self_link = "${local.bucket_self_link_prefix}${module.seed_bootstrap.gcs_bucket_tfstate}"
gcp_projects_state_bucket_self_link = module.gcp_projects_state_bucket.bucket.self_link
Expand Down
4 changes: 3 additions & 1 deletion 0-bootstrap/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ locals {
org_admins_org_iam_permissions = var.org_policy_admin_role == true ? [
"roles/orgpolicy.policyAdmin", "roles/resourcemanager.organizationAdmin", "roles/billing.user"
] : ["roles/resourcemanager.organizationAdmin", "roles/billing.user"]

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"

}

resource "google_folder" "bootstrap" {
Expand Down Expand Up @@ -103,4 +106,3 @@ module "seed_bootstrap" {

depends_on = [module.required_group]
}

25 changes: 5 additions & 20 deletions 0-bootstrap/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ output "gcs_bucket_tfstate" {
value = module.seed_bootstrap.gcs_bucket_tfstate
}

output "projects_gcs_bucket_tfstate" {
description = "Bucket used for storing terraform state for stage 4-projects foundations pipelines in seed project."
value = module.gcp_projects_state_bucket.bucket.name
}

output "common_config" {
description = "Common configuration data to be used in other steps."
value = {
Expand Down Expand Up @@ -96,11 +101,6 @@ output "gcs_bucket_cloudbuild_logs" {
value = { for key, value in module.tf_workspace : key => replace(value.logs_bucket, local.bucket_self_link_prefix, "") }
}

output "projects_gcs_bucket_tfstate" {
description = "Bucket used for storing terraform state for stage 4-projects foundations pipelines in seed project."
value = module.gcp_projects_state_bucket.bucket.name
}

output "cloud_builder_artifact_repo" {
description = "Artifact Registry (AR) Repository created to store TF Cloud Builder images."
value = "projects/${module.tf_source.cloudbuild_project_id}/locations/${var.default_region}/repositories/${module.tf_cloud_builder.artifact_repo}"
Expand Down Expand Up @@ -146,11 +146,6 @@ output "cloud_build_peered_network_id" {
# value = module.gh_cicd.project_id
# }

# output "projects_gcs_bucket_tfstate" {
# description = "Bucket used for storing terraform state for stage 4-projects foundations pipelines in seed project."
# value = module.seed_bootstrap.gcs_bucket_tfstate
# }

/* ----------------------------------------
Specific to jenkins_bootstrap module
---------------------------------------- */
Expand All @@ -170,11 +165,6 @@ output "cloud_build_peered_network_id" {
# value = module.jenkins_bootstrap.jenkins_agent_vpc_id
# }

# output "projects_gcs_bucket_tfstate" {
# description = "Bucket used for storing terraform state for stage 4-projects foundations pipelines in seed project."
# value = module.seed_bootstrap.gcs_bucket_tfstate
# }

# output "jenkins_agent_sa_email" {
# description = "Email for privileged custom service account for Jenkins Agent GCE instance."
# value = module.jenkins_bootstrap.jenkins_agent_sa_email
Expand All @@ -199,11 +189,6 @@ output "cloud_build_peered_network_id" {
# value = module.gitlab_cicd.project_id
# }

# output "projects_gcs_bucket_tfstate" {
# description = "Bucket used for storing terraform state for stage 4-projects foundations pipelines in seed project."
# value = module.seed_bootstrap.gcs_bucket_tfstate
# }

/* ----------------------------------------
Specific to tfc_bootstrap
---------------------------------------- */
Expand Down
Loading

0 comments on commit 1b08c16

Please sign in to comment.