Skip to content

Latest commit

 

History

History
286 lines (261 loc) · 14.3 KB

File metadata and controls

286 lines (261 loc) · 14.3 KB

5-app-infra

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, monitoring and networking projects, organization-level logging, and baseline security settings through organizational policies.
2-environments Sets up development, non-production, 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.

Purpose

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. To enable deployment via this pipeline, the projects deployed should enable the enable_cloudbuild_deploy flag and provide the Cloud Build service account value via cloudbuild_sa.

This enables the Cloud Build service account to impersonate the project service account and use it to deploy infrastructure. The roles required for the project SA can also be managed via sa_roles. (Note: This requires per project SA impersonation. If you would like to have a single SA managing an environment and all associated projects, that is also possible by granting roles/iam.serviceAccountTokenCreator to an SA with the right roles in 4-projects/env.)

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.

Prerequisites

  1. 0-bootstrap executed successfully.
  2. 1-org executed successfully.
  3. 2-environments executed successfully.
  4. 3-networks executed successfully.
  5. 4-projects executed successfully.

Troubleshooting

Please refer to troubleshooting if you run into issues during this step.

Usage

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.

Deploying with Cloud Build

  1. Get the Infra Pipeline project ID from the previous step. Run the following in the gcp-projects/business_unit_1/shared folder.
    terraform output cloudbuild_project_id
    
  2. Clone the policies repo. Note: This repo has the same name as the repo created in step 1-org, to prevent a collision the command below will clone it in folder gcp-policies-app-infra.
    gcloud source repos clone gcp-policies gcp-policies-app-infra --project=YOUR_INFRA_PIPELINE_PROJECT_ID
    
  3. Navigate into the 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
    
  4. Copy contents of policy-library to new repo.
    cp -RT ../terraform-example-foundation/policy-library/ .
    
  5. Commit changes.
    git add .
    git commit -m 'Your message'
    
  6. Push your main branch to the new repo.
    git push --set-upstream origin main
    
  7. Navigate out of the repo.
    cd ..
    
  8. Clone the bu1-example-app repo.
    gcloud source repos clone bu1-example-app --project=YOUR_INFRA_PIPELINE_PROJECT_ID
    
  9. Navigate into the 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
    
  10. Change freshly cloned repo and change to non-main branch.
    git checkout -b plan
    
  11. Copy contents of foundation to new repo.
    cp -RT ../terraform-example-foundation/5-app-infra/ .
    
  12. Copy Cloud Build configuration files for Terraform.
    cp ../terraform-example-foundation/build/cloudbuild-tf-* .
    
  13. Copy the Terraform wrapper script to the root of your new repository.
    cp ../terraform-example-foundation/build/tf-wrapper.sh .
    
  14. Ensure wrapper script can be executed.
    chmod 755 ./tf-wrapper.sh
    
  15. Rename common.auto.example.tfvars to common.auto.tfvars and 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.
  16. Rename bu1-development.auto.example.tfvars to bu1-development.auto.tfvars and update the file with values from your environment.
  17. Rename bu1-non-production.auto.example.tfvars to bu1-non-production.auto.tfvars and update the file with values from your environment.
  18. Rename bu1-production.auto.example.tfvars to bu1-production.auto.tfvars and update the file with values from your environment.
  19. Commit changes.
    git add .
    git commit -m 'Your message'
    
  20. 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.
    git push --set-upstream origin plan
    
  21. Review the plan output in your Cloud Build project https://console.cloud.google.com/cloud-build/builds?project=YOUR_INFRA_PIPELINE_PROJECT_ID
  22. Merge changes to development. Because this is a named environment branch, pushing to this branch triggers both terraform plan and terraform apply.
    git checkout -b development
    git push origin development
    
  23. Review the apply output in your Cloud Build project https://console.cloud.google.com/cloud-build/builds?project=YOUR_INFRA_PIPELINE_PROJECT_ID
  24. Merge changes to non-production. Because this is a named environment branch, pushing to this branch triggers both terraform plan and terraform apply.
    git checkout -b non-production
    git push origin non-production
    
  25. Review the apply output in your Cloud Build project https://console.cloud.google.com/cloud-build/builds?project=YOUR_INFRA_PIPELINE_PROJECT_ID
  26. Merge changes to production branch. Because this is a named environment branch, pushing to this branch triggers both terraform plan and terraform apply.
    git checkout -b production
    git push origin production
    
  27. Review the apply output in your Cloud Build project https://console.cloud.google.com/cloud-build/builds?project=YOUR_INFRA_PIPELINE_PROJECT_ID

Run Terraform locally

  1. Change into 5-app-infra folder, copy the Terraform wrapper script and ensure it can be executed.
    cd 5-app-infra
    cp ../build/tf-wrapper.sh .
    chmod 755 ./tf-wrapper.sh
    
  2. Rename auto.example.tfvars files to auto.tfvars.
    mv common.auto.example.tfvars common.auto.tfvars
    mv bu1-development.auto.example.tfvars bu1-development.auto.tfvars
    mv bu1-non-production.auto.example.tfvars bu1-non-production.auto.tfvars
    mv bu1-production.auto.example.tfvars bu1-production.auto.tfvars
    
  3. Update common.auto.tfvars file with values from your environment.
  4. Update files bu1-development.auto.tfvars, bu1-non-production.auto.tfvars, and bu1-production.auto.tfvars with values from 4-projects output.
  5. Use terraform output to get the project service account values from 4-projects output.
    export dev_sa=$(terraform -chdir="../4-projects/business_unit_1/development/" output -raw base_shared_vpc_project_sa)
    export non_prod_sa=$(terraform -chdir="../4-projects/business_unit_1/non-production/" output -raw base_shared_vpc_project_sa)
    export prod_sa=$(terraform -chdir="../4-projects/business_unit_1/production/" output -raw base_shared_vpc_project_sa)
    
    echo "development project_service_account = ${dev_sa}"
    echo "non-production project_service_account = ${non_prod_sa}"
    echo "production project_service_account = ${prod_sa}"
    
  6. Provide the user that will be running ./tf-wrapper.sh the Service Account Token Creator role to the bu1 project service accounts
  7. 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}
    
    dev_project=$(terraform -chdir="../4-projects/business_unit_1/development/" output -raw base_shared_vpc_project)
    non_prod_project=$(terraform -chdir="../4-projects/business_unit_1/non-production/" output -raw base_shared_vpc_project)
    prod_project=$(terraform -chdir="../4-projects/business_unit_1/production/" output -raw base_shared_vpc_project)
    
    gcloud iam service-accounts add-iam-policy-binding "${dev_sa}" --project "${dev_project}" --member="${member}" --role="roles/iam.serviceAccountTokenCreator"
    gcloud iam service-accounts add-iam-policy-binding "${non_prod_sa}" --project "${non_prod_project}" --member="${member}" --role="roles/iam.serviceAccountTokenCreator"
    gcloud iam service-accounts add-iam-policy-binding "${prod_sa}" --project "${prod_project}" --member="${member}" --role="roles/iam.serviceAccountTokenCreator"
    
  8. Update backend.tf with your bucket from the infra pipeline example.
    export backend_bucket=$(terraform -chdir="../4-projects/business_unit_1/shared/" output -json state_buckets | jq '.[0]' | tr -d '"')
    echo "backend_bucket = ${backend_bucket}"
    
    for i in `find -name 'backend.tf'`; do sed -i "s/UPDATE_ME/${backend_bucket}/" $i; done
    

We will now deploy each of our environments (development/production/non-production) 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.

  1. 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}
    
  2. Run init and plan and review output for environment production.
    ./tf-wrapper.sh init production
    ./tf-wrapper.sh plan production
    
  3. Run validate and check for violations.
    ./tf-wrapper.sh validate production $(pwd)/../policy-library ${INFRA_PIPELINE_PROJECT_ID}
    
  4. Run apply production.
    ./tf-wrapper.sh apply production
    
  5. Run init and plan and review output for environment non-production.
    ./tf-wrapper.sh init non-production
    ./tf-wrapper.sh plan non-production
    
  6. Run validate and check for violations.
    ./tf-wrapper.sh validate non-production $(pwd)/../policy-library ${INFRA_PIPELINE_PROJECT_ID}
    
  7. Run apply non-production.
    ./tf-wrapper.sh apply non-production
    
  8. Run init and plan and review output for environment development.
    ./tf-wrapper.sh init development
    ./tf-wrapper.sh plan development
    
  9. Run validate and check for violations.
    ./tf-wrapper.sh validate development $(pwd)/../policy-library ${INFRA_PIPELINE_PROJECT_ID}
    
  10. Run apply development.
    ./tf-wrapper.sh apply development
    

If you received any errors or made any changes to the Terraform config or terraform.tfvars you must re-run ./tf-wrapper.sh plan <env> before running ./tf-wrapper.sh apply <env>.