Skip to main content

Bootstrap (Stage 0)

Repository: gcp-foundations-bootstrap

Purpose

The bootstrap stage is a one-time manual setup that creates the foundational infrastructure required by all subsequent pipeline stages. It establishes the seed project, CI/CD project, granular Terraform service accounts, the shared GCS state bucket, and GitHub OIDC configuration for keyless CI/CD authentication.

This stage uses the terraform-google-modules/bootstrap/google module (version ~> 11.0).

Prerequisites

Before running the bootstrap stage, you must have:

  • GCP Organization with Organization Admin access
  • Billing Account with Billing Admin access
  • Google Groups for org admins and billing admins (pre-created or created by this stage)
  • GitHub App configured with appropriate permissions for the badal-io organization
  • Terraform Cloud token and GitHub App OAuth ID
  • Default labels for cost-center, owner-name, and owner-email

Resources Created

Projects

ProjectPurpose
prj-b-seedHosts Terraform state bucket, service accounts, KMS keys
prj-b-cicd-wif-ghHosts GitHub Actions Workload Identity Federation (OIDC)

Folder

FolderPurpose
fldr-bootstrapContains both bootstrap projects

Service Accounts

Five granular Terraform service accounts are created in the seed project, each with least-privilege roles scoped to their pipeline stage:

Service AccountPipeline StageKey Org-Level Roles
sa-terraform-bootstrap0-bootstrapresourcemanager.organizationAdmin, accesscontextmanager.policyAdmin, serviceusage.serviceUsageConsumer
sa-terraform-org1-orgorgpolicy.policyAdmin, logging.configWriter, resourcemanager.organizationAdmin, securitycenter.notificationConfigEditor, accesscontextmanager.policyAdmin, resourcemanager.tagAdmin, cloudasset.owner
sa-terraform-env2-environmentsresourcemanager.tagUser, assuredworkloads.admin
sa-terraform-net3-networksaccesscontextmanager.policyAdmin, compute.xpnAdmin, resourcemanager.tagAdmin, resourcemanager.tagUser
sa-terraform-proj4-projectsaccesscontextmanager.policyAdmin, resourcemanager.organizationAdmin, orgpolicy.policyAdmin, iam.workloadIdentityPoolAdmin, iam.serviceAccountAdmin, iam.organizationRoleAdmin

All service accounts additionally receive:

  • roles/browser at the org level (for ancestry reads)
  • roles/billing.user and roles/billing.admin on the billing account
  • roles/storage.objectAdmin on the seed project (for state read/write)
  • Stage-specific folder-level roles (e.g., roles/resourcemanager.folderAdmin)

GCS State Bucket

  • Name: bkt-prj-b-seed-tfstate-*
  • Encryption: KMS-encrypted with auto-rotating keys (90-day rotation)
  • Location: Default region (northamerica-northeast1)
  • Purpose: Shared Terraform state for all 5 pipeline stages

GitHub OIDC / Workload Identity Federation

  • OIDC Pool: foundation-pool
  • OIDC Provider: foundation-gh-provider
  • SA Mapping: Each pipeline SA is mapped to its corresponding GitHub repository via attribute.repository/{owner}/{repo}
  • GitHub Secrets: Automatically provisioned to each foundation repo (PROJECT_ID, WIF_PROVIDER_NAME, TF_BACKEND, SERVICE_ACCOUNT_EMAIL, etc.)

Google Groups

The bootstrap stage can optionally create Google Groups:

Required Groups:

  • group_org_admins -- GCP Organization Administrators
  • group_billing_admins -- GCP Billing Administrators
  • billing_data_users -- Billing data viewers
  • audit_data_users -- Audit log viewers
  • monitoring_workspace_users -- Monitoring workspace users

Optional Groups:

  • gcp_platform_viewer, gcp_security_reviewer, gcp_network_viewer
  • gcp_scc_admin, gcp_global_secrets_admin, gcp_audit_viewer

Key Variables

VariableDescriptionDefault
org_idGCP Organization ID--
billing_accountBilling account ID--
default_regionPrimary regionus-central1
default_region_2Secondary regionus-west1
project_prefixProject name prefix (max 3 chars)prj
folder_prefixFolder name prefixfldr
bucket_prefixState bucket name prefixbkt
gh_reposGitHub repo names for each stage--
gh_app_idGitHub App ID (sensitive)--
gh_app_installation_idGitHub App installation ID (sensitive)--
default_labelsRequired labels: cost-center, owner-name, owner-email--

Key Outputs

These outputs are consumed by all subsequent stages via terraform_remote_state:

OutputDescriptionConsumed By
common_configorg_id, billing_account, regions, prefixes, parent_idAll stages
seed_project_idSeed project IDAll stages
gcs_bucket_tfstateState bucket nameAll stages
cicd_project_idCI/CD project IDBootstrap
*_step_terraform_service_account_emailSA email per stageEach respective stage
group_org_adminsOrg admins group1-org
group_billing_adminsBilling admins group1-org

Running Bootstrap

The bootstrap stage is run manually by an operator with Organization Admin privileges. It cannot be run via CI/CD because the CI/CD infrastructure does not yet exist.

Preparation Checklist

  1. Ensure you have roles/resourcemanager.organizationAdmin and roles/billing.admin on the GCP organization
  2. Create or identify Google Groups for org admins and billing admins
  3. Register a GitHub App in the badal-io organization with repository permissions
  4. Configure a terraform.tfvars file with all required variables
  5. Run terraform init and terraform apply from the envs/shared directory
cd envs/shared
terraform init
terraform plan
terraform apply

After bootstrap completes, all subsequent stages can be deployed via GitHub Actions CI/CD using the service accounts and OIDC configuration created by this stage.

Directory Structure

gcp-foundations-bootstrap/
+-- envs/
+-- shared/
+-- main.tf # Seed bootstrap module, folder
+-- sa.tf # 5 granular service accounts + IAM
+-- github.tf # GitHub OIDC, CI/CD project, secrets
+-- groups.tf # Google Groups creation
+-- backstage.tf # Backstage-specific config
+-- outputs.tf # Outputs consumed by later stages
+-- variables.tf # Input variables
+-- versions.tf # Provider versions
+-- backend.tf # GCS backend config
+-- provider.tf # Provider configuration
+-- modules/
+-- cb-private-pool/ # Cloud Build private worker pool
+-- gitlab-oidc/ # GitLab OIDC (alternative)
+-- parent-iam-member/
+-- parent-iam-remove-role/
+-- tfc-agent-gke/ # TFC agent on GKE (alternative)