Skip to content

Commit

Permalink
feat!: Configure bring your own service account in bootstrap (#777)
Browse files Browse the repository at this point in the history
* configure byosa

* update list of allowed APIs

* fix integration tests

* fix permissions and log bucket

* fix linting

* add log bucket for infra pipeline

* set the version of the terraform image

* google terraform module exclusion

* remove service account impersonation

* nyosa in step 4-projects pipeline infra

* bump tf version to 0.15.5

* build terraform image

* set terraform service account as default member in the perimeter

* byosa in step 4-projects

* bump terrraform version to 1.0.0

* remove members variable

* add missing cloud build sa id

* use impersonate service account to run gcloud build submit

* add terraform tools to step 4 infra pipeline

* set base terraform version in trigger to v1

* restore step 5 providers

* make app infra pipeline compatible with with cloudbuild.yaml files

* add time sleep before creating terraform image

* setting a project is required for gcloud beta terraform vet

* increase wait time in integration build

* remove terraform_service_account from terraform.tfvars in step 2

* export service account for impersonation

* PR fixes

* fix lint

* create local value for docker_tag_version_terraform

* bump bootstrap version to 6.2
  • Loading branch information
daniel-cit committed Aug 24, 2022
1 parent 0d3b515 commit 015fe3d
Show file tree
Hide file tree
Showing 109 changed files with 464 additions and 784 deletions.
39 changes: 39 additions & 0 deletions 0-bootstrap/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Copyright 2022 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

FROM gcr.io/cloud-builders/gcloud-slim

# Use ARG so that values can be overriden by user/cloudbuild
ARG TERRAFORM_VERSION=1.0.0

ENV ENV_TERRAFORM_VERSION=$TERRAFORM_VERSION

RUN apt-get update && \
/builder/google-cloud-sdk/bin/gcloud -q components install alpha beta terraform-tools && \
apt-get -y install curl jq unzip git ca-certificates gnupg && \
curl https://releases.hashicorp.com/terraform/${ENV_TERRAFORM_VERSION}/terraform_${ENV_TERRAFORM_VERSION}_linux_amd64.zip --output terraform_${ENV_TERRAFORM_VERSION}_linux_amd64.zip && \
curl https://releases.hashicorp.com/terraform/${ENV_TERRAFORM_VERSION}/terraform_${ENV_TERRAFORM_VERSION}_SHA256SUMS.sig --output terraform_SHA256SUMS.sig && \
curl https://releases.hashicorp.com/terraform/${ENV_TERRAFORM_VERSION}/terraform_${ENV_TERRAFORM_VERSION}_SHA256SUMS --output terraform_SHA256SUMS && \
curl https://keybase.io/hashicorp/pgp_keys.asc --output pgp_keys.asc && \
gpg --import pgp_keys.asc && \
gpg --verify terraform_SHA256SUMS.sig terraform_SHA256SUMS && \
grep terraform_${ENV_TERRAFORM_VERSION}_linux_amd64.zip terraform_SHA256SUMS | shasum --algorithm 256 --check && \
unzip terraform_${ENV_TERRAFORM_VERSION}_linux_amd64.zip -d /builder/terraform && \
rm -f terraform_${ENV_TERRAFORM_VERSION}_linux_amd64.zip terraform_SHA256SUMS && \
apt-get --purge -y autoremove && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*

ENV PATH=/builder/terraform/:$PATH
ENTRYPOINT ["terraform"]
33 changes: 10 additions & 23 deletions 0-bootstrap/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,9 @@ To run the commands described in this document, you need to have the following
installed:

- The [Google Cloud SDK](https://cloud.google.com/sdk/install) version 391.0.0 or later
- [Terraform](https://www.terraform.io/downloads.html) version 0.13.7.
- An existing project which the user has access to be used by terraform-validator.
- [Terraform](https://www.terraform.io/downloads.html) version 1.0.0 or later

**Note:** Make sure that you use the same version of Terraform throughout this series. Otherwise, you might experience Terraform state snapshot lock errors.
**Note:** Make sure that you use version 1.0.0 or later of Terraform throughout this series. Otherwise, you might experience Terraform state snapshot lock errors.

Also make sure that you've done the following:

Expand Down Expand Up @@ -131,12 +130,16 @@ your current Jenkins manager (controller) environment.
```
1. Run `terraform init`.
1. Run `terraform plan` and review the output.
1. To run terraform-validator steps please follow the [instructions](https://cloud.google.com/docs/terraform/policy-validation/validate-policies#install) to install the terraform-tools component.
1. To run `gcloud beta terraform vet` steps please follow the [instructions](https://cloud.google.com/docs/terraform/policy-validation/validate-policies#install) to install the terraform-tools component.
1. Run `terraform plan -input=false -out bootstrap.tfplan`
1. Run `terraform show -json bootstrap.tfplan > bootstrap.json`
1. Run `gcloud beta terraform vet bootstrap.json --policy-library="../policy-library" --project <A-VALID-PROJECT-ID>` and check for violations (`<A-VALID-PROJECT-ID>` must be an existing project you have access to, this is necessary because Terraform-validator needs to link resources to a valid Google Cloud Platform project).
1. Run `terraform apply`.
1. Run `terraform output terraform_service_account` to get the email address of the admin. You need this address in a later procedure.
1. Run `terraform output organization_step_terraform_service_account_email` to get the email address of the admin of step `1-org`. You need this address in a later procedure.
1. Run `terraform output environment_step_terraform_service_account_email` to get the email address of the admin of step `2-environments`. You need this address in a later procedure.
1. Run `terraform output networks_step_terraform_service_account_email` to get the email address of the admin of steps `3-networks-dual-svpc` and `3-networks-hub-and-spoke`. You need this address in a later procedure.
1. Run `terraform output projects_step_terraform_service_account_email` to get the email address of the admin of step `4-projects`. You need this address in a later procedure.
1. Run `terraform output cloudbuild_project_id` to get the ID of your Cloud Build project.
1. Run `terraform output gcs_bucket_tfstate` to get your Google Cloud bucket name from Terraform's state.
1. Copy the backend:
```
Expand All @@ -148,21 +151,7 @@ your current Jenkins manager (controller) environment.
1. (Optional) Run `terraform apply` to verify that state is configured
correctly. You should see no changes from the previous state.

**Note 1:** The output of terraform-validator will contain lines like

```
ERROR: logging before flag.Parse: I0413 13:49:49.852283 6380 convert.go:189] unsupported resource: google_billing_account_iam_member
```

or

```
ERROR: logging before flag.Parse: I0413 13:49:49.852290 6380 convert.go:183] unknown resource: random_id
```

These are warnings for resources that are not yet supported or not known by terraform-validator, these are not actual errors.

**Note 2:** After the deploy, even if you did not receive the project quota error described in the [Troubleshooting guide](../docs/TROUBLESHOOTING.md#project-quota-exceeded), we recommend that you request 50 additional projects for the service account, `terraform_service_account`, created in this step.
**Note:** After the deploy, even if you did not receive the project quota error described in the [Troubleshooting guide](../docs/TROUBLESHOOTING.md#project-quota-exceeded), we recommend that you request 50 additional projects for the four service accounts created in this step.

## Running Terraform locally

Expand All @@ -186,8 +175,8 @@ the following steps:
| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| billing\_account | The ID of the billing account to associate projects with. | `string` | n/a | yes |
| bucket\_force\_destroy | When deleting a bucket, this boolean option will delete all contained objects. If false, Terraform will fail to delete buckets which contain objects. | `bool` | `false` | no |
| bucket\_prefix | Name prefix to use for state bucket created. | `string` | `"bkt"` | no |
| cloud\_source\_repos | List of Cloud Source Repositories created during bootstrap project build stage for use with Cloud Build. | `list(string)` | <pre>[<br> "gcp-org",<br> "gcp-environments",<br> "gcp-networks",<br> "gcp-projects"<br>]</pre> | no |
| default\_region | Default region to create resources where applicable. | `string` | `"us-central1"` | no |
| folder\_prefix | Name prefix to use for folders created. Should be the same in all steps. | `string` | `"fldr"` | no |
| group\_billing\_admins | Google Group for GCP Billing Administrators | `string` | n/a | yes |
Expand Down Expand Up @@ -216,7 +205,5 @@ the following steps:
| required\_groups | List of Google Groups created that are required by the Example Foundation steps. |
| seed\_project\_id | Project where service accounts and core APIs will be enabled. |
| terraform\_sa\_name | Fully qualified name for privileged service account for Terraform. |
| terraform\_service\_account | Email for privileged service account for Terraform. |
| terraform\_validator\_policies\_repo | Cloud Source Repository created for terraform-validator policies. |

<!-- END OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
171 changes: 171 additions & 0 deletions 0-bootstrap/cb.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@

/**
* Copyright 2022 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

locals {
// terraform version image configuration
terraform_version = "1.0.0"
// The version of the terraform docker image to be used in the workspace builds
docker_tag_version_terraform = "v1"

cb_source = {
"org" = "gcp-org",
"env" = "gcp-environments",
"net" = "gcp-networks",
"proj" = "gcp-projects",
}
cloud_source_repos = values(local.cb_source)
cloudbuilder_repo = "tf-cloudbuilder"
base_cloud_source_repos = [
"gcp-policies",
"gcp-bootstrap",
local.cloudbuilder_repo,
]
gar_repository = split("/", module.tf_cloud_builder.artifact_repo)[length(split("/", module.tf_cloud_builder.artifact_repo)) - 1]
}

resource "random_string" "suffix" {
length = 8
special = false
upper = false
}

module "tf_source" {
source = "terraform-google-modules/bootstrap/google//modules/tf_cloudbuild_source"
version = "~> 6.2"

org_id = var.org_id
folder_id = google_folder.bootstrap.id
project_id = "${var.project_prefix}-b-cicd-${random_string.suffix.result}"
billing_account = var.billing_account
group_org_admins = local.group_org_admins
buckets_force_destroy = var.bucket_force_destroy

activate_apis = [
"serviceusage.googleapis.com",
"servicenetworking.googleapis.com",
"compute.googleapis.com",
"logging.googleapis.com",
"iam.googleapis.com",
"admin.googleapis.com",
"sourcerepo.googleapis.com",
"workflows.googleapis.com",
"artifactregistry.googleapis.com",
"cloudbuild.googleapis.com",
"cloudscheduler.googleapis.com",
"bigquery.googleapis.com",
"cloudresourcemanager.googleapis.com",
"cloudbilling.googleapis.com",
"appengine.googleapis.com",
"storage-api.googleapis.com",
"billingbudgets.googleapis.com",
]

cloud_source_repos = distinct(concat(local.base_cloud_source_repos, local.cloud_source_repos))

project_labels = {
environment = "bootstrap"
application_name = "cloudbuild-bootstrap"
billing_code = "1234"
primary_contact = "example1"
secondary_contact = "example2"
business_code = "abcd"
env_code = "b"
}

# Remove after github.com/terraform-google-modules/terraform-google-bootstrap/issues/160
depends_on = [module.seed_bootstrap]
}

module "tf_cloud_builder" {
source = "terraform-google-modules/bootstrap/google//modules/tf_cloudbuild_builder"
version = "~> 6.2"

project_id = module.tf_source.cloudbuild_project_id
dockerfile_repo_uri = module.tf_source.csr_repos[local.cloudbuilder_repo].url
gar_repo_location = var.default_region
workflow_region = var.default_region
terraform_version = local.terraform_version
cb_logs_bucket_force_destroy = var.bucket_force_destroy
}

module "bootstrap_csr_repo" {
source = "terraform-google-modules/gcloud/google"
version = "~> 3.1.0"
upgrade = false

create_cmd_entrypoint = "${path.module}/scripts/push-to-repo.sh"
create_cmd_body = "${module.tf_source.cloudbuild_project_id} ${split("/", module.tf_source.csr_repos[local.cloudbuilder_repo].id)[3]} ${path.module}/Dockerfile"
}

resource "time_sleep" "cloud_builder" {
create_duration = "30s"

depends_on = [
module.tf_cloud_builder,
module.bootstrap_csr_repo,
]
}

module "build_terraform_image" {
source = "terraform-google-modules/gcloud/google"
version = "~> 3.1.0"
upgrade = false

create_cmd_triggers = {
"terraform_version" = local.terraform_version
}

create_cmd_body = "beta builds triggers run ${split("/", module.tf_cloud_builder.cloudbuild_trigger_id)[3]} --branch main --project ${module.tf_source.cloudbuild_project_id}"

module_depends_on = [
time_sleep.cloud_builder,
]
}

module "tf_workspace" {
source = "terraform-google-modules/bootstrap/google//modules/tf_cloudbuild_workspace"
version = "~> 6.2"
for_each = local.granular_sa

project_id = module.tf_source.cloudbuild_project_id
location = var.default_region
state_bucket_self_link = "${local.bucket_self_link_prefix}${module.seed_bootstrap.gcs_bucket_tfstate}"
cloudbuild_plan_filename = "cloudbuild-tf-plan.yaml"
cloudbuild_apply_filename = "cloudbuild-tf-apply.yaml"
tf_repo_uri = module.tf_source.csr_repos[local.cb_source[each.key]].url
cloudbuild_sa = google_service_account.terraform-env-sa[each.key].id
create_cloudbuild_sa = false
diff_sa_project = true
create_state_bucket = false
buckets_force_destroy = var.bucket_force_destroy

substitutions = {
"_ORG_ID" = var.org_id
"_BILLING_ID" = var.billing_account
"_DEFAULT_REGION" = var.default_region
"_GAR_REPOSITORY" = local.gar_repository
"_DOCKER_TAG_VERSION_TERRAFORM" = local.docker_tag_version_terraform
}

tf_apply_branches = ["development", "non\\-production", "production"]

depends_on = [
module.tf_source,
module.tf_cloud_builder,
]

}

0 comments on commit 015fe3d

Please sign in to comment.