GCP IaC Compliance Reviewer
Overview
This skill scans a Google Cloud Terraform configuration for security and
compliance violations before terraform apply runs, so a misconfigured
public bucket, an open SSH rule, or a roles/editor grant never reaches a
real project. It is not a generic Terraform linter: every rule it checks
maps to a specific CIS Google Cloud Platform Foundation Benchmark control,
a private-by-default storage/network default, or a least-privilege IAM
guideline, documented in references/ and encoded once as the canonical
rule metadata in assets/gcp_compliance_checklist.json.
Success looks like: a findings list ranked by severity, each with the exact
resource address and a concrete fix (not just "this is insecure"), plus a
set of reviewable — never auto-applied — HCL remediation snippets, and an
explicit list of controls that need human/org-level judgment this scan
cannot make on its own.
Prerequisites
The Terraform module/root directory to audit, or (preferred) a
terraform show -json plan export from it.
Python 3.9+ available to run scripts/audit_tf_gcp.py (standard library
only — no pip install required).
Bash available to run scripts/remediate_tf_compliance.sh (uses python3
for JSON parsing internally, not jq — do not assume jq is installed on
the target machine).
Data classification: Confidential. Terraform plans can contain resource
metadata and provider-supplied sensitive values; keep plan files and reports
local to the authorized repository and redact sensitive values before sharing.
Tool boundary: Use only the two bundled local scripts and read-only
Terraform commands. Never run terraform init, terraform apply,
terraform destroy, or cloud-provider CLI commands. Require a local regular
file for --plan-json and a local directory for --tf-dir; reject paths
that cannot be read rather than attempting a fallback.
Workflow
Step 1: Get the most authoritative view of the configuration you can
Ask whether the user can run Terraform against the target module. If yes,
have them generate a local plan export:
terraform init
terraform plan -out=tf.plan
terraform show -json tf.plan > plan.json
Do not run these commands yourself: terraform init may download provider
code and terraform plan may access cloud credentials. This is the
preferred path: Terraform has already resolved every
variable, local, module input, and count/for_each expansion, so the scan
in Step 2 has no blind spots from unresolved HCL expressions.
If terraform isn't available (no credentials, CI-only environment, or
the user just wants a quick look), fall back to scanning the raw .tf
directory directly in Step 2 — but see the heuristic-mode caveat below
before reporting any result as a clean pass.
Step 2: Run the audit
Preferred:
scripts/audit_tf_gcp.py --plan-json plan.json --json > findings.json
Fallback (heuristic — see the script's own docstring for exactly what it
cannot see: variables, locals, module outputs, for_each, dynamic
blocks):
scripts/audit_tf_gcp.py --tf-dir path/to/module --json > findings.json
Read the mode field in the JSON output before drawing any conclusion. If
mode is "tf-dir" and findings is empty, tell the user this is
inconclusive, not a clean bill of health — recommend generating a
--plan-json export instead of trusting the heuristic scan's silence.
- Step 3: Generate reviewable remediation snippets
For every CRITICAL/HIGH finding, run:
scripts/remediate_tf_compliance.sh findings.json ./tf_remediation_snippets
This writes one .tf.snippet file per finding — never edits the user's
actual .tf files, and never runs terraform apply. Present each snippet
next to its finding; tell the user to replace the REPLACE_ME/
REPLACE_WITH_* placeholders with their real resource names before merging
it into their configuration themselves.
Step 4: Deepen IAM-specific findings
If any finding has rule_id starting GCP-IAM-, or the user is asking
specifically about role scoping, read
references/iam_least_privilege_guidelines.md and recommend a specific
predefined role (not just "use a narrower role") based on what the flagged
principal actually needs to do — the reference file's role-mapping table
covers the common cases (bucket access, BigQuery queries, Cloud SQL
connections, CI/CD deploys).
Step 5: Compile the report
Copy assets/terraform_security_report_template.md and fill in the Summary
counts, the per-finding sections (from findings.json), and the Manual
Review Required section from the JSON output's manual_review_required
list — these are checklist controls marked automated: false because they
need organization- or folder-level context (audit log sinks, org policy
constraints) a single module's plan cannot confirm on its own. Read
references/gcp_security_benchmarks.md if you need to explain why a
control matters, beyond the one-line rationale in the JSON output.
Examples
Example 1: Plan-json audit with a blocking finding
Input: "Here's our GCP Terraform module, can you check it's safe to apply?"
Expected output / behavior: generate plan.json per Step 1, run
audit_tf_gcp.py --plan-json plan.json --json, find e.g. a
google_compute_firewall allowing 0.0.0.0/0 on port 22 (GCP-NET-001,
CRITICAL) and a roles/editor project IAM member (GCP-IAM-001,
CRITICAL). Run remediate_tf_compliance.sh to produce the two snippets,
recommend roles/storage.objectAdmin (or whatever the member's actual job
is) in place of roles/editor per references/iam_least_privilege_guidelines.md,
and state clearly: do not run terraform apply until these are
resolved.
Example 2: No Terraform binary available
Input: "I don't have terraform installed, just look at these .tf files."
Expected output / behavior: run audit_tf_gcp.py --tf-dir <path> --json,
note in the report header that this is heuristic mode, and if a for_each
or module-sourced value is visible in the raw files, explicitly flag that
those resources could not be fully evaluated rather than silently reporting
them as clean.
Error Handling
audit_tf_gcp.py exits 2: this is a parse/usage error (e.g. a plan JSON
missing planned_values.root_module, likely from a terraform show -json
run against an unsupported/very old Terraform version) — never treat exit
2 as "0 findings"; show the stderr message and ask the user to
regenerate the plan JSON.
A supplied path is unreadable, is not a regular plan file, or --tf-dir
is not a directory: stop and report the validation error. Do not broaden the
scan to a parent path or upload the input to any service.
A resource type is absent from assets/gcp_compliance_checklist.json
entirely (e.g. Cloud Run, Pub/Sub, Artifact Registry): say so explicitly —
this checklist covers the controls in
references/gcp_security_benchmarks.md's CIS sections 1–7, not every GCP
resource type. Do not imply a clean scan covers resources it never looked
at.
remediate_tf_compliance.sh finds a rule_id with no canned template: it
prints a generic fallback pointing at the checklist's remediation field
instead of silently skipping the finding — surface that fallback file to
the user rather than treating the finding as handled.
A finding looks like it might already be neutralized by an org-level
policy the scan can't see (e.g. an inherited publicAccessPrevention
constraint): report the finding anyway and note the possibility — see
"Known limitations of scanning a single Terraform plan" in
references/gcp_security_benchmarks.md. Never suppress a finding based on
an assumption you can't verify from the plan.
Do not run terraform apply yourself, and do not instruct the user to
auto-apply the generated snippets without review — Terraform changes here
(removing a firewall rule, disabling a public IP) can break a running
workload; every snippet is a starting point for manual integration, not a
patch to merge blind.
Reference Files
scripts/audit_tf_gcp.py: runs the automated checklist against a
--plan-json export (authoritative) or a --tf-dir (heuristic) and
prints/JSON-dumps ranked findings plus the manual-review list — run in
Step 2.
scripts/remediate_tf_compliance.sh: converts findings.json into
reviewable .tf.snippet files, one per CRITICAL/HIGH finding — run in
Step 3. Never modifies the user's own .tf files.
references/gcp_security_benchmarks.md: CIS GCP Foundation Benchmark
structure, the private-by-default rationale for storage/network/compute/
GKE/Cloud SQL controls, the org-policy constraints that make a fix
durable, and the limitations of scanning a single Terraform plan — read
in Step 5, or whenever "why does this matter" needs a real answer.
references/iam_least_privilege_guidelines.md: primitive vs. predefined
vs. custom role guidance, a role-mapping table for common job functions,
service account and Workload Identity best practices — read in Step 4 for
any GCP-IAM-* finding.
assets/gcp_compliance_checklist.json: the canonical rule metadata
(severity, CIS control ID, rationale, remediation text) that both the
script and this SKILL.md draw from — the single source of truth if a
rule's wording or severity ever needs updating.
assets/terraform_security_report_template.md: fill-in-the-blanks
report structure — copy it in Step 5 rather than inventing a report
format ad hoc.
If a referenced script, asset, or reference file is missing, stop and report
the skill as incomplete; do not substitute an unreviewed command or recreate
control metadata from memory.
Output Format
Return, in order: (1) the scan mode used (plan-json vs. tf-dir) and an
explicit inconclusive-vs-clean caveat if tf-dir was used, (2) the findings
ranked by severity with resource address and fix for each, (3) the path to
the generated remediation snippets, (4) the manual-review list, and (5) a
one-line go/no-go recommendation on running terraform apply given the
current CRITICAL/HIGH count. Never state or imply "compliant" based on a
tf-dir scan with zero findings.
1---2name: gcp-terraform-security-policy3description: Audits Google Cloud Terraform configuration (raw .tf files or a `terraform show -json` plan) against CIS Google Cloud Platform Foundation Benchmark controls, private-by-default storage/network defaults, and least-privilege IAM, then proposes remediation HCL before `terraform apply`. TRIGGER when the user asks to "audit Terraform for GCP security", "scan for public GCS buckets/IAM/firewall rules", "check CIS GCP benchmark compliance", "review least-privilege IAM in Terraform", or provides a `terraform plan`/`terraform show -json` output for GCP. DO NOT TRIGGER for general Terraform authoring/module design unrelated to security, AWS/Azure/other-cloud IaC scanning, or actually running `terraform apply` (this skill only audits and proposes; it never applies infrastructure changes).4license: Apache-2.05---67- GCP IaC Compliance Reviewer89- Overview10This skill scans a Google Cloud Terraform configuration for security and11compliance violations *before* `terraform apply` runs, so a misconfigured12public bucket, an open SSH rule, or a `roles/editor` grant never reaches a13real project. It is not a generic Terraform linter: every rule it checks14maps to a specific CIS Google Cloud Platform Foundation Benchmark control,15a private-by-default storage/network default, or a least-privilege IAM16guideline, documented in `references/` and encoded once as the canonical17rule metadata in `assets/gcp_compliance_checklist.json`.1819Success looks like: a findings list ranked by severity, each with the exact20resource address and a concrete fix (not just "this is insecure"), plus a21set of reviewable — never auto-applied — HCL remediation snippets, and an22explicit list of controls that need human/org-level judgment this scan23cannot make on its own.2425- Prerequisites26- The Terraform module/root directory to audit, or (preferred) a27 `terraform show -json` plan export from it.28- Python 3.9+ available to run `scripts/audit_tf_gcp.py` (standard library29 only — no pip install required).30- Bash available to run `scripts/remediate_tf_compliance.sh` (uses `python3`31 for JSON parsing internally, not `jq` — do not assume `jq` is installed on32 the target machine).33- **Data classification:** Confidential. Terraform plans can contain resource34 metadata and provider-supplied sensitive values; keep plan files and reports35 local to the authorized repository and redact sensitive values before sharing.36- **Tool boundary:** Use only the two bundled local scripts and read-only37 Terraform commands. Never run `terraform init`, `terraform apply`,38 `terraform destroy`, or cloud-provider CLI commands. Require a local regular39 file for `--plan-json` and a local directory for `--tf-dir`; reject paths40 that cannot be read rather than attempting a fallback.4142- Workflow4344- Step 1: Get the most authoritative view of the configuration you can45Ask whether the user can run Terraform against the target module. If yes,46have them generate a local plan export:47```48terraform init49terraform plan -out=tf.plan50terraform show -json tf.plan > plan.json51```52Do not run these commands yourself: `terraform init` may download provider53code and `terraform plan` may access cloud credentials. This is the54**preferred** path: Terraform has already resolved every55variable, local, module input, and `count`/`for_each` expansion, so the scan56in Step 2 has no blind spots from unresolved HCL expressions.57- If `terraform` isn't available (no credentials, CI-only environment, or58 the user just wants a quick look), fall back to scanning the raw `.tf`59 directory directly in Step 2 — but see the heuristic-mode caveat below60 before reporting any result as a clean pass.6162- Step 2: Run the audit63Preferred:64```65scripts/audit_tf_gcp.py --plan-json plan.json --json > findings.json66```67Fallback (heuristic — see the script's own docstring for exactly what it68cannot see: variables, locals, module outputs, `for_each`, `dynamic`69blocks):70```71scripts/audit_tf_gcp.py --tf-dir path/to/module --json > findings.json72```73Read the `mode` field in the JSON output before drawing any conclusion. If74`mode` is `"tf-dir"` and `findings` is empty, tell the user this is75**inconclusive, not a clean bill of health** — recommend generating a76`--plan-json` export instead of trusting the heuristic scan's silence.7778- Step 3: Generate reviewable remediation snippets79For every CRITICAL/HIGH finding, run:80```81scripts/remediate_tf_compliance.sh findings.json ./tf_remediation_snippets82```83This writes one `.tf.snippet` file per finding — never edits the user's84actual `.tf` files, and never runs `terraform apply`. Present each snippet85next to its finding; tell the user to replace the `REPLACE_ME`/86`REPLACE_WITH_*` placeholders with their real resource names before merging87it into their configuration themselves.8889- Step 4: Deepen IAM-specific findings90If any finding has `rule_id` starting `GCP-IAM-`, or the user is asking91specifically about role scoping, read92`references/iam_least_privilege_guidelines.md` and recommend a *specific*93predefined role (not just "use a narrower role") based on what the flagged94principal actually needs to do — the reference file's role-mapping table95covers the common cases (bucket access, BigQuery queries, Cloud SQL96connections, CI/CD deploys).9798- Step 5: Compile the report99Copy `assets/terraform_security_report_template.md` and fill in the Summary100counts, the per-finding sections (from `findings.json`), and the Manual101Review Required section from the JSON output's `manual_review_required`102list — these are checklist controls marked `automated: false` because they103need organization- or folder-level context (audit log sinks, org policy104constraints) a single module's plan cannot confirm on its own. Read105`references/gcp_security_benchmarks.md` if you need to explain *why* a106control matters, beyond the one-line rationale in the JSON output.107108- Examples109110- Example 1: Plan-json audit with a blocking finding111Input: "Here's our GCP Terraform module, can you check it's safe to apply?"112Expected output / behavior: generate `plan.json` per Step 1, run113`audit_tf_gcp.py --plan-json plan.json --json`, find e.g. a114`google_compute_firewall` allowing `0.0.0.0/0` on port 22 (`GCP-NET-001`,115CRITICAL) and a `roles/editor` project IAM member (`GCP-IAM-001`,116CRITICAL). Run `remediate_tf_compliance.sh` to produce the two snippets,117recommend `roles/storage.objectAdmin` (or whatever the member's actual job118is) in place of `roles/editor` per `references/iam_least_privilege_guidelines.md`,119and state clearly: **do not run `terraform apply` until these are120resolved.**121122- Example 2: No Terraform binary available123Input: "I don't have terraform installed, just look at these .tf files."124Expected output / behavior: run `audit_tf_gcp.py --tf-dir <path> --json`,125note in the report header that this is heuristic mode, and if a `for_each`126or module-sourced value is visible in the raw files, explicitly flag that127those resources could not be fully evaluated rather than silently reporting128them as clean.129130- Error Handling131- `audit_tf_gcp.py` exits 2: this is a parse/usage error (e.g. a plan JSON132 missing `planned_values.root_module`, likely from a `terraform show -json`133 run against an unsupported/very old Terraform version) — never treat exit134 2 as "0 findings"; show the stderr message and ask the user to135 regenerate the plan JSON.136- A supplied path is unreadable, is not a regular plan file, or `--tf-dir`137 is not a directory: stop and report the validation error. Do not broaden the138 scan to a parent path or upload the input to any service.139- A resource type is absent from `assets/gcp_compliance_checklist.json`140 entirely (e.g. Cloud Run, Pub/Sub, Artifact Registry): say so explicitly —141 this checklist covers the controls in142 `references/gcp_security_benchmarks.md`'s CIS sections 1–7, not every GCP143 resource type. Do not imply a clean scan covers resources it never looked144 at.145- `remediate_tf_compliance.sh` finds a `rule_id` with no canned template: it146 prints a generic fallback pointing at the checklist's `remediation` field147 instead of silently skipping the finding — surface that fallback file to148 the user rather than treating the finding as handled.149- A finding looks like it might already be neutralized by an org-level150 policy the scan can't see (e.g. an inherited `publicAccessPrevention`151 constraint): report the finding anyway and note the possibility — see152 "Known limitations of scanning a single Terraform plan" in153 `references/gcp_security_benchmarks.md`. Never suppress a finding based on154 an assumption you can't verify from the plan.155- Do not run `terraform apply` yourself, and do not instruct the user to156 auto-apply the generated snippets without review — Terraform changes here157 (removing a firewall rule, disabling a public IP) can break a running158 workload; every snippet is a starting point for manual integration, not a159 patch to merge blind.160161- Reference Files162- **scripts/audit_tf_gcp.py**: runs the automated checklist against a163 `--plan-json` export (authoritative) or a `--tf-dir` (heuristic) and164 prints/JSON-dumps ranked findings plus the manual-review list — run in165 Step 2.166- **scripts/remediate_tf_compliance.sh**: converts `findings.json` into167 reviewable `.tf.snippet` files, one per CRITICAL/HIGH finding — run in168 Step 3. Never modifies the user's own `.tf` files.169- **references/gcp_security_benchmarks.md**: CIS GCP Foundation Benchmark170 structure, the private-by-default rationale for storage/network/compute/171 GKE/Cloud SQL controls, the org-policy constraints that make a fix172 durable, and the limitations of scanning a single Terraform plan — read173 in Step 5, or whenever "why does this matter" needs a real answer.174- **references/iam_least_privilege_guidelines.md**: primitive vs. predefined175 vs. custom role guidance, a role-mapping table for common job functions,176 service account and Workload Identity best practices — read in Step 4 for177 any `GCP-IAM-*` finding.178- **assets/gcp_compliance_checklist.json**: the canonical rule metadata179 (severity, CIS control ID, rationale, remediation text) that both the180 script and this SKILL.md draw from — the single source of truth if a181 rule's wording or severity ever needs updating.182- **assets/terraform_security_report_template.md**: fill-in-the-blanks183 report structure — copy it in Step 5 rather than inventing a report184 format ad hoc.185- If a referenced script, asset, or reference file is missing, stop and report186 the skill as incomplete; do not substitute an unreviewed command or recreate187 control metadata from memory.188189- Output Format190Return, in order: (1) the scan mode used (plan-json vs. tf-dir) and an191explicit inconclusive-vs-clean caveat if tf-dir was used, (2) the findings192ranked by severity with resource address and fix for each, (3) the path to193the generated remediation snippets, (4) the manual-review list, and (5) a194one-line go/no-go recommendation on running `terraform apply` given the195current CRITICAL/HIGH count. Never state or imply "compliant" based on a196tf-dir scan with zero findings.