Infrastructure-as-code review
When it applies
Reviewing the code that provisions cloud/infra. IaC misconfigurations become real, exploitable
exposure the moment they apply — a single line can make a bucket public or an SG world-open — so
this pairs directly with the offensive cloud-* skills.
Why it works
IaC is declarative and repeatable: the same insecure default gets deployed everywhere it's
referenced. Scanning the definitions catches the exposure before it exists, and the patterns
(public access, 0.0.0.0/0, plaintext secrets, missing encryption/logging) are consistent across
providers.
Sinks & patterns (scan, then reason about blast radius)
- Public exposure: S3/GCS/Blob
acl = "public-read" / public access blocks disabled; security
groups / firewall rules 0.0.0.0/0 on 22/3389/DB ports; public RDS/ELB; publiclyAccessible=true.
- Over-broad IAM:
Action:"*"/Resource:"*", iam:PassRole wildcards, AssumeRole trust to
"*", admin-equivalent managed policies attached broadly.
- Secrets in code: hardcoded keys/passwords/tokens in
.tf/vars/playbooks; secrets committed in
state or plan output; sensitive = false on secret outputs.
- Missing protections: encryption at rest/in transit off (EBS/S3/RDS/SNS), logging/audit disabled
(CloudTrail, flow logs, GCP audit), no MFA-delete/versioning, public snapshots/AMIs.
- Kubernetes/Helm:
privileged: true, hostNetwork/hostPID, no securityContext/runAsNonRoot,
wide RBAC (cluster-admin), secrets as env/plaintext, latest images, no network policies.
- Ansible:
shell/command with unquoted vars, no_log missing on secret tasks, world-readable
file modes, validate_certs: no.
Method
- Run
checkov/tfsec/kics for a broad first pass; they cover hundreds of provider rules.
rg '0.0.0.0/0|public|Action.*\*|password|secret|privileged: true' and review each hit's context.
- Trace module inputs/variables — an insecure default in a reused module multiplies everywhere.
- Check state handling (remote, encrypted, access-controlled) and CI that applies it (
code-review-cicd).
Gotchas
- A finding's severity depends on blast radius — a public dev sandbox ≠ a public prod data store.
- Scanners miss cross-resource logic (an SG that's fine until paired with a public subnet) — reason about the whole graph.
- Secrets belong in a manager (Vault/SSM/KMS), never in variables or state — flag any inline secret.
References
CIS Benchmarks (AWS/Azure/GCP/Kubernetes); Checkov/tfsec/KICS rule sets; provider well-architected security pillars.
1---2name: code-review-iac3description: Security review of infrastructure-as-code — Terraform, CloudFormation, Ansible, Kubernetes/Helm manifests. Load when reviewing IaC in a repo/PR, on .tf/.yaml/.yml infra files, or "review our Terraform". Signals: *.tf, cloudformation/*.yaml, playbooks, k8s manifests, Helm charts, module registries.4---56# Infrastructure-as-code review78## When it applies9Reviewing the code that provisions cloud/infra. IaC misconfigurations become real, exploitable10exposure the moment they apply — a single line can make a bucket public or an SG world-open — so11this pairs directly with the offensive `cloud-*` skills.1213## Why it works14IaC is declarative and repeatable: the same insecure default gets deployed everywhere it's15referenced. Scanning the definitions catches the exposure before it exists, and the patterns16(public access, `0.0.0.0/0`, plaintext secrets, missing encryption/logging) are consistent across17providers.1819## Sinks & patterns (scan, then reason about blast radius)20- **Public exposure**: S3/GCS/Blob `acl = "public-read"` / public access blocks disabled; security21 groups / firewall rules `0.0.0.0/0` on 22/3389/DB ports; public RDS/ELB; `publiclyAccessible=true`.22- **Over-broad IAM**: `Action:"*"`/`Resource:"*"`, `iam:PassRole` wildcards, `AssumeRole` trust to23 `"*"`, admin-equivalent managed policies attached broadly.24- **Secrets in code**: hardcoded keys/passwords/tokens in `.tf`/vars/playbooks; secrets committed in25 state or plan output; `sensitive = false` on secret outputs.26- **Missing protections**: encryption at rest/in transit off (EBS/S3/RDS/SNS), logging/audit disabled27 (CloudTrail, flow logs, GCP audit), no MFA-delete/versioning, public snapshots/AMIs.28- **Kubernetes/Helm**: `privileged: true`, `hostNetwork/hostPID`, no `securityContext`/`runAsNonRoot`,29 wide RBAC (`cluster-admin`), secrets as env/plaintext, `latest` images, no network policies.30- **Ansible**: `shell`/`command` with unquoted vars, `no_log` missing on secret tasks, world-readable31 file modes, `validate_certs: no`.3233## Method341. Run `checkov`/`tfsec`/`kics` for a broad first pass; they cover hundreds of provider rules.352. `rg '0.0.0.0/0|public|Action.*\*|password|secret|privileged: true'` and review each hit's context.363. Trace module inputs/variables — an insecure default in a reused module multiplies everywhere.374. Check state handling (remote, encrypted, access-controlled) and CI that applies it (`code-review-cicd`).3839## Gotchas40- A finding's severity depends on blast radius — a public dev sandbox ≠ a public prod data store.41- Scanners miss cross-resource logic (an SG that's fine until paired with a public subnet) — reason about the whole graph.42- Secrets belong in a manager (Vault/SSM/KMS), never in variables or state — flag any inline secret.4344## References45CIS Benchmarks (AWS/Azure/GCP/Kubernetes); Checkov/tfsec/KICS rule sets; provider well-architected security pillars.