L’interface est localisée ; les présentations et documents des Skills sont traduits automatiquement par IA dans votre langue. Le code, les commandes, chemins et termes techniques restent en version originale, et le document de l’auteur fait foi.
Explorer les Skills
Déploiement et opérations · SKILL.md

terraform-skill

terraform-skill

Terraform/OpenTofu best practices, testing strategy, naming conventions, and CI/CD integration. Load BEFORE writing any Terraform module or environment config. Triggers: terraform test, terraform module, terraform naming, IaC best practices, terratest, terraform ci/cd, terraform version, for_each vs count, terraform structure, terraform conventions.

Independent GitHub snapshot · Automated classification · Original documentation governs

Documentation de la Skill

GitHub

name: terraform-skill description: "Terraform/OpenTofu best practices, testing strategy, naming conventions, and CI/CD integration. Load BEFORE writing any Terraform module or environment config. Triggers: terraform test, terraform module, terraform naming, IaC best practices, terratest, terraform ci/cd, terraform version, for_each vs count, terraform structure, terraform conventions." allowed-tools: Bash, Read, Write, Edit, Glob, Grep metadata: triggers: ["terraform test", "terraform module", "terraform naming", "IaC best practices", "terratest", "terraform ci/cd", "terraform version", "for_each vs count", "terraform structure", "terraform conventions"] related-skills: [gcp-cloud-run, gcp-finops, docker, architecture-design, terraform-module-library] domain: backend role: specialist scope: infrastructure output-format: code last-reviewed: "2026-03-15"

Terraform Skill

Source: terraform-best-practices.com + enterprise Terraform/OpenTofu experience. GCP-primary for this workspace.

Iron Law

BEFORE writing any Terraform:
1. Load this skill for naming, testing, and code structure conventions
2. Dispatch terraform-specialist agent to provision GCP resources
3. Run tfsec/Checkov BEFORE terraform apply — no exceptions
4. State files NEVER go in git — GCS remote state always
5. GitHub Actions only — never generate cloudbuild.yaml

This Skill vs terraform-specialist Agent

TaskUse This SkillUse terraform-specialist Agent
Naming conventions (resources, variables, files)YESNo
Testing strategy (native test vs Terratest)YESNo
count vs for_each decisionYESNo
Resource block ordering standardsYESNo
Version constraint strategyYESNo
CI/CD pipeline for Terraform (GitHub Actions)YESNo
Provision Cloud Run, Cloud SQL, Artifact RegistryNoYES
Multi-environment (staging/prod) setupNoYES
GCS remote state configurationNoYES
Workload Identity FederationNoYES
tfsec/Checkov security scanningNoYES

Load this skill for how to write Terraform. Dispatch terraform-specialist for what to provision.


Pattern Selector

What do you need?
    |
    +-- Writing or reviewing a Terraform module?
    |   -> Apply § Naming Conventions
    |   -> Apply § Code Structure Standards (resource block ordering)
    |   -> Apply § Count vs For_Each decision
    |
    +-- Adding tests to a Terraform module?
    |   -> Use § Testing Strategy decision tree
    |   -> Terraform 1.6+: native test (preferred for this workspace)
    |   -> Terraform 1.0–1.5: Terratest (Go)
    |
    +-- Setting up CI/CD for Terraform?
    |   -> See § CI/CD Integration
    |   -> GitHub Actions ONLY (workspace rule — never cloudbuild.yaml)
    |
    +-- Choosing module or environment structure?
        -> See § Code Structure Philosophy
        -> See docs/workflows/cloud-run-terraform.md for GCP-specific layout
        -> See terraform-module-library skill for GCP module patterns

Code Structure Philosophy

terraform/
├── modules/          # Reusable modules — NO provider {}, NO backend {}
│   ├── cloud-run/    # One resource group per module
│   ├── cloud-sql/
│   ├── artifact-registry/
│   ├── secret-manager/
│   └── wif/
├── environments/     # Environment roots — call modules, configure backends
│   ├── staging/
│   │   ├── main.tf         # Module calls only — no raw resource definitions
│   │   ├── variables.tf
│   │   ├── terraform.tfvars
│   │   └── backend.tf      # GCS remote state
│   └── production/
│       └── ...
└── examples/         # Usage examples — also serve as integration test fixtures
    └── complete/

Rules:

  • Modules do NOT contain provider {} blocks or backend {} — only environment roots do
  • Environment roots contain module calls only, never raw resource definitions
  • examples/ doubles as documentation AND integration test fixture

Naming Conventions

Resource Names

# Use descriptive names for resources used multiple times in a module
resource "google_cloud_run_v2_service" "api" { }
resource "google_cloud_run_v2_service" "worker" { }

# Use "this" ONLY for singleton resources (exactly one per module)
resource "google_artifact_registry_repository" "this" { }
resource "google_sql_database_instance" "this" { }

Variable Names — Context-Prefixed

# Avoid — ambiguous
variable "name" { }
variable "region" { }

# Prefer — context-prefixed
variable "service_name" { }
variable "cloud_run_region" { }
variable "sql_instance_name" { }

File Names

FilePurpose
main.tfPrimary resource definitions
variables.tfAll input variable declarations
outputs.tfAll output declarations
versions.tfterraform {} block + required_providers
data.tfData source lookups only
locals.tfLocal value computations (extract from main.tf when > 5 locals)

Testing Strategy

Decision Tree

What Terraform version?
    |
    +-- 1.7+ → Use native test WITH mock providers (fastest, no real GCP calls)
    |
    +-- 1.6 → Use native test (terraform test command)
    |          Test files: tests/*.tftest.hcl
    |
    +-- 1.0–1.5 → Use Terratest (Go)
                   Test files: tests/*_test.go

Testing Pyramid

LayerToolRuns OnCost
Static analysistflint, terraform validate, tfsecEvery commitFree
Unit (plan)Native test (command = plan)PR open/updateFree
IntegrationNative test (command = apply, mock provider)PR merge to developFree
E2ENative test (command = apply, real provider)Release branch only~$0.01–$1/run

Rule: Run layers 1–2 on every PR. Layer 3 on merge to develop. Layer 4 on release branches only.

Native Test — Preferred (Terraform 1.6+)

# tests/cloud_run_module.tftest.hcl
mock_provider "google" {
  mock_resource "google_cloud_run_v2_service" {
    defaults = {
      uri = "https://test-api-abc123-uc.a.run.app"
    }
  }
  mock_resource "google_cloud_run_v2_service_iam_member" {}
}

variables {
  service_name          = "test-api"
  project_id            = "test-project"
  region                = "us-central1"
  image_url             = "us-central1-docker.pkg.dev/test-project/registry/api:latest"
  service_account_email = "sa@test-project.iam.gserviceaccount.com"
}

run "verify_service_name" {
  command = apply   # Safe — mock provider, no real GCP calls

  assert {
    condition     = google_cloud_run_v2_service.this.name == "test-api"
    error_message = "Service name should match input variable"
  }

  assert {
    condition     = startswith(output.service_url, "https://")
    error_message = "Service URL must be HTTPS"
  }
}

run "verify_name_validation" {
  command = plan

  variables {
    service_name = "this-name-is-way-too-long-for-cloud-run-service-names-xxxx"
  }

  expect_failures = [var.service_name]
}

Code Structure Standards

Resource Block Ordering

resource "google_cloud_run_v2_service" "api" {
  # 1. count / for_each first
  for_each = toset(var.regions)

  # 2. Required arguments (alphabetical within group)
  location = each.key
  name     = "${var.service_name}-${each.key}"
  project  = var.project_id

  # 3. Optional arguments
  template { ... }

  # 4. Labels
  labels = var.labels

  # 5. depends_on (before lifecycle)
  depends_on = [google_project_service.run]

  # 6. lifecycle (last)
  lifecycle {
    ignore_changes = [template[0].containers[0].image]
  }
}

Variable Block Ordering

variable "service_name" {
  description = "Name of the Cloud Run service"   # 1. description (always required)
  type        = string                             # 2. type
  default     = null                              # 3. default (if any)
  validation {                                    # 4. validation (if any)
    condition     = length(var.service_name) <= 49
    error_message = "Cloud Run service names must be <= 49 chars."
  }
  nullable = false                                # 5. nullable
}

Count vs For_Each

Decision Guide

Is the resource conditional (enabled/disabled flag)?
    YES -> count = var.enable_feature ? 1 : 0

Is the set driven by a list that could change order?
    YES -> for_each (stable addressing — prevents destroy/recreate cascade)
    NO (truly static, never reordered) -> count is acceptable

Do items have meaningful identity beyond index?
    YES -> for_each = tomap(...) or toset(...)
    NO  -> count

Example trap: multiple Cloud Run regions
    WRONG: count = 2  (count[0] -> count[1] on reorder = destroy us-central1!)
    RIGHT: for_each = toset(["us-central1", "us-east1"])
# Conditional resource — count
resource "google_monitoring_alert_policy" "latency" {
  count = var.enable_monitoring ? 1 : 0
  ...
}

# Multi-region stable addressing — for_each
resource "google_cloud_run_v2_service" "regional" {
  for_each = toset(var.regions)
  name     = "${var.service_name}-${each.key}"
  location = each.key
}

# IAM members — for_each (never count — order instability)
resource "google_artifact_registry_repository_iam_member" "readers" {
  for_each   = toset(var.reader_service_accounts)
  role       = "roles/artifactregistry.reader"
  member     = "serviceAccount:${each.key}"
  ...
}

Version Management

Constraint Strategy

ComponentConstraintExample
Terraform binaryPin minor~> 1.9.0
google providerPin minor~> 6.0
google-beta providerPin minor~> 6.0
Internal modulesPin exact= 1.2.3
Registry modulesPin minor~> 2.1
# versions.tf
terraform {
  required_version = "~> 1.9.0"

  required_providers {
    google = {
      source  = "hashicorp/google"
      version = "~> 6.0"
    }
    google-beta = {
      source  = "hashicorp/google-beta"
      version = "~> 6.0"
    }
  }
}

Feature Availability by Version

FeatureMin VersionUse For
try() function0.13Safely access nested optional attributes
optional() in object types1.3Optional object keys with defaults
moved {} block1.1Rename resources without destroy
import {} block1.5Declarative resource import
Native terraform test1.6Module unit testing
Mock providers in tests1.7Offline module testing (no real GCP calls)
Cross-variable validation1.9Validate interdependent variable combinations

CI/CD Integration (GitHub Actions Only)

Full workflow: load reference/cicd-github-actions.md

Stage order: validate → test → plan → apply — never skip test stage.

Key jobs: validate (fmt + tflint + tfsec), test (native terraform test with mock providers), plan (PR only, requires WIF auth), apply (main branch only, environment gate).


Reference Files

ReferenceLoad When
reference/index.mdNavigation
reference/cicd-github-actions.mdSetting up GitHub Actions CI/CD for Terraform

Cross-References

  • GCP Infrastructure provisioning: Dispatch terraform-specialist agent
  • GCP module patterns (Cloud Run, Cloud SQL, VPC, WIF): Load terraform-module-library skill
  • Provisioning workflow: docs/workflows/cloud-run-terraform.md
  • Module development workflow: docs/workflows/terraform-module-development.md
  • Security scanning post-apply: Dispatch security-reviewer agent
  • CI/CD application pipeline: docs/workflows/deployment-ci-cd.md
Skills enregistrées