AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Terraform Gcp

skill-way-platform-skills-terraform-gcp · by way-platform

Write, review, and refactor Terraform HCL for GCP. Use when editing .tf files, managing IAM, writing terraform tests, or organizing GCP Terraform modules.

— No reviews yet
0 installs
33 views
0.0% view→install

Install

$ agentstack add skill-way-platform-skills-terraform-gcp

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • ✓ Prompt-injection patterns
  • ✓ Secret / credential exfiltration
  • ✓ Dangerous shell & filesystem operations
  • ✓ Untrusted network calls
  • ✓ Known-malicious package signatures

What it can access

  • ✓ Network access No
  • ✓ Filesystem access No
  • ✓ Shell / process execution No
  • ✓ Environment & secrets No
  • ✓ Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-way-platform-skills-terraform-gcp)

Reliability & compatibility

✓ Security review passed
0 installs to date
— no reviews yet
● 3mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Terraform Gcp? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Terraform + GCP

File Organization

Per references/terraform-style-guide.md (HashiCorp):

| File | Purpose | | -------------- | ------------------------------------------- | | terraform.tf | Terraform and provider version requirements | | providers.tf | Provider configurations | | main.tf | Primary resources and data sources | | variables.tf | Input variable declarations (alphabetical) | | outputs.tf | Output value declarations (alphabetical) | | locals.tf | Local value declarations |

For larger modules, split main.tf into purpose-grouped files (references/general-style-and-structure.md, Google):

# dns.tf — google_dns_managed_zone + google_dns_record_set together
# network.tf — VPC, subnets, firewall rules together

Formatting

  • 2 spaces per nesting level, no tabs — always run terraform fmt -recursive
  • Align = for consecutive arguments in the same block
  • Block order within a resource:
  1. Meta-arguments (count, for_each, provider, depends_on)
  2. Arguments
  3. Nested blocks
  4. lifecycle last

Naming Conventions

  • lowercase_underscores for all resource/variable/output names
  • Descriptive nouns — no resource type in the name
  • Singular, not plural
  • Use main when there is only one of a type
# Bad
resource "google_compute_global_address" "main_global_address" {}
resource "google_storage_bucket" "buckets" {}

# Good
resource "google_compute_global_address" "main" {}
resource "google_storage_bucket" "artifacts" {}

Variables

Every variable needs type + description. Add validation for constrained inputs. Mark sensitive = true for secrets. Don't provide defaults for environment-specific values like project_id — force the caller to provide them.

GCP-specific naming:

  • Numeric values: include units — ram_size_gb, disk_size_gib
  • Storage: binary prefixes (kibi, mebi, gibi); all other measurements: decimal
  • Booleans: positive names — enable_external_access, not disable_internal
variable "ram_size_gb" {
  description = "RAM per instance in gibibytes"
  type        = number
}

variable "environment" {
  description = "Deployment environment"
  type        = string

  validation {
    condition     = contains(["dev", "qa", "prod"], var.environment)
    error_message = "Must be dev, qa, or prod."
  }
}

Outputs

Every output needs description. Mark sensitive = true where appropriate.

Never pass an input variable directly as an output — always reference a resource attribute to preserve the dependency graph:

# Bad — breaks implicit dependencies
output "bucket_name" {
  value = var.bucket_name
}

# Good — reference the resource attribute
output "bucket_name" {
  description = "Name of the storage bucket"
  value       = google_storage_bucket.main.name
}

for_each vs count

  • for_each — multiple named resources (stable identity, survives reordering)
  • count — conditional creation only
  • Use a separate enable_x boolean for conditional logic; don't drive count

directly from resource attributes that may be unknown at plan time

# Multiple resources — use for_each
resource "google_storage_bucket" "regional" {
  for_each = toset(var.regions)
  name     = "data-${each.key}"
  location = each.key
}

# Conditional — use count
resource "google_monitoring_alert_policy" "latency" {
  count        = var.enable_alerts ? 1 : 0
  display_name = "High Latency Alert"
}

Dependency Management (CRITICAL)

Prefer implicit over explicit. Reference output attributes — not input args — to create real ordering. Input args are known at plan time and create no dependency; output attrs are only known after creation.

# Bad — .name is an input arg, Terraform sees no dependency
bucket = google_storage_bucket.main.name

# Good — .id is an output attr, creates real implicit dependency
bucket = google_storage_bucket.main.id

Module dependency — implicit via output reference:

# Bad — depends_on is a blunt instrument, slows planning
module "bigquery" {
  project_id = var.project_id
  depends_on = [module.project_services]
}

# Good — implicit dependency, Terraform tracks exactly what changed
module "bigquery" {
  project_id = module.project_services.project_id
}

Use depends_on only as a last resort. Always add a comment explaining why.

Cross-config dependencies: use terraform_remote_state (GCS backend). Don't use data sources to reference resources managed by another Terraform config.


IAM — Authoritative vs Additive (CRITICAL)

| Resource pattern | Behavior | Use? | | ---------------------- | ------------------------------------------------------------------------- | ----------------------------------- | | google_*_iam_policy | Authoritative — overwrites ALL roles, removes Google-managed accounts | AVOID | | google_*_iam_binding | Authoritative — overwrites that specific role's bindings | Avoid unless owning the entire role | | google_*_iam_member | Additive — adds one member, leaves all others untouched | PREFERRED |

Authoritative resources silently remove Google's auto-managed service account roles, breaking Cloud services. Default to google_*_iam_member.

# Bad — removes all other IAM, including Google-managed bindings
resource "google_project_iam_policy" "main" {
  project     = var.project_id
  policy_data = data.google_iam_policy.admin.policy_data
}

# Good — additive, safe
resource "google_project_iam_member" "invoker" {
  project = var.project_id
  role    = "roles/run.invoker"
  member  = "serviceAccount:${google_service_account.worker.email}"
}

Stateful Resource Protection

Add lifecycle { prevent_destroy = true } to databases, buckets, and other stateful resources:

resource "google_sql_database_instance" "main" {
  name             = "primary"
  database_version = "POSTGRES_15"

  lifecycle {
    prevent_destroy = true
  }
}

Compute / VM

  • Bake images with Packer — do NOT use provisioners for configuration
  • Pass runtime config via instance metadata, not provisioner scripts

Version Pinning

Root modules — pin to minor, allow patch updates:

terraform {
  required_version = ">= 1.7"

  required_providers {
    google = {
      source  = "hashicorp/google"
      version = "~> 6.0.0"
    }
  }
}

Reusable modules — permissive >=, let callers decide:

terraform {
  required_providers {
    google = {
      source  = "hashicorp/google"
      version = ">= 4.0.0"
    }
  }
}

Root Module Structure

service/
├── OWNERS
├── modules/
│   └── /
│       ├── main.tf
│       ├── variables.tf
│       ├── outputs.tf
│       └── README.md
└── environments/
    ├── dev/
    │   ├── backend.tf        # GCS backend
    │   ├── main.tf           # Instantiates service module
    │   └── terraform.tfvars
    ├── qa/
    └── prod/
  • Max ~100 resources per state (ideally a few dozen) — per references/root-modules.md (Google)
  • One directory per application/service; nest all code under it
  • Default workspace only — no multiple CLI workspaces
  • Variables in terraform.tfvars; check in .terraform.lock.hcl
  • Never commit: .terraform/, *.tfstate, *.tfstate.backup, *.tfplan

Reusable Module Rules

  • No provider or backend config — root modules own these
  • Expose labels = {} variable for every module
  • Every resource defined in the module must have at least one output
  • Enable APIs via google_project_service; expose enable_apis = true

variable; always set disable_services_on_destroy = false

  • Inline submodules in modules//
  • Use moved blocks when refactoring to prevent destroy/recreate
  • Release with SemVer; callers reference with ~> major.0

Testing

Two categories of .tftest.hcl tests:

| Type | Naming | Mode | Creates resources? | | ----------- | ------------------------------- | ------- | ------------------ | | Unit | *_unit_test.tftest.hcl | plan | No — fast, safe | | Integration | *_integration_test.tftest.hcl | apply | Yes — real infra |

run "bucket_name_follows_convention" {
  command = plan

  assert {
    condition     = google_storage_bucket.main.name == "myproject-artifacts"
    error_message = "Bucket name does not match expected pattern."
  }
}

Key practices:

  • Randomize resource names/project IDs to avoid collisions
  • Use a dedicated test project isolated from dev/prod
  • Always destroy after tests: terraform destroy or project_cleanup module
  • Run independent tests in parallel: test { parallel = true }
  • Order: terraform validate → unit tests → integration tests → e2e

See references/terraform-test.md for full .tftest.hcl syntax, mock providers, expect_failures, and parallel execution rules.


Import / Export

Export existing GCP resources:

gcloud beta resource-config bulk-export \
  --project=MY_PROJECT \
  --resource-format=terraform \
  --path=./exported/

Import one resource:

terraform import google_storage_bucket.main my-project/my-bucket

Bulk import with generated config (Terraform 1.5+):

import {
  id = "projects/MY_PROJECT/global/networks/my-network"
  to = google_compute_network.main
}
terraform plan -generate-config-out=generated.tf

See references/import-google-cloud-resources.md and references/export-google-cloud-resources.md for full workflows.


Reference Files

| File | Read when | | --------------------------------------------------- | -------------------------------------------------------------------------------------------- | | references/terraform-style-guide.md | Full HashiCorp style guide: formatting, block order, naming, security patterns | | references/terraform-test.md | Complete .tftest.hcl syntax: run/assert/mock blocks, parallel execution, expect_failures | | references/general-style-and-structure.md | Module structure, data source placement, static files, helper scripts, expression complexity | | references/root-modules.md | Root module patterns, remote state, environment dirs, workspace rules | | references/reusable-modules.md | API activation, OWNERS file, SemVer releases, submodule patterns, moved blocks | | references/dependency-management.md | Implicit vs explicit deps with full examples, cross-config remote state | | references/working-with-google-cloud-resources.md | IAM authoritative vs additive detail, VM baking | | references/testing.md | GCP testing strategies, parallel execution, test environment isolation, cleanup | | references/import-google-cloud-resources.md | Step-by-step import workflows, import block + generate-config-out | | references/export-google-cloud-resources.md | Bulk export with gcloud beta resource-config, supported resource types | | references/blueprints.md | Cloud Foundation Toolkit blueprint patterns |

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.