Last reviewed: May 2026
Build the AWS services on the CDL exam with plain Terraform — one block at a time, each tied back to an exam domain. The same code works on OpenTofu.
By the end of this lab you'll have provisioned, with plain Terraform, the smallest realistic GCP footprint — two project services enabled, a Cloud Storage bucket with uniform bucket-level access + lifecycle, and a Cloud Billing budget that emails when spend crosses a threshold. Four blocks, the GCP equivalent of creating an AWS account and dropping a single S3 bucket in it.
Drop the snippets into a single main.tf, run terraform init, then terraform apply step-by-step.
>= 1.5 or OpenTofu >= 1.6.provider block.gcloud auth application-default login.gcloud beta billing accounts list.your-project-id and your-billing-account-id in the snippets below before running terraform apply.All free at this scope:
us-* regions; lab bucket holds nothing.The lab idles at ~$0/month. The point is to prove the billing tripwire works — the entire CDL exam orbits around the operate-GCP-safely skillset, of which "know what you're spending" is rule #1.
GCP requires explicit project services (APIs) to be enabled before resources can be provisioned. We enable storage.googleapis.com (for Step 2) and billingbudgets.googleapis.com (for Step 4). Compare to AWS where API surfaces are always on — GCP makes you opt in per project.
Replace your-project-id with your actual project ID.
terraform {
required_version = ">= 1.5"
required_providers {
google = { source = "hashicorp/google", version = "~> 6.0" }
}
}
provider "google" {
project = "your-project-id" # REPLACE with your GCP project ID
region = "us-central1"
}
locals {
labels = {
project = "certlabpro-cdl"
managed_by = "terraform"
}
}
resource "google_project_service" "storage" {
service = "storage.googleapis.com"
disable_on_destroy = false
}
resource "google_project_service" "budgets" {
service = "billingbudgets.googleapis.com"
disable_on_destroy = false
}Cloud Storage is GCP's S3 equivalent — object store with regional, multi-regional, and dual-region replication options. The CDL exam tests the which-storage-class question repeatedly: Standard (hot), Nearline (>30 day), Coldline (>90 day), Archive (>365 day).
We enable uniform bucket-level access (the CDL-recommended security default — disables fine-grained per-object ACLs in favor of IAM-only) and a 30-day → Nearline lifecycle transition. Names must be globally unique across all GCP — we suffix with a random hex.
resource "random_id" "suffix" {
byte_length = 4
}
resource "google_storage_bucket" "main" {
name = "certlabpro-cdl-${random_id.suffix.hex}"
location = "US"
uniform_bucket_level_access = true
force_destroy = true # lab-only — never in production
lifecycle_rule {
condition {
age = 30
}
action {
type = "SetStorageClass"
storage_class = "NEARLINE"
}
}
labels = local.labels
depends_on = [google_project_service.storage]
}GCP's Cloud Logging is on by default for most services — but the CDL exam tests the Required vs Default vs Data Access audit-log distinction. Required audit logs (admin activity) are always on, free, can't be disabled. Default logs (data writes for some services) are on but can be disabled. Data Access logs (data reads) are off by default — must be explicitly enabled and bill normally.
We enable Data Access logging for Cloud Storage so every read of every object in the bucket from Step 2 lands in Cloud Logging. The lab is a demonstration of the iam-audit-config primitive; production deployments use this pattern at org level via [[gcp-pcse]] patterns.
resource "google_project_iam_audit_config" "storage_data_access" {
service = "storage.googleapis.com"
audit_log_config {
log_type = "DATA_READ"
}
audit_log_config {
log_type = "DATA_WRITE"
}
}The CDL exam loves this pattern — Cloud Billing budgets + alerts is the recurring CDL exam-question shape for cost control. We set a $10/month budget and configure alerts at 50% / 90% / 100% of forecasted spend. The alert lands via email to billing-account admins (no extra config needed for email; for Slack / PagerDuty you'd add a Pub/Sub topic + Cloud Function fanout).
Replace your-billing-account-id with your actual ID. The budget is scoped to the current project only via projects filter — the CDL exam tests this per-project-budget vs org-wide-budget distinction.
data "google_project" "current" {}
resource "google_billing_budget" "monthly_10" {
billing_account = "your-billing-account-id" # REPLACE — find via `gcloud beta billing accounts list`
display_name = "certlabpro-cdl-$10-monthly"
budget_filter {
projects = ["projects/${data.google_project.current.number}"]
}
amount {
specified_amount {
currency_code = "USD"
units = "10"
}
}
threshold_rules {
threshold_percent = 0.5
spend_basis = "FORECASTED_SPEND"
}
threshold_rules {
threshold_percent = 0.9
spend_basis = "FORECASTED_SPEND"
}
threshold_rules {
threshold_percent = 1.0
spend_basis = "CURRENT_SPEND"
}
depends_on = [google_project_service.budgets]
}terraform destroy tears down everything cleanly. The bucket destroys (lab-only force_destroy = true lets Terraform delete it even when non-empty — never use this in production). The budget detaches; emails stop. The IAM audit config reverts to default. The project services stay enabled (we set disable_on_destroy = false — they're free to leave on, and disabling them can break unrelated workloads on the same project).
CDL covers many GCP surfaces this lab can't fit — Compute Engine VMs, GKE clusters, Cloud Run, Cloud Functions, App Engine, BigQuery, Cloud SQL, Spanner, Bigtable, Firestore, Cloud Pub/Sub, Dataflow, Dataproc, Vertex AI, Cloud Build, Cloud Deploy, Anthos / Multi-Cloud, Cloud CDN / Cloud Armor, VPC + Cloud NAT, Cloud Interconnect, Cloud IAM / Identity, Cloud KMS, Security Command Center, the full GCP marketplace.
We stick to the Storage + Logging + Billing primitives because they're the lowest-common-denominator footprint every CDL exam scenario assumes is in place. Every other GCP service writes to Cloud Storage / reads from Cloud Storage / lands logs in Cloud Logging / shows up on a Cloud Billing dashboard. Master the foundation; layer specialty services later.
For the service-by-service conceptual coverage, see the Browse, Playbook, and Editorial sections of this cert page.