AWS infrastructure as code is the practice of defining your AWS resources in declarative files that live in Git, and its biggest security payoff is that every S3 bucket, IAM role, and security group becomes reviewable before it ever exists. Instead of clicking through the console and hoping someone remembers what they changed, you get a diff. That diff is where security should happen.
Most teams reach for Terraform, AWS CloudFormation, or the AWS CDK. The tool matters less than the discipline around it. Below is how I approach securing an AWS IaC pipeline that I actually trust.
Why IaC changes the security model
When infrastructure lives in code, misconfigurations become bugs, and bugs can be caught with the same tooling you already use for application code: linters, tests, code review, and CI gates. This is the whole promise of infrastructure as code in a DevOps workflow. A public S3 bucket is no longer a mystery discovered during an incident; it's a line in a .tf file that a reviewer can flag.
The flip side is that a mistake now scales. One bad module reused across forty stacks propagates the same open port forty times. So the review and automated-check layer has to be real, not decorative.
The misconfigurations that actually bite
After enough cloud reviews, the same handful of issues show up repeatedly:
- S3 buckets with
acl = "public-read"or a bucket policy allowingPrincipal: "*". - Security groups opening
0.0.0.0/0on port 22 or 3389. - IAM policies with
Action: "*"andResource: "*"— the classic over-privileged role. - Unencrypted EBS volumes and RDS instances (encryption is off by default in older resource definitions).
- Missing bucket versioning and no server-side encryption on data stores.
Here is a Terraform snippet with a common mistake:
resource "aws_security_group" "web" {
name = "web-sg"
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"] # SSH open to the entire internet
}
}
The fix is to scope the CIDR to a bastion or corporate range, or to drop SSH entirely in favor of AWS Systems Manager Session Manager. The point is that a scanner can spot that 0.0.0.0/0 on port 22 automatically, on every commit.
Policy as code: your first automated gate
Static analysis of IaC files is where you catch most problems cheaply. A few battle-tested open-source options:
- Checkov (Bridgecrew) — hundreds of built-in policies for Terraform, CloudFormation, and CDK.
- tfsec / Trivy — fast Terraform-focused scanning, now consolidated under Trivy.
- KICS — broad IaC coverage across Terraform, CloudFormation, Ansible, and Kubernetes.
- OPA / Conftest — write your own org-specific rules in Rego when built-ins aren't enough.
Running Checkov is as simple as:
checkov -d . --framework terraform --compact
Commercial platforms fold this in too. Snyk infrastructure as code, for example, scans Terraform, CloudFormation, and Kubernetes manifests against a large built-in ruleset and integrates into the IDE and CI. Whatever you pick, wire it into a pre-merge check so a failing policy blocks the pull request rather than emailing someone after deployment.
Secrets do not belong in your IaC
A recurring finding is hardcoded credentials in .tf files or, worse, in terraform.tfvars committed to the repo. State files are the other trap: Terraform state stores resource attributes in plaintext, including some secrets, so an unencrypted state bucket is a real exposure.
Practical rules:
- Store state in an encrypted, versioned S3 bucket with a DynamoDB lock table, and lock down access with IAM.
- Pull secrets at apply time from AWS Secrets Manager or SSM Parameter Store using data sources, not literals.
- Add a secret scanner (gitleaks, trufflehog) to CI so an accidental
aws_access_key_idnever merges.
data "aws_secretsmanager_secret_version" "db" {
secret_id = "prod/db/password"
}
# reference: data.aws_secretsmanager_secret_version.db.secret_string
Drift and the gap between code and reality
IaC only protects you if the running infrastructure matches the code. Someone doing a "quick fix" in the console creates drift, and now your reviewed, scanned files describe a fiction. Run terraform plan on a schedule and alert on unexpected diffs, or use AWS CloudFormation drift detection for stacks. Treat out-of-band changes as incidents, not conveniences.
Wiring it into CI/CD
A sane pipeline for AWS infrastructure as code looks like this:
- Developer opens a PR with a Terraform change.
- CI runs
terraform fmt -check,terraform validate, then a policy scan (Checkov/Trivy). terraform planoutput is posted to the PR for a human reviewer.- Merge is blocked if any high-severity policy fails or the plan touches sensitive resources.
terraform applyruns from CI with a scoped role, never from a laptop.
The dependencies your IaC pulls in — provider plugins, modules from the registry — carry supply chain risk too. An SCA tool can flag a compromised or vulnerable module version before it lands in your pipeline. If you want to go deeper on scanning strategy, our code vulnerability scanning tools guide covers the tradeoffs.
A short maturity checklist
- Every resource type has a default of encryption-on and least-privilege.
- Policy-as-code runs on every PR and blocks on high severity.
- State is encrypted, remote, and access-controlled.
- Secrets come from Secrets Manager, never from committed files.
- Drift detection runs on a schedule and pages someone.
- Reusable modules are versioned and themselves scanned.
FAQ
What is the difference between infrastructure as code and configuration management?
Infrastructure as code provisions resources — it creates the VMs, buckets, and networks. Configuration management (Ansible, Chef) configures what runs inside them. In an AWS DevOps workflow you often use both: Terraform to build the EC2 instance, then a config tool or user data to set it up.
Is Terraform or CloudFormation more secure?
Neither is inherently more secure; security comes from the checks around them. CloudFormation has native drift detection and tight AWS integration, while Terraform has a larger ecosystem and works across clouds. Both are scanned by the same policy-as-code tools.
Do I still need runtime cloud security if I scan IaC?
Yes. IaC scanning catches misconfigurations before deployment, but it can't see credentials leaked at runtime, resources created out-of-band, or drift you haven't detected yet. Pair pre-deploy IaC scanning with runtime posture management for full coverage.
Can Snyk infrastructure as code replace open-source scanners?
Snyk infrastructure as code and open-source tools like Checkov overlap heavily on policy coverage. Teams often start with the open-source scanners in CI and adopt a commercial platform when they need centralized reporting, IDE feedback, and support across many teams.