Skip to content

Commit

Permalink
feat: Use Cloud build private pools (#868)
Browse files Browse the repository at this point in the history
* use cloud build private pool

* add validation for peering and vpn configuration

* fix trigger region

* the peered network used in the private the pool should use the local thata can select between the provided or the created network

* update module reference

* add worker pool tests

* configure firewall for the peered network

* use secret manager for vpn secret in cloud build private pool vpn

* secret manager must use the same flag of the vpn

* use peering routes config to enable import/export of custom routes to allow connection to on-prem

* create workspace for bootstrap

* Revert "create workspace for bootstrap"

This reverts commit 3989503.

* use network name for peering routes config

* disable creation of the default terraform service account

* fix linting

* Adding custom ip range for Peered PP connection to VPN HA Router

* expose the peered IP range of the private pool as an output

* update bootstrap references

* set region in gcloud beta builds triggers list test

* use the common_config output in integration tests

* bump bootstrap version to 6.3

* add section regarding private pools in the 0-bootstrap README.

* move Cloud Build on-prem instrucions to onprem.md

Co-authored-by: mauro-cit <maurosj@ciandt.com>
  • Loading branch information
daniel-cit and mauro-cit committed Nov 17, 2022
1 parent e449be5 commit ca06365
Show file tree
Hide file tree
Showing 30 changed files with 639 additions and 48 deletions.
8 changes: 8 additions & 0 deletions 0-bootstrap/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,10 @@ All groups in the `groups.required_groups` are required.

All groups in the `groups.optional_groups` are optional.

### Optional - Cloud Build access to on-prem

Please refer to [onprem](./onprem.md) for instructions on how to configure Cloud Build access to on-prem.

### Troubleshooting

Please refer to [troubleshooting](../docs/TROUBLESHOOTING.md) if you run into issues during this step.
Expand Down Expand Up @@ -287,6 +291,10 @@ Each step has instructions for this change.
| Name | Description |
|------|-------------|
| bootstrap\_step\_terraform\_service\_account\_email | Bootstrap Step Terraform Account |
| cloud\_build\_peered\_network\_id | The ID of the Cloud Build peered network. |
| cloud\_build\_private\_worker\_pool\_id | ID of the Cloud Build private worker pool. |
| cloud\_build\_worker\_peered\_ip\_range | The IP range of the peered service network. |
| cloud\_build\_worker\_range\_id | The Cloud Build private worker IP range ID. |
| cloud\_builder\_artifact\_repo | GAR Repo created to store TF Cloud Builder images. |
| cloudbuild\_project\_id | Project where CloudBuild configuration and terraform container image will reside. |
| common\_config | Common configuration data to be used in other steps. |
Expand Down
36 changes: 31 additions & 5 deletions 0-bootstrap/cb.tf
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ locals {
"gcp-bootstrap",
local.cloudbuilder_repo,
]
gar_repository = split("/", module.tf_cloud_builder.artifact_repo)[length(split("/", module.tf_cloud_builder.artifact_repo)) - 1]
gar_repository = split("/", module.tf_cloud_builder.artifact_repo)[length(split("/", module.tf_cloud_builder.artifact_repo)) - 1]
cloud_builder_trigger_id = element(split("/", module.tf_cloud_builder.cloudbuild_trigger_id), index(split("/", module.tf_cloud_builder.cloudbuild_trigger_id), "triggers") + 1, )
}

resource "random_string" "suffix" {
Expand All @@ -76,7 +77,7 @@ module "gcp_projects_state_bucket" {

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

org_id = var.org_id
folder_id = google_folder.bootstrap.id
Expand Down Expand Up @@ -121,16 +122,38 @@ module "tf_source" {
depends_on = [module.seed_bootstrap]
}

module "tf_private_pool" {
source = "./modules/cb-private-pool"

project_id = module.tf_source.cloudbuild_project_id

private_worker_pool = {
region = var.default_region,
enable_network_peering = true,
create_peered_network = true,
peered_network_subnet_ip = "10.10.20.0/24"
peering_address = "192.168.0.0"
peering_prefix_length = 24
}

vpn_configuration = {
enable_vpn = false
}
}

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

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
trigger_location = var.default_region
enable_worker_pool = true
worker_pool_id = module.tf_private_pool.private_worker_pool_id
}

module "bootstrap_csr_repo" {
Expand Down Expand Up @@ -160,7 +183,7 @@ module "build_terraform_image" {
"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}"
create_cmd_body = "beta builds triggers run ${local.cloud_builder_trigger_id} --branch main --region ${var.default_region} --project ${module.tf_source.cloudbuild_project_id}"

module_depends_on = [
time_sleep.cloud_builder,
Expand All @@ -169,11 +192,14 @@ module "build_terraform_image" {

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

project_id = module.tf_source.cloudbuild_project_id
location = var.default_region
trigger_location = var.default_region
enable_worker_pool = true
worker_pool_id = module.tf_private_pool.private_worker_pool_id
state_bucket_self_link = local.cb_config[each.key].state_bucket
cloudbuild_plan_filename = "cloudbuild-tf-plan.yaml"
cloudbuild_apply_filename = "cloudbuild-tf-apply.yaml"
Expand Down
6 changes: 4 additions & 2 deletions 0-bootstrap/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,9 @@ resource "google_folder" "bootstrap" {
}

module "seed_bootstrap" {
source = "terraform-google-modules/bootstrap/google"
version = "~> 6.2"
source = "terraform-google-modules/bootstrap/google"
version = "~> 6.3"

org_id = var.org_id
folder_id = google_folder.bootstrap.id
project_id = "${var.project_prefix}-b-seed"
Expand All @@ -57,6 +58,7 @@ module "seed_bootstrap" {
default_region = var.default_region
org_project_creators = local.org_project_creators
sa_enable_impersonation = true
create_terraform_sa = false
parent_folder = var.parent_folder == "" ? "" : local.parent
org_admins_org_iam_permissions = local.org_admins_org_iam_permissions
project_prefix = var.project_prefix
Expand Down
19 changes: 19 additions & 0 deletions 0-bootstrap/modules/cb-private-pool/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<!-- BEGINNING OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| private\_worker\_pool | name: Name of the worker pool. A name with a random suffix is generated if not set.<br> region: The private worker pool region. See https://cloud.google.com/build/docs/locations for available locations.<br> disk\_size\_gb: Size of the disk attached to the worker, in GB.<br> machine\_type: Machine type of a worker.<br> no\_external\_ip: If true, workers are created without any public address, which prevents network egress to public IPs.<br> enable\_network\_peering: Set to true to enable configuration of networking peering for the private worker pool.<br> create\_peered\_network: If true a network will be created to stablish the network peering.<br> peered\_network\_id: The ID of the existing network to configure peering for the private worker pool if create\_peered\_network false. The project containing the network must have Service Networking API (`servicenetworking.googleapis.com`) enabled.<br> peered\_network\_subnet\_ip: The IP range to be used for the subnet that a will created in the peered network if create\_peered\_network true.<br> peering\_address: The IP address or beginning of the peering address range. This can be supplied as an input to reserve a specific address or omitted to allow GCP to choose a valid one.<br> peering\_prefix\_length: The prefix length of the IP peering range. If not present, it means the address field is a single IP address. | <pre>object({<br> name = optional(string, "")<br> region = optional(string, "us-central1")<br> disk_size_gb = optional(number, 100)<br> machine_type = optional(string, "e2-medium")<br> no_external_ip = optional(bool, false)<br> enable_network_peering = optional(bool, false)<br> create_peered_network = optional(bool, false)<br> peered_network_id = optional(string, "")<br> peered_network_subnet_ip = optional(string, "")<br> peering_address = optional(string, null)<br> peering_prefix_length = optional(number, 24)<br> })</pre> | `{}` | no |
| project\_id | ID of the project where the private pool will be created | `string` | n/a | yes |
| vpn\_configuration | enable\_vpn: set to true to create VPN connection to on prem. If true, the following values must be valid.<br> on\_prem\_public\_ip\_address0: The first public IP address for on prem VPN connection.<br> on\_prem\_public\_ip\_address1: The second public IP address for on prem VPN connection.<br> router\_asn: Border Gateway Protocol (BGP) Autonomous System Number (ASN) for cloud routes.<br> bgp\_peer\_asn: Border Gateway Protocol (BGP) Autonomous System Number (ASN) for peer cloud routes.<br> shared\_secret: The shared secret used in the VPN.<br> psk\_secret\_project\_id: The ID of the project that contains the secret from secret manager that holds the VPN pre-shared key.<br> psk\_secret\_name: The name of the secret to retrieve from secret manager that holds the VPN pre-shared key.<br> tunnel0\_bgp\_peer\_address: BGP peer address for tunnel 0.<br> tunnel0\_bgp\_session\_range: BGP session range for tunnel 0.<br> tunnel1\_bgp\_peer\_address: BGP peer address for tunnel 1.<br> tunnel1\_bgp\_session\_range: BGP session range for tunnel 1. | <pre>object({<br> enable_vpn = optional(bool, false)<br> on_prem_public_ip_address0 = optional(string, "")<br> on_prem_public_ip_address1 = optional(string, "")<br> router_asn = optional(number, 64515)<br> bgp_peer_asn = optional(number, 64513)<br> psk_secret_project_id = optional(string, "")<br> psk_secret_name = optional(string, "")<br> tunnel0_bgp_peer_address = optional(string, "")<br> tunnel0_bgp_session_range = optional(string, "")<br> tunnel1_bgp_peer_address = optional(string, "")<br> tunnel1_bgp_session_range = optional(string, "")<br> })</pre> | `{}` | no |

## Outputs

| Name | Description |
|------|-------------|
| peered\_network\_id | The ID of the peered network. |
| private\_worker\_pool\_id | Private worker pool ID. |
| worker\_peered\_ip\_range | The IP range of the peered service network. |
| worker\_range\_id | The worker IP range ID. |

<!-- END OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
52 changes: 52 additions & 0 deletions 0-bootstrap/modules/cb-private-pool/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/**
* 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 {
network_name = "vpc-peered-network"
private_pool_name = var.private_worker_pool.name != "" ? var.private_worker_pool.name : "private-pool-${random_string.suffix.result}"
peered_network_id = !var.private_worker_pool.enable_network_peering ? "" : var.private_worker_pool.peered_network_id != "" ? var.private_worker_pool.peered_network_id : module.peered_network[0].network_id
peered_network_name = element(split("/", local.peered_network_id), index(split("/", local.peered_network_id), "networks") + 1, )
}

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

resource "google_cloudbuild_worker_pool" "private_pool" {
name = local.private_pool_name
project = var.project_id
location = var.private_worker_pool.region

worker_config {
disk_size_gb = var.private_worker_pool.disk_size_gb
machine_type = var.private_worker_pool.machine_type
no_external_ip = var.private_worker_pool.no_external_ip
}

dynamic "network_config" {
for_each = var.private_worker_pool.enable_network_peering ? ["network_config"] : []
content {
peered_network = local.peered_network_id
}
}

depends_on = [
google_compute_global_address.worker_pool_range,
google_service_networking_connection.worker_pool_conn,
]
}
105 changes: 105 additions & 0 deletions 0-bootstrap/modules/cb-private-pool/network.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/**
* 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 {
peered_ip_range = var.private_worker_pool.enable_network_peering ? "${google_compute_global_address.worker_pool_range[0].address}/${google_compute_global_address.worker_pool_range[0].prefix_length}" : ""
}

module "peered_network" {
source = "terraform-google-modules/network/google"
version = "~> 5.2"
count = var.private_worker_pool.create_peered_network ? 1 : 0

project_id = var.project_id
network_name = local.network_name
delete_default_internet_gateway_routes = "true"

subnets = [
{
subnet_name = "sb-peered"
subnet_ip = var.private_worker_pool.peered_network_subnet_ip
subnet_region = var.private_worker_pool.region
subnet_private_access = "true"
subnet_flow_logs = "true"
description = "Peered subnet for Cloud Build private pool"
}
]

}

resource "google_compute_global_address" "worker_pool_range" {
count = var.private_worker_pool.enable_network_peering ? 1 : 0

name = "ga-worker-pool-range-vpc-peering"
project = var.project_id
purpose = "VPC_PEERING"
address_type = "INTERNAL"
address = var.private_worker_pool.peering_address
prefix_length = var.private_worker_pool.peering_prefix_length
network = local.peered_network_id
}

resource "google_service_networking_connection" "worker_pool_conn" {
count = var.private_worker_pool.enable_network_peering ? 1 : 0

network = local.peered_network_id
service = "servicenetworking.googleapis.com"
reserved_peering_ranges = [google_compute_global_address.worker_pool_range[0].name]
}

resource "google_compute_network_peering_routes_config" "peering_routes" {
count = var.private_worker_pool.enable_network_peering ? 1 : 0

project = var.project_id
peering = google_service_networking_connection.worker_pool_conn[0].peering
network = local.peered_network_name

import_custom_routes = true
export_custom_routes = true
}

module "firewall_rules" {
source = "terraform-google-modules/network/google//modules/firewall-rules"
version = "~> 5.2"
count = var.private_worker_pool.enable_network_peering ? 1 : 0

project_id = var.project_id
network_name = local.peered_network_id

rules = [{
name = "allow-servicenetworking-ingress"
description = "allow ingres from the IPs configured for service networking"
direction = "INGRESS"
priority = 100
source_tags = null
source_service_accounts = null
target_tags = null
target_service_accounts = null

ranges = [local.peered_ip_range]

allow = [{
protocol = "all"
ports = null
}]

deny = []

log_config = {
metadata = "INCLUDE_ALL_METADATA"
}
}]
}
35 changes: 35 additions & 0 deletions 0-bootstrap/modules/cb-private-pool/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/**
* 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.
*/

output "private_worker_pool_id" {
description = "Private worker pool ID."
value = google_cloudbuild_worker_pool.private_pool.id
}

output "worker_range_id" {
description = "The worker IP range ID."
value = try(google_compute_global_address.worker_pool_range[0].id, "")
}

output "worker_peered_ip_range" {
description = "The IP range of the peered service network."
value = local.peered_ip_range
}

output "peered_network_id" {
description = "The ID of the peered network."
value = local.peered_network_id
}

0 comments on commit ca06365

Please sign in to comment.