The deployment of enterprise-grade cloud infrastructure requires more than just writing code; it demands a rigorous, multi-layered orchestration of identity, state management, and continuous integration. When utilizing the Terraform Example Foundation, the integration with GitLab CI/CD represents the nexus where Infrastructure as Code (IaC) meets automated delivery pipelines. This process is designed to move through a specific hierarchy of stages—ranging from the initial 0-bootstrap phase through 1-org, 2-environments, 3-networks, and finally 4-projects—ensuring that each layer of the Google Cloud Platform (GCP) hierarchy is established with granular control and strict separation of concerns.
Achieving this level of automation requires a sophisticated environment where the runner's identity is decoupled from the resources it manages. By leveraging Workload Identity Federation (WIF), organizations can move away from long-lived, high-risk service account keys, instead using short-lived tokens that establish trust between GitLab and Google Cloud. This article serves as a technical blueprint for establishing this automated foundation, ensuring that every engineer, from the novice to the seasoned DevOps architect, understands the deep mechanics of the bootstrap and subsequent deployment stages.
Infrastructure Separation and Project Topology
A fundamental principle in this deployment model is the strict separation of concerns through the use of distinct Google Cloud Platform projects. Attempting to collapse these roles into a single project creates a "blast radius" that is unacceptable in production environments.
The architecture mandates the use of two specific initial projects:
- prj-b-seed
- prj-b-cicd-wif-gl
The prj-b-seed project acts as the bedrock of the entire infrastructure. Its primary responsibility is the storage of the Terraform state files, which are the source of truth for the current state of the deployed cloud resources. Furthermore, this project houses the highly privileged Service Accounts capable of creating, modifying, and deleting the core infrastructure components. The security implication here is profound: by isolating the state and the most powerful identities in a single, highly guarded project, the risk of accidental or malicious infrastructure destruction is significantly mitigated.
The prj-b-cicd-wif-gl project serves a different, critical purpose. It hosts the authentication infrastructure required for Workload Identity Federation. This project is where the trust relationship between the GitLab CI/CD runners and GCP is established. By separating the authentication mechanism (WIF) from the resource-management identities (Seed), the organization ensures that an identity compromise in the CI/CD pipeline does not automatically grant full administrative access to the core state and seed resources without passing through the federated trust layer.
Prerequisites and Toolchain Requirements
Before initiating the bootstrap process, the local workstation or the deployment environment must meet exact version requirements. Discrepancies in versions—particularly regarding Terraform—can lead to catastrophic failures, such as state snapshot lock errors, which prevent any further modifications to the infrastructure until manual intervention occurs.
The following toolchain is mandatory:
- Google Cloud SDK: version 393.0.0 or later
- terraform-tools: required component for specific GCP operations
- Git: version 2.28.0 or later
- Terraform: version 1.5.7 or later
- jq: version 1.6 or later
The recommendation for Terraform version 1.5.7 is not arbitrary; this specific version represents the final release before the significant changes to the Terraform license model. Using this version ensures compatibility with the specific logic used in the Terraform Example Foundation and provides a stable, predictable environment for the build pipelines.
Repository Structure and Branching Strategy
The deployment follows a modular repository pattern. Each stage of the foundation is housed in its own Git repository to allow for independent lifecycles, permissions, and deployment cadences. The initial layout of the required repositories should be organized as follows:
- gcp-bootstrap/
- gcp-cicd-runner/
- gcp-environments/
- gcp-networks/
- gcp-org/
- gcp-projects/
- terraform-example-foundation/
To facilitate a healthy CI/CD workflow, a rigorous branching strategy must be implemented. Branches must exist to act as the targets for Merge Requests (MRs), and these branches should not be empty to ensure the CI/CD engine has a valid target to track.
Required branches by repository:
- CI/CD Runner: image
- Bootstrap: plan, production
- Organization: plan, production
- Environments: plan, development, nonproduction, production
- Networks: plan, development, nonproduction, production
- Projects: plan, development, nonproduction, production
The "plan" branch serves as the staging ground where changes are proposed, while the "production" or "development" branches serve as the stable, long-lived branches representing the current state of the live environment.
The Bootstrap Phase: Step-by-Step Execution
The 0-bootstrap stage is the most critical. It prepares the environment to handle all subsequent stages. This process involves cloning the necessary repositories and populating the bootstrap repository with the foundation's core logic.
Initial Repository Setup
First, the repositories must be cloned from the GitLab host. This establishes the local working directory for the automation.
bash
git clone [email protected]:<GITLAB-OWNER>/<GITLAB-BOOTSTRAP-REPO>.git gcp-bootstrap
git clone [email protected]:<GITLAB-OWNER>/<GITLAB-ORGANIZATION-REPO>.git gcp-org
git clone [email protected]:<GITLAB-OWNER>/<GITLAB-ENVIRONMENTS-REPO>.git gcp-environments
git clone [email protected]:<GITLAB-OWNER>/<GITLAB-NETWORKS-REPO>.git gcp-networks
git clone [email protected]:<GITLAB-OWNER>/<GITLAB-PROJECTS-REPO>.git gcp-projects
git clone [email protected]:<GITLAB-OWNER>/<GITLAB-RUNNER-REPO>.git gcp-cicd-runner
Once cloned, the runner repository must be initialized. This involves committing the initial state and pushing it to GitLab to trigger the build process.
bash
git commit -m 'Initialize CI/CD runner project'
git push
After the build-image job succeeds in GitLab, security settings must be adjusted to allow cross-repository access. Navigate to the CI/CD runner settings in GitLab and add the Bootstrap, Organization, Environments, Networks, and Projects repositories to the allow list. Furthermore, use the "Allow CI job tokens from the following projects to access this project" setting to permit access using the <GITLAB-OWNER>/<GITLAB-REPO> format.
Configuring the Bootstrap Directory
The actual configuration begins within the gcp-bootstrap directory. All operations hereafter assume the user has navigated into this directory.
bash
cd gcp-bootstrap
git checkout plan
The contents of the foundation must be manually migrated into the bootstrap environment. This is done using the cp -RT command to ensure the directory structure is preserved exactly.
bash
mkdir -p envs/shared
cp -RT ../terraform-example-foundation/0-bootstrap/ ./envs/shared
cp -RT ../terraform-example-foundation/policy-library/ ./policy-library
cp ../terraform-example-foundation/build/gitlab-ci.yml ./.gitlab-ci.yml
cp ../terraform-example-foundation/build/run_gcp_auth.sh .
cp ../terraform-example-foundation/build/tf-wrapper.sh .
chmod 755 ./*.sh
To enable the specific GitLab-compatible build type, the helper script must be executed:
bash
./scripts/choose_build_type.sh gitlab
Variable Management and Security
Terraform requires specific variables to interact with the GCP environment. Renaming the example files to the standard .tfvars naming convention is a prerequisite.
bash
mv ./terraform.example.tfvars ./terraform.tfvars
mv ./common.auto.example.tfvars common.auto.tfvars
mv ./production.auto.example.tfvars production.auto.tfvars
mv ./access_context.auto.example.tfvars access_context.auto.tfvars
A critical security step is the handling of the gitlab_token. To avoid the catastrophic risk of committing plain-text credentials to a Git repository, the token must be injected via an environment variable.
bash
export TF_VAR_gitlab_token="YOUR-PERSONAL-OR-GROUP-ACCESS-TOKEN"
The terraform.tfvars file must be updated with environment-specific values, and production.auto.tfvars must be updated with target_name_server_addresses. Additionally, the Access Context Manager policy ID must be dynamically retrieved and injected into the configuration.
bash
export ORGANIZATION_ID=$(terraform -chdir="../gcp-bootstrap/envs/shared/" output -json common_config | jq '.org_id' --raw-output)
export ACCESS_CONTEXT_MANAGER_ID=$(gcloud access-context-manager policies list --organization ${ORGANIZATION_ID} --format="value(name)")
sed -i'' -e "s/ACCESS_CONTEXT_MANAGER_ID/${ACCESS_CONTEXT_MANAGER_ID}/" ./access_context.auto.tfvars
Validation and Execution
Before applying any changes, the environment must be validated using the built-in helper script. This script checks for necessary components but does not validate IAM roles within Cloud Identity or Google Workspace.
bash
../../../terraform-example-foundation/scripts/validate-requirements.sh -o <ORGANIZATION_ID> -b <BILLING_ACCOUNT_ID> -u <END_USER_EMAIL> -e
The final steps involve initializing the Terraform working directory and generating a plan file for review.
bash
terraform init
terraform plan -input=false -out bootstrap.tfplan
To ensure the security posture of the infrastructure, the gcloud beta terraform vet command should be used to validate policies against the proposed changes.
Expanding to the Environments Layer
Once the bootstrap is complete, the process is replicated for the gcp-environments repository. This stage depends heavily on the state produced during the bootstrap phase.
- Navigate to the environments directory and switch to the
planbranch. - Copy the foundation components, including the policy library and build scripts.
- Rename the example variables:
mv terraform.example.tfvars terraform.tfvars. - Link the environment to the bootstrap state by injecting the
remote_state_bucketvalue.
bash
export backend_bucket=$(terraform -chdir="../gcp-bootstrap/envs/shared" output -raw gcs_bucket_tfstate)
sed -i'' -e "s/REMOTE_STATE_BUCKET/${backend_bucket}/" terraform.tfvars
After these modifications, the changes are committed and pushed, and a Merge Request is opened from the plan branch to the development branch in GitLab.
OpenTofu Integration and Modern Alternatives
As the IaC landscape evolves, GitLab has provided pathways for users to integrate OpenTofu, the open-source fork of Terraform. This is particularly relevant for users seeking to avoid the licensing complexities of HashiCorp's proprietary versions.
GitLab provides a dedicated OpenTofu CI/CD component that simplifies the integration. An engineer can add a complete validate, plan, and apply workflow by including the following block in their .gitlab-ci.yml:
yaml
include:
- component: gitlab.com/components/opentofu/validate-plan-apply@<VERSION>
inputs:
version: <VERSION>
opentofu_version: <OPENTOFU_VERSION>
root_dir: terraform/
state_name: production
stages: [validate, build, deploy]
While GitLab no longer distributes the original terraform-images, the community and the "Terraform Images" project allow users to build and host their own custom job images, ensuring that the CI/CD pipeline remains functional and tailored to specific version requirements.
Comparative Analysis of Implementation Strategies
The following table compares the two primary paths for running IaC within GitLab:
| Feature | Traditional Terraform Integration | OpenTofu CI/CD Component |
|---|---|---|
| Distribution | User-hosted/Custom images | GitLab-managed component |
| License Model | HashiCorp BSL | Open Source (Mozilla Public License) |
| Workflow Control | Manual pipeline definition | Highly abstracted via component |
| State Management | GitLab-managed or Remote | GitLab-managed or Remote |
| Configuration Complexity | High (requires custom image builds) | Low (uses predefined inputs) |
The choice between these two paths depends heavily on the organization's legal requirements regarding the Terraform license and the desired level of abstraction in the CI/CD pipeline.
Analytical Conclusion
Implementing the Terraform Example Foundation within a GitLab CI/CD ecosystem is a sophisticated undertaking that transforms manual infrastructure provisioning into a robust, repeatable, and secure software engineering discipline. The architectural decision to separate the prj-b-seed and prj-b-cicd-wif-gl projects is not merely a preference but a fundamental security requirement to isolate state management from authentication mechanisms.
The successful execution of this deployment depends on three critical pillars: strict version parity to prevent state locks, rigorous branch management to facilitate controlled merges, and the secure handling of sensitive tokens through environment variables rather than plain-text files. As organizations move toward more open-source-centric models, the transition to OpenTofu components offers a streamlined alternative that maintains the same level of rigor while providing easier integration through GitLab's modern component architecture. Ultimately, this framework provides the structural integrity required to manage complex, multi-project Google Cloud environments at scale.