Introduction to Deployment Manager and Terraform
Infrastructure as Code (IaC) on Google Cloud is dominated by Terraform in 2024-2026, while Deployment Manager (DM) is on Google's deprecation track for new project creation. The PCD exam expects you to recognise that net-new architectures must default to Terraform with the hashicorp/google provider, and that Deployment Manager appears mainly in legacy migration questions. Both tools speak to Google Cloud Resource Manager APIs underneath, but Terraform exposes a richer, multi-cloud, community-driven module ecosystem.
A Professional Cloud Developer must be able to: choose between google and google-beta providers, configure a GCS remote state backend with locking, run terraform plan inside Cloud Build, secure HCP Terraform with Workload Identity Federation (WIF) instead of long-lived service account keys, and recognise alternative tools such as Pulumi or Config Connector. This note builds a deep mental model for each of these capabilities.
Infrastructure as Code (IaC) is the practice of declaring cloud resources in version-controlled text files and reconciling actual cloud state with that declaration via an automated engine such as Terraform, Pulumi, or Config Connector — replacing imperative Console clicks with reproducible, peer-reviewable, rollback-able Git commits.
Deployment Manager: Legacy and Deprecation Status
Architecture and configuration files
Deployment Manager (DM) is Google's first-party IaC service launched in 2015. It accepts a top-level YAML config that references types (e.g. compute.v1.instance, storage.v1.bucket) and supports templates written in Jinja2 or Python. A typical workflow is gcloud deployment-manager deployments create my-dep --config config.yaml, which submits the manifest to the Deployment Manager API and returns a deployment resource whose state Google itself stores — there is no local state file to manage.
2024 deprecation announcement
In April 2024 Google announced that Deployment Manager will not be available for new Google Cloud projects created after a cutoff date, although existing deployments continue to function for managed lifecycle reasons. Customers were directed to migrate to Terraform (the strategic IaC tool) or Config Connector (the Kubernetes-native equivalent). New PCD questions phrased as "your team starts a greenfield workload in 2025 — which IaC tool should they pick?" expect Terraform, not DM.
Migration paths
Existing DM users can run terraformer or gcloud beta terraform vet style tooling to extract resource configurations and convert YAML manifests to HCL. Practically, teams freeze DM, write Terraform that imports the same resources via terraform import, then delete the DM deployment with --delete-policy=ABANDON so resources are preserved during cutover. The PCD exam may show a scenario where ABANDON-vs-DELETE is the trap distractor.
A common wrong answer on the PCD exam is "use Deployment Manager for a new multi-region landing zone." Deployment Manager is GCP-only, is in deprecation status for new projects, and lacks the module ecosystem of Terraform. Pick terraform with the google and google-beta providers plus Cloud Foundation Toolkit modules instead.
Terraform google and google-beta Providers
Why two providers exist
HashiCorp ships two complementary Terraform providers for Google Cloud:
hashicorp/google— the stable provider exposing resources in General Availability (GA) on Google Cloud.hashicorp/google-beta— the beta provider exposing preview / beta features such as new Workload Identity Pool fields, freshly released Cloud Run flags, or experimental Cloud SQL options.
You can use both in the same root module by declaring two required_providers blocks and aliasing them, e.g. provider "google-beta" { alias = "beta" }, then choosing on a per-resource basis with provider = google-beta.beta.
Pinning versions
Terraform best practice is to pin both core CLI and providers using required_version = "~> 1.6" and required_providers { google = { version = "~> 5.10.0" } }. Without pinning, a terraform init six months later can pull a major-version bump that breaks your plan. The PCD exam likes to test whether you understand that the provider version is part of the IaC contract, not just the HCL itself.
Authenticating the provider
The provider supports four credential sources, evaluated in order: GOOGLE_CREDENTIALS env var, gcloud Application Default Credentials, attached compute identity (e.g. running on GCE / Cloud Build), and Workload Identity Federation for external CI such as GitHub Actions. Hardcoded service account JSON keys are the worst option and should be avoided in any production answer choice.
The google-beta provider is not automatically swapped for google once a feature graduates to GA. Teams must explicitly migrate resource blocks from provider = google-beta to the default google provider — leaving them on the beta provider risks silent behavioural change when HashiCorp evolves preview semantics.
HCP Terraform (Terraform Cloud) with Workload Identity Federation
What HCP Terraform provides
HashiCorp rebranded Terraform Cloud to HCP Terraform in 2024. It is a managed control plane that stores state remotely, runs plans/applies in isolated workers, enforces policy via Sentinel or OPA, and exposes a CI/CD-friendly web UI. For PCD scenarios, HCP Terraform is the answer when a multi-team org needs governed runs without operating its own runner fleet.
Workload Identity Federation removes JSON keys
The strategic security pattern is Workload Identity Federation: HCP Terraform mints short-lived OIDC tokens, Google's Security Token Service (STS) exchanges them for federated Google Cloud credentials, and the provider authenticates without any long-lived service account JSON ever leaving Google. The flow uses a Workload Identity Pool (iam.googleapis.com/projects/.../locations/global/workloadIdentityPools/<pool>) plus a provider that trusts the HCP Terraform OIDC issuer https://app.terraform.io.
Configuration sketch
provider "google" {
project = "my-prod-host"
region = "asia-east1"
# No credentials = ADC + WIF token exchange resolves automatically
}
HCP Terraform exposes TFC_GCP_WORKLOAD_PROVIDER_NAME and TFC_GCP_SERVICE_ACCOUNT_EMAIL workspace variables; the runner injects them and the provider performs the STS exchange. PCD candidates should be able to recite this chain end to end.
For any exam question phrased "minimise key-management toil for Terraform runs", the answer is Workload Identity Federation with short-lived STS tokens, never "rotate service account JSON keys every 90 days". Long-lived keys are the wrong answer in 2026-era PCD content.
GCS Backend with State Locking
Why remote state is mandatory for teams
Terraform stores the mapping between HCL resources and Cloud Resource IDs in a terraform.tfstate JSON file. Storing this file locally is fatal for any team larger than one: two developers running apply concurrently can corrupt state and orphan resources. The Google-blessed answer is the GCS backend.
Backend configuration
terraform {
backend "gcs" {
bucket = "acme-tfstate-prod"
prefix = "platform/landing-zone"
}
}
The bucket should be regional or dual-region, have uniform bucket-level access enabled, Object Versioning turned on (so an accidental terraform destroy is recoverable), and Customer-Managed Encryption Keys (CMEK) if regulatory requirements demand it.
Native object-based locking
Since 2024 the GCS backend supports native state locking via GCS object generations and If-Match preconditions — no separate Cloud Spanner or Cloud SQL lock table is needed. Terraform acquires a lock by writing a default.tflock object; concurrent runs see a 409 Conflict and refuse to proceed until the lock object is released. This replaces the older "use Cloud Storage + Cloud Spanner" pattern from pre-1.4 days.
Access control on the bucket
The bucket should grant roles/storage.objectAdmin only to the Terraform runner identity. Developers should NOT have direct write access to the state bucket — that is the whole point of routing changes through CI. A typical IAM Condition restricts access to the GCS state bucket to requests originating from the runner's Workload Identity Pool.
Cloud Foundation Toolkit (CFT) Modules
What CFT provides
The Cloud Foundation Toolkit is Google's open-source library of opinionated Terraform and Deployment Manager modules that codify GCP best practices. The Terraform side lives under the terraform-google-modules GitHub org and contains 150+ modules: networking (terraform-google-network), KMS (terraform-google-kms), Cloud SQL (terraform-google-sql-db), Kubernetes Engine (terraform-google-kubernetes-engine), and the marquee Project Factory.
Consuming a CFT module
module "vpc" {
source = "terraform-google-modules/network/google"
version = "~> 9.1"
project_id = "acme-prod-host"
network_name = "shared-prod-vpc"
subnets = [{
subnet_name = "ae1-app"
subnet_ip = "10.20.0.0/20"
subnet_region = "asia-east1"
}]
}
Pinning version is critical — without it, an upstream major release may introduce breaking changes to your network on the next terraform apply.
Versioning and validation
CFT modules ship with their own integration tests (kitchen-terraform, blueprint test framework), CHANGELOGs, and SemVer guarantees. The PCD exam may distinguish CFT modules from random community modules — CFT modules are Google-maintained, signed, and tested against Forseti / Policy Library; random Registry modules are not.
Project Factory and Resource Manager Tags
Project Factory pattern
The terraform-google-project-factory module standardises project creation with billing, APIs, default service accounts, networking attachment, and labels enforced in one place. A typical landing zone uses it inside a for_each loop over a map of business units, producing tens or hundreds of projects from a few hundred lines of HCL.
module "project" {
source = "terraform-google-modules/project-factory/google"
version = "~> 16.0"
name = "acme-payments-prod"
org_id = "111122223333"
billing_account = "0123AB-456789-CDEF01"
folder_id = "folders/4444555566"
activate_apis = ["run.googleapis.com", "pubsub.googleapis.com"]
}
Resource Manager Tags + IAM Conditions
Resource Manager Tags are key-value pairs (e.g. env=prod, dataclass=pii) that bind to projects/folders/orgs and feed IAM Conditions to scope permissions. A Terraform pattern is to define the tag key/value via google_tags_tag_key and google_tags_tag_value, attach with google_tags_tag_binding, then write an IAM policy where role only applies if resource.matchTag('111122223333/env', 'prod') — granting prod-only access without project-by-project bindings.
Resource Manager Tags are different from labels. Tags participate in IAM Conditions and propagate up the resource hierarchy; labels are purely metadata and cannot gate access. PCD scenarios about conditional access (e.g. "developers see dev projects, only SREs see prod") expect a tag-plus-IAM-Condition answer.
Config Connector: Kubernetes-Style Declarative IaC
What Config Connector is
Config Connector (KCC) is a Google-built Kubernetes operator that exposes Google Cloud resources as Custom Resource Definitions (CRDs). Once installed in a GKE cluster (typically via the Config Controller managed offering), you can kubectl apply -f bucket.yaml and KCC reconciles a StorageBucket resource by calling the Cloud Storage API.
When to choose KCC over Terraform
KCC shines when your platform team already operates GKE with GitOps tooling like Config Sync or Argo CD, and wants to manage GCP infra using the same Kubernetes reconcile loop. Drift detection is continuous (the controller keeps re-reconciling), whereas Terraform only runs on explicit apply. The trade-off: KCC has a smaller resource catalogue than Terraform's google provider and lacks plan-style diff preview.
Example CRD
apiVersion: storage.cnrm.cloud.google.com/v1beta1
kind: StorageBucket
metadata:
name: acme-logs-bucket
namespace: acme-prod
spec:
location: ASIA-EAST1
uniformBucketLevelAccess: true
versioning:
enabled: true
Authentication
KCC authenticates via Workload Identity on GKE: the controller's KSA is annotated with iam.gke.io/gcp-service-account, mapping to a GSA that holds the GCP roles required for the resources it manages. Same WIF mental model as HCP Terraform, just sourced from a Kubernetes Pod identity instead of an OIDC token.
Terraform Plan inside Cloud Build Triggers
CI/CD pipeline shape
The reference architecture from Google's docs ("Managing IaC with Terraform and Cloud Build") splits the pipeline into two triggers:
- PR trigger — on pull request to
main, runterraform fmt -check,terraform validate, thenterraform planand post the plan output as a PR comment. - Merge trigger — on push to
main, runterraform apply -auto-approveagainst the production state.
Sample cloudbuild.yaml
steps:
- name: 'hashicorp/terraform:1.7'
entrypoint: sh
args: ['-c', 'terraform init && terraform plan -no-color -out=tfplan']
- name: 'hashicorp/terraform:1.7'
entrypoint: sh
args: ['-c', 'terraform show -json tfplan > plan.json']
artifacts:
objects:
location: 'gs://acme-tfplans/$BUILD_ID'
paths: ['tfplan', 'plan.json']
options:
logging: CLOUD_LOGGING_ONLY
serviceAccount: 'projects/acme-cicd/serviceAccounts/[email protected]'
The Cloud Build service account is granted only the minimum project-level roles needed (typically roles/editor on a sandbox, more restricted in prod), and uses Workload Identity Federation when triggered from GitHub Actions or GitLab instead of Cloud Build's native trigger.
Storing plan artefacts
Plan artefacts go into a dedicated GCS bucket with object lifecycle deleting after 30 days, so any auditor can answer "what did Terraform actually change on 2026-03-04?" by replaying the JSON plan.
Cloud Build IaC pipeline memorisation card: PR trigger runs fmt + validate + plan (no apply); merge-to-main trigger runs apply; Cloud Build service account uses WIF not JSON keys; state lives in GCS bucket with versioning + object-generation locking; plan output is archived to GCS for 30-day audit trail.
Pulumi: The Alternative IaC Engine
Why Pulumi exists
Pulumi is an open-source IaC tool that lets you write infrastructure in real programming languages — TypeScript, Python, Go, C#, Java — instead of HCL. It uses the same Google Cloud APIs under the hood (via the @pulumi/gcp package), supports remote state (Pulumi Cloud, S3, GCS), and offers preview/apply semantics analogous to terraform plan / apply.
Pulumi vs Terraform trade-offs
- Pro Pulumi: full language power (loops, conditionals, classes, unit tests with Jest/pytest), strong typing in TS/Go, easier to share helpers as npm/pip packages.
- Pro Terraform: larger ecosystem, Google-maintained CFT modules, HCP Terraform's enterprise governance, more community examples, the de facto industry standard.
Example
import * as gcp from "@pulumi/gcp";
const bucket = new gcp.storage.Bucket("acme-logs", {
location: "ASIA-EAST1",
uniformBucketLevelAccess: true,
versioning: { enabled: true },
});
Exam relevance
On the PCD, Pulumi is the answer only when the scenario explicitly says "the team wants to write infrastructure in TypeScript and unit-test it with Jest". For generic GCP IaC questions, Terraform remains the default.
白話文解釋(Plain English Explanation)
Analogy 1: The Building Blueprint
IaC is a digital blueprint for a building. Clicking buttons in the Console is hiring day-labourers to stack bricks by memory. Feeding a Terraform plan into Google Cloud's STS-backed runner is feeding the blueprint into a 3D printer: the same input always yields the same building, and any deviation is reported as drift. Deployment Manager was Google's in-house printer; Terraform is the printer the whole industry adopted, so Google is sunsetting its own model and shipping Cloud Foundation Toolkit as add-on cartridges for the new printer.
Analogy 2: The Undo Button
Without IaC, an accidental delete is a panicked Slack thread and a recovery ticket. With Terraform plus a GCS backend with Object Versioning and state locking, the undo button is git revert plus terraform apply — the printer reads yesterday's blueprint and rebuilds yesterday's building. HCP Terraform adds a second safety net: every apply is logged with the user identity from the OIDC token, so the audit answers "who pressed undo?" with a name.
Analogy 3: The Universal Adapter
The google and google-beta providers are like Type-C and Thunderbolt cables: same shape, different capability level. You can plug either into your Terraform CLI, but Thunderbolt (google-beta) carries preview features that may break without notice. Workload Identity Federation is the chip in the cable that proves it's genuine — no fake JSON keys allowed, only short-lived STS tokens cryptographically tied to your CI runner's identity.
Exam Tips & Traps
Common traps
- Trap: Choosing Deployment Manager for any greenfield 2025+ workload. Tip: It is deprecated for new projects; pick Terraform.
- Trap: Selecting "rotate service account JSON keys every 90 days" for HCP Terraform auth. Tip: Use Workload Identity Federation; no long-lived keys.
- Trap: Storing
terraform.tfstatein a Git repo. Tip: Use GCS backend with versioning + state locking; never commit state to Git, it contains secrets. - Trap: Conflating labels with Resource Manager Tags. Tip: Only tags drive IAM Conditions.
- Trap: Picking Pulumi for a generic IaC question. Tip: Default to Terraform unless TypeScript/Python is explicitly required.
High-value memorisation
Remember the four IaC engines in priority order: Terraform (default), Config Connector (GKE/GitOps shops), Pulumi (TS/Python language preference), Deployment Manager (legacy migrations only). Remember the three security defaults: WIF over JSON keys, GCS backend with locking, Cloud Build with least-privilege runner identity.
Frequently Asked Questions (FAQs)
Q1: Is Deployment Manager being deprecated?
A1: Yes — in 2024 Google announced that Deployment Manager is unavailable for new Google Cloud projects created after the cutoff date. Existing deployments keep working, but all new architectures should default to Terraform with the hashicorp/google provider. The PCD exam expects you to pick Terraform for any greenfield question.
Q2: How do I handle secrets in IaC?
A2: Never hardcode secrets in .tf or .yaml files. Store them in Secret Manager, then reference at apply time using the google_secret_manager_secret_version data source, and surface them to runtime workloads via Cloud Run / GKE secret mounts. For CI runner auth, use Workload Identity Federation so no JSON service-account key ever exists.
Q3: Should I use google or google-beta?
A3: Default to google for stable GA resources. Use google-beta per-resource (with a provider = google-beta.beta alias) only when you need a preview feature, and plan a migration back to google once the feature reaches GA — preview semantics can change without a major-version bump.
Q4: How does state locking actually work on GCS?
A4: Since Terraform 1.4 the GCS backend uses GCS object generations and If-Match preconditions for native locking. Terraform writes a default.tflock object; concurrent runs receive HTTP 409 and back off. No Cloud Spanner or external DB is required — just enable Object Versioning on the bucket for safety.
Q5: When should I pick Config Connector over Terraform?
A5: Choose Config Connector when your platform already runs on GKE with GitOps (Config Sync, Argo CD) and wants continuous drift reconciliation via Kubernetes controllers. Choose Terraform when you need plan-style preview, the broadest resource catalogue, HCP Terraform governance, or multi-cloud portability.
Q6: How does HCP Terraform authenticate to GCP without keys?
A6: HCP Terraform mints an OIDC token scoped to your workspace. Google's Security Token Service (STS) exchanges that token, via a Workload Identity Pool + Provider that trusts the app.terraform.io issuer, for short-lived federated credentials impersonating a Google service account. The Terraform provider then calls GCP APIs with those credentials — no JSON keys, full audit trail, automatic rotation.
Q7: Is Pulumi a serious option on the PCD exam?
A7: Pulumi is mentioned only when the scenario explicitly calls for general-purpose-language IaC (TypeScript, Python, Go) with unit tests. For every other IaC question on the PCD, the expected answer is Terraform with the google provider and a GCS backend, optionally accelerated with Cloud Foundation Toolkit modules and Project Factory.