Infrastructure-as-Code Security

SkillCloud & infra

Terraform, CloudFormation, and Pulumi hardening: state as a secret store, pinned providers and modules, encryption and network defaults, drift, and the privilege of the pipeline that applies the plan. Use when generating infrastructure code, reviewing IaC changes in a pull request, configuring a state backend, or setting up a new cloud account or workspace.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Infrastructure-as-Code Security skill

What this skill tells your AI

The instructions your AI receives, as published by shieldnet-360/secure-vibe in skills/iac-security/SKILL.md and read by ahel’s review.

Rules (for AI agents)

ALWAYS

  • Treat the state file as a secret store. Every value that passes through Terraform — a generated password, an RDS master credential, a private key, the contents of a data source — is written to state in plaintext. sensitive = true only hides a value from CLI output; it changes nothing about what is stored. So read access to the backend is read access to those secrets, and the backend's access policy has to be written on that basis.
  • Configure a remote backend with encryption at rest, state locking, and versioning. Prefer the backend's own locking where it exists — recent Terraform supports S3-native locking, so a separate DynamoDB lock table is no longer required for new stacks. references/backends-and-state.md has the per-backend form.
  • Pin providers and modules to an exact version or a pessimistic constraint (~> 5.42), and pin a third-party module sourced from a git URL to a commit SHA, not a branch or tag. A module is code that runs with your apply credentials, and a registry or repository you do not control is a supply-chain input like any other.
  • Give the apply identity the least privilege that the stack actually needs, and keep it separate from the plan identity. A pipeline role with account-wide admin turns any CI compromise into a full account compromise — cicd-security owns hardening the pipeline itself, iam-best-practices owns the role's shape.
  • Encrypt persistent resources by default with a customer-managed key: object storage, block storage, managed databases, queues, log groups. Prefer a module or default that applies it, so a new resource is encrypted because of how the code is organised rather than because someone remembered.
  • Deny inbound by default and open ports deliberately. Administrative and database ports reachable from 0.0.0.0/0 are the finding — SSH, RDP, and the managed database ports especially — and "it is only dev" does not change the exposure. references/backends-and-state.md lists the ports worth failing a build over.
  • Run plan (or pulumi preview, a CloudFormation change set) in CI, require human approval before applying to production, and run scheduled drift detection that raises an issue when the cloud diverges from the code. Drift is where a break-glass change made at 3am quietly becomes the permanent configuration.
  • Scope roles and resource policies with the provider's own condition mechanism — source account, source ARN, organization ID, TLS-only access on storage. iam-best-practices owns policy design; what belongs here is that the condition is expressed in the code rather than clicked into the console.

NEVER

  • Hardcode provider credentials in code or .tfvars (access_key, secret_key, client_secret, service_account_key). Use OIDC federation from CI, the platform's workload identity, or a secret manager.
  • Commit terraform.tfstate, terraform.tfstate.backup, .pulumi/, or a .tfvars holding real values — see the state rule above for why the file is a credential dump even when the code only references variables.
  • Use local-exec / null_resource to fetch a secret at apply time. It lands in state, and the provisioner runs on whatever machine ran apply, with that machine's identity.
  • Disable provider TLS verification (skip_tls_verify, insecure = true).

KNOWN FALSE POSITIVES

  • A bastion deliberately reachable on SSH is not the same finding as a database open to the world — but "bastion" is not the exemption, its configuration is: key-only authentication, MFA, and a narrow source range. A session-manager or identity-aware-proxy path that removes the public port entirely is better than hardening one.
  • Resources that are meant to be internet-facing: CDN distributions, load-balancer listeners on 80/443, API gateways, function URLs.
  • Backend bootstrap resources — the bucket and lock mechanism the backend itself uses — cannot live in the state they provide. A one-time local backend that is then migrated is the normal resolution, not a finding.
  • An unencrypted resource that holds nothing but public data, where the tag or classification says so explicitly.

Context (for humans)

IaC mistakes scale by construction: one bad module is applied into every account that consumes it, and the blast radius is whatever the apply credential can reach. That credential is the part most reviews skip. A pipeline that can create IAM roles can create itself a better one, so the privilege of the thing running apply bounds everything else in this skill.

The other recurring surprise is state. Practitioners reach for sensitive = true and believe the value is protected; it is a display flag. Anything Terraform manages, it has seen, and anything it has seen is in the state file — which is why "who can read the backend" is a more consequential question than most of the resource-level settings a scanner will flag.

References

  • references/verifying-findings.md — confirm or refute a finding, then lock it
  • references/backends-and-state.md — backend and locking options per tool, what is stored in state and how to reduce it, and the port list worth failing a build over
  • checklists/terraform_hardening.yaml
  • checklists/cloudformation_hardening.yaml
  • CIS AWS Foundations Benchmark.
  • Terraform recommended practices.
  • NIST SP 800-53 Rev. 5.

Signals

GitHub stars
22
Last commit
Aug 2026
Advanced
Catalog kind
skill
Gateway key
iac-security
Source
github.com/shieldnet-360/secure-vibe