Skip to content

Commit

Permalink
feat: App Infra pipelines (#337)
Browse files Browse the repository at this point in the history
* initial impl

* add tests

* fmt

* address comments

* fix checksums for 0.13.6

* fix validator version

* update readmes

* update docs
  • Loading branch information
bharathkkb committed Mar 31, 2021
1 parent 8c13603 commit c3b19e8
Show file tree
Hide file tree
Showing 57 changed files with 1,252 additions and 11 deletions.
14 changes: 9 additions & 5 deletions 4-projects/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# 4-projects

The purpose of this step is to set up folder structure and projects for applications, which are connected as service projects to the shared VPC created in the previous stage.
The purpose of this step is to set up folder structure, projects and infrastructure pipelines for applications, which are connected as service projects to the shared VPC created in the previous stage. For each business unit, a shared `sample-infra` project is created along with Cloud Build triggers, CSRs for application infrastructure code, GCS buckets for state storage and follows the same [conventions](https://github.com/terraform-google-modules/terraform-example-foundation#branching-strategy) as the foundation pipeline deployed in [0-bootstrap](https://github.com/terraform-google-modules/terraform-example-foundation/blob/master/0-bootstrap/README.md). The cloudbuild SA used by this pipeline can impersonate the project SA by enabling the `enable_cloudbuild_deploy` flag and necessary roles can be granted to this SA via `sa_roles` as show in this [example](business_unit_1/development/example_base_shared_vpc_project.tf). This pipeline can be utilized for deploying resources in projects across development/non-production/production with granular permissions.

## Prerequisites

Expand Down Expand Up @@ -29,12 +29,12 @@ If your user does not have access to run the commands above and you are in the o
1. Commit changes with `git add .` and `git commit -m 'Your message'`.
1. Push your plan branch to trigger a plan `git push --set-upstream origin plan` (the branch `plan` is not a special one. Any branch which name is different from `development`, `non-production` or `production` will trigger a terraform plan).
1. Review the plan output in your cloud build project https://console.cloud.google.com/cloud-build/builds?project=YOUR_CLOUD_BUILD_PROJECT_ID
1. Merge changes to production with `git checkout -b production` and `git push origin production`.
1. Review the apply output in your cloud build project. https://console.cloud.google.com/cloud-build/builds?project=YOUR_CLOUD_BUILD_PROJECT_ID
1. Merge changes to development with `git checkout -b development` and `git push origin development`.
1. Review the apply output in your cloud build project https://console.cloud.google.com/cloud-build/builds?project=YOUR_CLOUD_BUILD_PROJECT_ID
1. Merge changes to non-production with `git checkout -b non-production` and `git push origin non-production`.
1. Review the apply output in your cloud build project. https://console.cloud.google.com/cloud-build/builds?project=YOUR_CLOUD_BUILD_PROJECT_ID
1. Merge changes to production with `git checkout -b production` and `git push origin production`.
1. Review the apply output in your cloud build project. https://console.cloud.google.com/cloud-build/builds?project=YOUR_CLOUD_BUILD_PROJECT_ID


### Setup to run via Jenkins
Expand All @@ -58,13 +58,13 @@ If your user does not have access to run the commands above and you are in the o
1. Push your plan branch `git push --set-upstream origin plan`. The branch `plan` is not a special one. Any branch which name is different from `development`, `non-production` or `production` will trigger a terraform plan.
- Assuming you configured an automatic trigger in your Jenkins Master (see [Jenkins sub-module README](../0-bootstrap/modules/jenkins-agent)), this will trigger a plan. You can also trigger a Jenkins job manually. Given the many options to do this in Jenkins, it is out of the scope of this document see [Jenkins website](http://www.jenkins.io) for more details.
1. Review the plan output in your Master's web UI.
1. Merge changes to production branch with `git checkout -b production` and `git push origin production`.
1. Review the apply output in your Master's web UI (You might want to use the option to "Scan Multibranch Pipeline Now" in your Jenkins Master UI).
1. After production has been applied apply development and non-production.
1. Merge changes to development branch with `git checkout -b development` and `git push origin development`.
1. Review the apply output in your Master's web UI (You might want to use the option to "Scan Multibranch Pipeline Now" in your Jenkins Master UI).
1. Merge changes to non-production branch with `git checkout -b non-production` and `git push origin non-production`.
1. Review the apply output in your Master's web UI (You might want to use the option to "Scan Multibranch Pipeline Now" in your Jenkins Master UI).
1. Merge changes to production branch with `git checkout -b production` and `git push origin production`.
1. Review the apply output in your Master's web UI (You might want to use the option to "Scan Multibranch Pipeline Now" in your Jenkins Master UI).

1. You can now move to the instructions in the step [4-projects](../4-projects/README.md).

Expand All @@ -85,6 +85,10 @@ When using Cloud Build or Jenkins as your CI/CD tool each environment correspond

To use the `validate` option of the `tf-wrapper.sh` script, the latest version of `terraform-validator` must be [installed](https://github.com/forseti-security/policy-library/blob/master/docs/user_guide.md#how-to-use-terraform-validator) in your system and in you `PATH`.

1. Run `./tf-wrapper.sh init shared`.
1. Run `./tf-wrapper.sh plan shared` and review output.
1. Run `./tf-wrapper.sh validate shared $(pwd)/../policy-library <YOUR_CLOUD_BUILD_PROJECT_ID>` and check for violations.
1. Run `./tf-wrapper.sh apply shared`.
1. Run `./tf-wrapper.sh init production`.
1. Run `./tf-wrapper.sh plan production` and review output.
1. Run `./tf-wrapper.sh validate production $(pwd)/../policy-library <YOUR_CLOUD_BUILD_PROJECT_ID>` and check for violations.
Expand Down
2 changes: 2 additions & 0 deletions 4-projects/business_unit_1/development/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
| access\_context\_manager\_policy\_id | The ID of the access context manager policy the perimeter lies in. Can be obtained by running `gcloud access-context-manager policies list --organization YOUR-ORGANIZATION_ID --format="value(name)"`. | `string` | n/a | yes |
| alert\_pubsub\_topic | The name of the Cloud Pub/Sub topic where budget related messages will be published, in the form of `projects/{project_id}/topics/{topic_id}` | `string` | `null` | no |
| alert\_spent\_percents | A list of percentages of the budget to alert on when threshold is exceeded | `list(number)` | <pre>[<br> 0.5,<br> 0.75,<br> 0.9,<br> 0.95<br>]</pre> | no |
| app\_infra\_pipeline\_cloudbuild\_sa | Cloud Build SA used for deploying infrastructure | `string` | n/a | yes |
| billing\_account | The ID of the billing account to associated this project with | `string` | n/a | yes |
| budget\_amount | The amount to use as the budget | `number` | `1000` | no |
| enable\_hub\_and\_spoke | Enable Hub-and-Spoke architecture. | `bool` | `false` | no |
Expand All @@ -26,6 +27,7 @@
|------|-------------|
| access\_context\_manager\_policy\_id | Access Context Manager Policy ID. |
| base\_shared\_vpc\_project | Project sample base project. |
| base\_shared\_vpc\_project\_sa | Project sample base project SA. |
| floating\_project | Project sample floating project. |
| peering\_complete | Output to be used as a module dependency. |
| peering\_network | Peer network peering resource. |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ module "base_shared_vpc_project" {
budget_amount = var.budget_amount
project_prefix = var.project_prefix
enable_hub_and_spoke = var.enable_hub_and_spoke
sa_roles = ["roles/editor"]
enable_cloudbuild_deploy = true
cloudbuild_sa = var.app_infra_pipeline_cloudbuild_sa

# Metadata
project_suffix = "sample-base"
Expand Down
5 changes: 5 additions & 0 deletions 4-projects/business_unit_1/development/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ output "base_shared_vpc_project" {
value = module.base_shared_vpc_project.project_id
}

output "base_shared_vpc_project_sa" {
description = "Project sample base project SA."
value = module.base_shared_vpc_project.sa
}

output "floating_project" {
description = "Project sample floating project."
value = module.floating_project.project_id
Expand Down
5 changes: 5 additions & 0 deletions 4-projects/business_unit_1/development/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -104,3 +104,8 @@ variable "enable_hub_and_spoke" {
type = bool
default = false
}

variable "app_infra_pipeline_cloudbuild_sa" {
description = "Cloud Build SA used for deploying infrastructure"
type = string
}
2 changes: 2 additions & 0 deletions 4-projects/business_unit_1/non-production/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
| access\_context\_manager\_policy\_id | The ID of the access context manager policy the perimeter lies in. Can be obtained by running `gcloud access-context-manager policies list --organization YOUR-ORGANIZATION_ID --format="value(name)"`. | `string` | n/a | yes |
| alert\_pubsub\_topic | The name of the Cloud Pub/Sub topic where budget related messages will be published, in the form of `projects/{project_id}/topics/{topic_id}` | `string` | `null` | no |
| alert\_spent\_percents | A list of percentages of the budget to alert on when threshold is exceeded | `list(number)` | <pre>[<br> 0.5,<br> 0.75,<br> 0.9,<br> 0.95<br>]</pre> | no |
| app\_infra\_pipeline\_cloudbuild\_sa | Cloud Build SA used for deploying infrastructure | `string` | n/a | yes |
| billing\_account | The ID of the billing account to associated this project with | `string` | n/a | yes |
| budget\_amount | The amount to use as the budget | `number` | `1000` | no |
| enable\_hub\_and\_spoke | Enable Hub-and-Spoke architecture. | `bool` | `false` | no |
Expand All @@ -26,6 +27,7 @@
|------|-------------|
| access\_context\_manager\_policy\_id | Access Context Manager Policy ID. |
| base\_shared\_vpc\_project | Project sample base project. |
| base\_shared\_vpc\_project\_sa | Project sample base project SA. |
| floating\_project | Project sample floating project. |
| peering\_complete | Output to be used as a module dependency. |
| peering\_network | Peer network peering resource. |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ module "base_shared_vpc_project" {
budget_amount = var.budget_amount
project_prefix = var.project_prefix
enable_hub_and_spoke = var.enable_hub_and_spoke
sa_roles = ["roles/editor"]
enable_cloudbuild_deploy = true
cloudbuild_sa = var.app_infra_pipeline_cloudbuild_sa

# Metadata
project_suffix = "sample-base"
Expand Down
5 changes: 5 additions & 0 deletions 4-projects/business_unit_1/non-production/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ output "base_shared_vpc_project" {
value = module.base_shared_vpc_project.project_id
}

output "base_shared_vpc_project_sa" {
description = "Project sample base project SA."
value = module.base_shared_vpc_project.sa
}

output "floating_project" {
description = "Project sample floating project."
value = module.floating_project.project_id
Expand Down
5 changes: 5 additions & 0 deletions 4-projects/business_unit_1/non-production/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -104,3 +104,8 @@ variable "enable_hub_and_spoke" {
type = bool
default = false
}

variable "app_infra_pipeline_cloudbuild_sa" {
description = "Cloud Build SA used for deploying infrastructure"
type = string
}
2 changes: 2 additions & 0 deletions 4-projects/business_unit_1/production/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
| access\_context\_manager\_policy\_id | The ID of the access context manager policy the perimeter lies in. Can be obtained by running `gcloud access-context-manager policies list --organization YOUR-ORGANIZATION_ID --format="value(name)"`. | `string` | n/a | yes |
| alert\_pubsub\_topic | The name of the Cloud Pub/Sub topic where budget related messages will be published, in the form of `projects/{project_id}/topics/{topic_id}` | `string` | `null` | no |
| alert\_spent\_percents | A list of percentages of the budget to alert on when threshold is exceeded | `list(number)` | <pre>[<br> 0.5,<br> 0.75,<br> 0.9,<br> 0.95<br>]</pre> | no |
| app\_infra\_pipeline\_cloudbuild\_sa | Cloud Build SA used for deploying infrastructure | `string` | n/a | yes |
| billing\_account | The ID of the billing account to associated this project with | `string` | n/a | yes |
| budget\_amount | The amount to use as the budget | `number` | `1000` | no |
| enable\_hub\_and\_spoke | Enable Hub-and-Spoke architecture. | `bool` | `false` | no |
Expand All @@ -27,6 +28,7 @@
|------|-------------|
| access\_context\_manager\_policy\_id | Access Context Manager Policy ID. |
| base\_shared\_vpc\_project | Project sample base project. |
| base\_shared\_vpc\_project\_sa | Project sample base project SA. |
| floating\_project | Project sample floating project. |
| peering\_complete | Output to be used as a module dependency. |
| peering\_network | Peer network peering resource. |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ module "base_shared_vpc_project" {
budget_amount = var.budget_amount
project_prefix = var.project_prefix
enable_hub_and_spoke = var.enable_hub_and_spoke
sa_roles = ["roles/editor"]
enable_cloudbuild_deploy = true
cloudbuild_sa = var.app_infra_pipeline_cloudbuild_sa

# Metadata
project_suffix = "sample-base"
Expand Down
5 changes: 5 additions & 0 deletions 4-projects/business_unit_1/production/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ output "base_shared_vpc_project" {
value = module.base_shared_vpc_project.project_id
}

output "base_shared_vpc_project_sa" {
description = "Project sample base project SA."
value = module.base_shared_vpc_project.sa
}

output "floating_project" {
description = "Project sample floating project."
value = module.floating_project.project_id
Expand Down
5 changes: 5 additions & 0 deletions 4-projects/business_unit_1/production/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -110,3 +110,8 @@ variable "enable_hub_and_spoke" {
type = bool
default = false
}

variable "app_infra_pipeline_cloudbuild_sa" {
description = "Cloud Build SA used for deploying infrastructure"
type = string
}
28 changes: 28 additions & 0 deletions 4-projects/business_unit_1/shared/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<!-- BEGINNING OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| alert\_pubsub\_topic | The name of the Cloud Pub/Sub topic where budget related messages will be published, in the form of `projects/{project_id}/topics/{topic_id}` | `string` | `null` | no |
| alert\_spent\_percents | A list of percentages of the budget to alert on when threshold is exceeded | `list(number)` | <pre>[<br> 0.5,<br> 0.75,<br> 0.9,<br> 0.95<br>]</pre> | no |
| billing\_account | The ID of the billing account to associated this project with | `string` | n/a | yes |
| budget\_amount | The amount to use as the budget | `number` | `1000` | no |
| folder\_prefix | Name prefix to use for folders created. | `string` | `"fldr"` | no |
| org\_id | The organization id for the associated services | `string` | n/a | yes |
| parent\_folder | Optional - if using a folder for testing. | `string` | `""` | no |
| project\_prefix | Name prefix to use for projects created. | `string` | `"prj"` | no |
| terraform\_service\_account | Service account email of the account to impersonate to run Terraform | `string` | n/a | yes |

## Outputs

| Name | Description |
|------|-------------|
| apply\_triggers | CB apply triggers |
| artifact\_buckets | GCS Buckets to store Cloud Build Artifacts |
| cloudbuild\_project\_id | n/a |
| cloudbuild\_sa | Cloud Build service account |
| plan\_triggers | CB plan triggers |
| repos | CSRs to store source code |
| state\_buckets | GCS Buckets to store TF state |

<!-- END OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
1 change: 1 addition & 0 deletions 4-projects/business_unit_1/shared/common.auto.tfvars
45 changes: 45 additions & 0 deletions 4-projects/business_unit_1/shared/example_infra_pipeline.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/**
* Copyright 2021 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.
*/

module "app_infra_cloudbuild_project" {
source = "../../modules/single_project"
impersonate_service_account = var.terraform_service_account
org_id = var.org_id
billing_account = var.billing_account
folder_id = data.google_active_folder.common.name
environment = "shared"
alert_spent_percents = var.alert_spent_percents
alert_pubsub_topic = var.alert_pubsub_topic
budget_amount = var.budget_amount
project_prefix = var.project_prefix
activate_apis = ["cloudbuild.googleapis.com", "sourcerepo.googleapis.com", "cloudkms.googleapis.com"]

# Metadata
project_suffix = "sample-infra"
application_name = "app-infra-pipelines"
billing_code = "1234"
primary_contact = "example@example.com"
secondary_contact = "example2@example.com"
business_code = "bu1"
}

module "infra_pipelines" {
source = "../../modules/infra_pipelines"
cloudbuild_project_id = module.app_infra_cloudbuild_project.project_id
billing_account = var.billing_account
app_infra_repos = ["bu1-example-app"]
}

20 changes: 20 additions & 0 deletions 4-projects/business_unit_1/shared/folder.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* Copyright 2021 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.
*/

data "google_active_folder" "common" {
display_name = "${var.folder_prefix}-common"
parent = var.parent_folder != "" ? "folders/${var.parent_folder}" : "organizations/${var.org_id}"
}
49 changes: 49 additions & 0 deletions 4-projects/business_unit_1/shared/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
* Copyright 2021 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.
*/

output "cloudbuild_project_id" {
value = module.app_infra_cloudbuild_project.project_id
}

output "cloudbuild_sa" {
description = "Cloud Build service account"
value = module.infra_pipelines.cloudbuild_sa
}

output "repos" {
description = "CSRs to store source code"
value = module.infra_pipelines.repos
}

output "artifact_buckets" {
description = "GCS Buckets to store Cloud Build Artifacts"
value = module.infra_pipelines.artifact_buckets
}

output "state_buckets" {
description = "GCS Buckets to store TF state"
value = module.infra_pipelines.state_buckets
}

output "plan_triggers" {
description = "CB plan triggers"
value = module.infra_pipelines.plan_triggers
}

output "apply_triggers" {
description = "CB apply triggers"
value = module.infra_pipelines.apply_triggers
}

0 comments on commit c3b19e8

Please sign in to comment.