Skip to content

Commit 56450bd

Browse files
authored
feat: add instructions for deployment using GitHub Actions (#955)
1 parent a7ce17e commit 56450bd

File tree

23 files changed

+1449
-78
lines changed

23 files changed

+1449
-78
lines changed

0-bootstrap/README-GitHub.md

Lines changed: 936 additions & 0 deletions
Large diffs are not rendered by default.

0-bootstrap/README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,12 @@ for requirements and instructions on how to run the 0-bootstrap step. Using
122122
Jenkins requires a few manual steps, including configuring connectivity with
123123
your current Jenkins manager (controller) environment.
124124

125+
## Deploying with GitHub Actions
126+
127+
If you are deploying using [GitHub Actions](https://docs.github.com/en/actions), see [README-GitHub.md](./README-GitHub.md)
128+
for requirements and instructions on how to run the 0-bootstrap step.
129+
Using GitHub Actions requires manual creation of the GitHub repositories used in each stage.
130+
125131
## Deploying with Cloud Build
126132

127133
1. Clone [terraform-example-foundation](https://github.com/terraform-google-modules/terraform-example-foundation) into your local environment and navigate to the `0-bootstrap` folder.

0-bootstrap/github.tf.example

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
/**
2+
* Copyright 2022 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
18+
provider "github" {
19+
owner = var.gh_repos.owner
20+
token = var.gh_token
21+
}
22+
23+
locals {
24+
cicd_project_id = module.gh_cicd.project_id
25+
26+
gh_config = {
27+
"bootstrap" = var.gh_repos.bootstrap,
28+
"org" = var.gh_repos.organization,
29+
"env" = var.gh_repos.environments,
30+
"net" = var.gh_repos.networks,
31+
"proj" = var.gh_repos.projects,
32+
}
33+
34+
sa_mapping = {
35+
for k, v in local.gh_config : k => {
36+
sa_name = google_service_account.terraform-env-sa[k].name
37+
attribute = "attribute.repository/${var.gh_repos.owner}/${v}"
38+
}
39+
}
40+
41+
commom_secrets = {
42+
"PROJECT_ID" : module.gh_cicd.project_id,
43+
"WIF_PROVIDER_NAME" : module.gh_oidc.provider_name,
44+
"TF_BACKEND" : module.seed_bootstrap.gcs_bucket_tfstate,
45+
"TF_VAR_gh_token": var.gh_token,
46+
}
47+
48+
secrets_list = flatten([
49+
for k, v in local.gh_config : [
50+
for secret, plaintext in local.commom_secrets : {
51+
config = k
52+
secret_name = secret
53+
plaintext_value = plaintext
54+
repository = v
55+
}
56+
]
57+
])
58+
59+
sa_secrets = [for k, v in local.gh_config : {
60+
config = k
61+
secret_name = "SERVICE_ACCOUNT_EMAIL"
62+
plaintext_value = google_service_account.terraform-env-sa[k].email
63+
repository = v
64+
}
65+
]
66+
67+
gh_secrets = { for v in concat(local.sa_secrets, local.secrets_list) : "${v.config}.${v.secret_name}" => v }
68+
69+
}
70+
71+
module "gh_cicd" {
72+
source = "terraform-google-modules/project-factory/google"
73+
version = "~> 12.0"
74+
75+
name = "${var.project_prefix}-b-cicd-wif-gh"
76+
random_project_id = true
77+
org_id = var.org_id
78+
folder_id = google_folder.bootstrap.id
79+
billing_account = var.billing_account
80+
activate_apis = [
81+
"compute.googleapis.com",
82+
"admin.googleapis.com",
83+
"iam.googleapis.com",
84+
"billingbudgets.googleapis.com",
85+
"cloudbilling.googleapis.com",
86+
"serviceusage.googleapis.com",
87+
"cloudresourcemanager.googleapis.com",
88+
"iamcredentials.googleapis.com",
89+
]
90+
}
91+
92+
module "gh_oidc" {
93+
source = "terraform-google-modules/github-actions-runners/google//modules/gh-oidc"
94+
version = "~> 3.1"
95+
96+
project_id = module.gh_cicd.project_id
97+
pool_id = "foundation-pool"
98+
provider_id = "foundation-gh-provider"
99+
sa_mapping = local.sa_mapping
100+
}
101+
102+
resource "github_actions_secret" "secrets" {
103+
for_each = local.gh_secrets
104+
105+
repository = each.value.repository
106+
secret_name = each.value.secret_name
107+
plaintext_value = each.value.plaintext_value
108+
}

0-bootstrap/outputs.tf

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ output "optional_groups" {
8686
/* ----------------------------------------
8787
Specific to cloudbuild_module
8888
---------------------------------------- */
89-
# Comment-out the cloudbuild_bootstrap module and its outputs if you want to use Jenkins instead of Cloud Build
89+
# Comment-out the cloudbuild_bootstrap module and its outputs if you want to use GitHub Actions or Jenkins instead of Cloud Build
9090
output "cloudbuild_project_id" {
9191
description = "Project where Cloud Build configuration and terraform container image will reside."
9292
value = module.tf_source.cloudbuild_project_id
@@ -126,7 +126,6 @@ output "csr_repos" {
126126
output "cloud_build_private_worker_pool_id" {
127127
description = "ID of the Cloud Build private worker pool."
128128
value = module.tf_private_pool.private_worker_pool_id
129-
130129
}
131130

132131
output "cloud_build_worker_range_id" {
@@ -144,6 +143,20 @@ output "cloud_build_peered_network_id" {
144143
value = module.tf_private_pool.peered_network_id
145144
}
146145

146+
/* ----------------------------------------
147+
Specific to github_bootstrap
148+
---------------------------------------- */
149+
# Un-comment github_bootstrap and its outputs if you want to use GitHub Actions instead of Cloud Build
150+
# output "cicd_project_id" {
151+
# description = "Project where the CI/CD infrastructure for GitHub Action resides."
152+
# value = module.gh_cicd.project_id
153+
# }
154+
155+
# output "projects_gcs_bucket_tfstate" {
156+
# description = "Bucket used for storing terraform state for stage 4-projects foundations pipelines in seed project."
157+
# value = module.seed_bootstrap.gcs_bucket_tfstate
158+
# }
159+
147160
/* ----------------------------------------
148161
Specific to jenkins_bootstrap module
149162
---------------------------------------- */

0-bootstrap/sa.tf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ locals {
125125
"roles/cloudscheduler.admin",
126126
"roles/resourcemanager.projectDeleter",
127127
"roles/dns.admin",
128+
"roles/iam.workloadIdentityPoolAdmin",
128129
],
129130
}
130131

0-bootstrap/terraform.example.tfvars

Lines changed: 78 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -28,67 +28,87 @@ group_billing_admins = "REPLACE_ME"
2828

2929
default_region = "us-central1"
3030

31-
// Optional - for an organization with existing projects or for development/validation.
32-
// Uncomment this variable to place all the example foundation resources under
33-
// the provided folder instead of the root organization.
34-
// The variable value is the numeric folder ID
35-
// The folder must already exist.
36-
//parent_folder = "01234567890"
31+
# Optional - for an organization with existing projects or for development/validation.
32+
# Uncomment this variable to place all the example foundation resources under
33+
# the provided folder instead of the root organization.
34+
# The variable value is the numeric folder ID
35+
# The folder must already exist.
36+
# parent_folder = "01234567890"
3737

38-
// Optional - for enabling the automatic groups creation, uncoment the groups
39-
// variable and update the values with the desired group names
40-
//groups = {
41-
// create_groups = true,
42-
// billing_project = "billing-project",
43-
// required_groups = {
44-
// group_org_admins = "[email protected]"
45-
// group_billing_admins = "[email protected]"
46-
// billing_data_users = "[email protected]"
47-
// audit_data_users = "[email protected]"
48-
// monitoring_workspace_users = "[email protected]"
49-
// },
50-
// optional_groups = {
51-
// gcp_platform_viewer = "[email protected]"
52-
// gcp_security_reviewer = "[email protected]"
53-
// gcp_network_viewer = "[email protected]"
54-
// gcp_scc_admin = "[email protected]"
55-
// gcp_global_secrets_admin = "[email protected]"
56-
// gcp_audit_viewer = "[email protected]"
57-
// }
58-
//}
59-
//
38+
# Optional - for enabling the automatic groups creation, uncoment the groups
39+
# variable and update the values with the desired group names
40+
# groups = {
41+
# create_groups = true,
42+
# billing_project = "billing-project",
43+
# required_groups = {
44+
# group_org_admins = "[email protected]"
45+
# group_billing_admins = "[email protected]"
46+
# billing_data_users = "[email protected]"
47+
# audit_data_users = "[email protected]"
48+
# monitoring_workspace_users = "[email protected]"
49+
# },
50+
# optional_groups = {
51+
# gcp_platform_viewer = "[email protected]"
52+
# gcp_security_reviewer = "[email protected]"
53+
# gcp_network_viewer = "[email protected]"
54+
# gcp_scc_admin = "[email protected]"
55+
# gcp_global_secrets_admin = "[email protected]"
56+
# gcp_audit_viewer = "[email protected]"
57+
# }
58+
# }
59+
#
60+
61+
62+
/* ----------------------------------------
63+
Specific to github_bootstrap
64+
---------------------------------------- */
65+
# Un-comment github_bootstrap and its outputs if you want to use GitHub Actions instead of Cloud Build
66+
# gh_repos = {
67+
# owner = "YOUR-GITHUB-USER-OR-ORGANIZATION",
68+
# bootstrap = "YOUR-BOOTSTRAP-REPOSITORY",
69+
# organization = "YOUR-ORGANIZATION-REPOSITORY",
70+
# environments = "YOUR-ENVIRONMENTS-REPOSITORY",
71+
# networks = "YOUR-NETWORKS-REPOSITORY",
72+
# projects = "YOUR-PROJECTS-REPOSITORY",
73+
# }
74+
#
75+
# to prevent saving the `gh_token` in plain text in this file,
76+
# export the GitHub fine grained access token in the command line
77+
# as an environment variable before running terraform.
78+
# Run the following commnad in your shell:
79+
# export TF_VAR_gh_token="YOUR-FINE-GRAINED-ACCESS-TOKEN"
6080

6181

6282
/* ----------------------------------------
6383
Specific to jenkins_bootstrap module
6484
---------------------------------------- */
65-
// Un-comment the jenkins_bootstrap module and its outputs if you want to use Jenkins instead of Cloud Build
66-
//jenkins_agent_gce_subnetwork_cidr_range = "172.16.1.0/24"
67-
//
68-
//jenkins_agent_gce_private_ip_address = "172.16.1.6"
69-
//
70-
//jenkins_agent_gce_ssh_pub_key = "ssh-rsa [KEY_VALUE] [USERNAME]"
71-
//
72-
//jenkins_agent_sa_email = "jenkins-agent-gce" # service_account_prefix will be added
73-
//
74-
//jenkins_controller_subnetwork_cidr_range = ["10.1.0.6/32"]
75-
//
76-
//nat_bgp_asn = "64514"
77-
//
78-
//vpn_shared_secret = "shared_secret"
79-
//
80-
//on_prem_vpn_public_ip_address = ""
81-
//
82-
//on_prem_vpn_public_ip_address2 = ""
83-
//
84-
//router_asn = "64515"
85-
//
86-
//bgp_peer_asn = "64513"
87-
//
88-
//tunnel0_bgp_peer_address = "169.254.1.1"
89-
//
90-
//tunnel0_bgp_session_range = "169.254.1.2/30"
91-
//
92-
//tunnel1_bgp_peer_address = "169.254.2.1"
93-
//
94-
//tunnel1_bgp_session_range = "169.254.2.2/30"
85+
# Un-comment the jenkins_bootstrap module and its outputs if you want to use Jenkins instead of Cloud Build
86+
# jenkins_agent_gce_subnetwork_cidr_range = "172.16.1.0/24"
87+
#
88+
# jenkins_agent_gce_private_ip_address = "172.16.1.6"
89+
#
90+
# jenkins_agent_gce_ssh_pub_key = "ssh-rsa [KEY_VALUE] [USERNAME]"
91+
#
92+
# jenkins_agent_sa_email = "jenkins-agent-gce" # service_account_prefix will be added
93+
#
94+
# jenkins_controller_subnetwork_cidr_range = ["10.1.0.6/32"]
95+
#
96+
# nat_bgp_asn = "64514"
97+
#
98+
# vpn_shared_secret = "shared_secret"
99+
#
100+
# on_prem_vpn_public_ip_address = ""
101+
#
102+
# on_prem_vpn_public_ip_address2 = ""
103+
#
104+
# router_asn = "64515"
105+
#
106+
# bgp_peer_asn = "64513"
107+
#
108+
# tunnel0_bgp_peer_address = "169.254.1.1"
109+
#
110+
# tunnel0_bgp_session_range = "169.254.1.2/30"
111+
#
112+
# tunnel1_bgp_peer_address = "169.254.2.1"
113+
#
114+
# tunnel1_bgp_session_range = "169.254.2.2/30"

0-bootstrap/variables.tf

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,37 @@ variable "initial_group_config" {
164164
default = "WITH_INITIAL_OWNER"
165165
}
166166

167+
/* ----------------------------------------
168+
Specific to github_bootstrap
169+
---------------------------------------- */
170+
171+
# Un-comment github_bootstrap and its outputs if you want to use GitHub Actions instead of Cloud Build
172+
# variable "gh_repos" {
173+
# description = <<EOT
174+
# Configuration for the GitHub Repositories to be used to deploy the Terraform Example Foundation stages.
175+
# owner: The owner of the repositories. An user or an organization.
176+
# bootstrap: The repository to host the code of the bootstrap stage.
177+
# organization: The repository to host the code of the organization stage.
178+
# environments: The repository to host the code of the environments stage.
179+
# networks: The repository to host the code of the networks stage.
180+
# projects: The repository to host the code of the projects stage.
181+
# EOT
182+
# type = object({
183+
# owner = string,
184+
# bootstrap = string,
185+
# organization = string,
186+
# environments = string,
187+
# networks = string,
188+
# projects = string,
189+
# })
190+
# }
191+
192+
# variable "gh_token" {
193+
# description = "A fine-grained personal access token for the user or organization. See https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token#creating-a-fine-grained-personal-access-token"
194+
# type = string
195+
# sensitive = true
196+
# }
197+
167198
/* ----------------------------------------
168199
Specific to jenkins_bootstrap module
169200
---------------------------------------- */

0-bootstrap/versions.tf

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,12 @@ terraform {
2222
source = "hashicorp/google"
2323
version = ">= 3.50, != 4.31.0"
2424
}
25+
26+
// Un-comment github required_providers when using GitHub Actions
27+
# github = {
28+
# source = "integrations/github"
29+
# version = "5.34.0"
30+
# }
2531
}
2632

2733
provider_meta "google" {

1-org/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,10 @@ If you received a `PERMISSION_DENIED` error while running the `gcloud access-con
206206

207207
See `0-bootstrap` [README-Jenkins.md](../0-bootstrap/README-Jenkins.md#deploying-step-1-org).
208208

209+
### Deploying with GitHub Actions
210+
211+
See `0-bootstrap` [README-GitHub.md](../0-bootstrap/README-GitHub.md#deploying-step-1-org).
212+
209213
### Running Terraform locally
210214

211215
1. The next instructions assume that you are at the same level of the `terraform-example-foundation` folder.

2-environments/README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,11 @@ Run `terraform output cloudbuild_project_id` in the `0-bootstrap` folder to get
174174

175175
### Deploying with Jenkins
176176

177-
See `0-bootstrap` [README-Jenkins.md](../0-bootstrap/README-Jenkins.md#deploying-step-2-environments)
177+
See `0-bootstrap` [README-Jenkins.md](../0-bootstrap/README-Jenkins.md#deploying-step-2-environments).
178+
179+
### Deploying with GitHub Actions
180+
181+
See `0-bootstrap` [README-GitHub.md](../0-bootstrap/README-GitHub.md#deploying-step-2-environments).
178182

179183
### Run Terraform locally
180184

0 commit comments

Comments
 (0)