IaC Scanner
Infrastructure as code turns a cloud account into a text file, so a misconfiguration is a line you can search for. This scanner reads every .tf and .tfvars file and runs eight AWS-oriented regular expressions over the raw text: open security groups, wildcard IAM, secrets in variable defaults, public buckets, and a few others.
Which files it reads
The simplest discovery in the group: file extension only.
1The scanner looks at the repository file index. Infrastructure as Code has a clear file extension, so extension is the only test.
2Files ending in .tf or .tfvars are Terraform. Every one gets all eight checks, with no per-file routing. The .tfvars files matter because that is where people paste real values.
3Everything else is passed over. CloudFormation templates are not read, nor are JSON Terraform, state files or documentation.
Walking a Terraform file
Eight checks, nine rules. The IAM check reports actions and resources as separate findings.
1One Terraform file, twenty-one lines. Eight checks run in a fixed order over the raw text; the HCL is never parsed. Two checks (ALB and ECS) will find nothing here.
2Security group. A regular expression finds an ingress { block that holds 0.0.0.0/0 (or ::/0), then reads from_port out of the same block. Ports 80 and 443 are allowed; 5432 is not.
3IAM action. "Action" : "*" in JSON form, actions = ["*"] or action = "*" in HCL. The policy can call every AWS API.
4IAM resource. The same shapes for Resource. Reported separately and one level lower, because a wildcard resource with narrow actions is less dangerous.
5Hardcoded secret. A default = value shaped like a Stripe live key, Anthropic key, AWS access key, GitHub token, OpenAI key, a database URL or a JWT. The value must look like the secret; a word like changeme does not match.
6Public S3. acl = "public-read" or public-read-write anywhere in the file.
7Secrets Manager. recovery_window_in_days = 0 deletes a secret immediately and permanently. A mistake cannot be undone.
8Log retention. Any retention_in_days of 7 or fewer is flagged. The title carries the number.
9Seven findings. The ALB and ECS checks stayed quiet because this file has neither a plain HTTP forward nor assign_public_ip = true. Missing encryption and missing public access blocks are not checked.
What it deliberately skips
Each row is a line the scanner meets. Step through for the verdict and the reason.
1Web ports are allowed. The check exists to catch databases, SSH and application ports, not the load balancer's front door.
2No port, no finding. The port is part of the title and the decision. A block without a from_port is skipped, which can hide an all-ports rule.
3IPv6 is covered. The IPv4 and IPv6 patterns are separate, so opening a port to ::/0 is not a way around the check.
4Seven days or fewer is short. The scanner suggests 30 to 90 days for investigation and compliance.
5Only known secret shapes. A weak password in a default is not detected here. This keeps the check at Critical, conf 0.95, without noise.
6A real key shape does match. This is the documented AWS example key id, and it is flagged all the same.
7The ALB check is file-wide. A redirect or an HTTPS listener anywhere in the same file turns the finding off, even if it belongs to another load balancer.
The fix, line by line
The fixed form is the one the regular expressions do not match.
1Before: the seven findings from the walk. Each step fixes one line and the matching checks go quiet.
2Narrow the source range. Only the load balancer or the VPC should reach a database port.
3Grant what is needed. One action, one resource ARN. Both IAM findings clear with this one edit.
4Remove the value from the file. The variable stays, the secret does not.
5Make the bucket private and put CloudFront in front if the objects should be public.
6Allow recovery. Seven days is the minimum the scanner accepts.
7Keep logs long enough to investigate. Six edits clear all seven findings.
Why it matters
Infrastructure misconfigurations are the root cause of most cloud data breaches. Public S3 buckets have leaked data from hundreds of companies. Overly permissive IAM roles let an attacker escalate from one compromised service to full account control. A secret committed in a Terraform default is in version control for good.
Twitch (2021). An AWS misconfiguration contributed to the leak of Twitch's entire source code and payout data. Accenture (2017). Four AWS S3 buckets were left public, exposing secret API data, authentication credentials and decryption keys.
Vulnerable vs fixed code
# BAD: the walk above
variable "stripe_key" {
default = "sk_live_abc123def456"
}
resource "aws_security_group" "db" {
ingress {
from_port = 5432
cidr_blocks = ["0.0.0.0/0"]
}
}
resource "aws_s3_bucket" "data" {
acl = "public-read"
}# GOOD: private S3 bucket with encryption
resource "aws_s3_bucket" "data" {
bucket = "my-app-data"
}
resource "aws_s3_bucket_public_access_block" "data" {
bucket = aws_s3_bucket.data.id
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}
resource "aws_s3_bucket_server_side_encryption_configuration" "data" {
bucket = aws_s3_bucket.data.id
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "aws:kms"
}
}
}Checks and limits
Every check, with the severity and confidence the code assigns.
| Check | Fires when | Severity | Conf. |
|---|---|---|---|
| Open ingress | ingress block with 0.0.0.0/0 or ::/0 and a port other than 80 or 443 | High | 0.90 |
| IAM Action | "Action" : "*", actions = ["*"], action = "*" | High | 0.90 |
| IAM Resource | the same three shapes for resource | Medium | 0.90 |
| Secret default | default = value shaped like a known key, URL or JWT | Critical | 0.95 |
| Public S3 | acl of public-read or public-read-write | High | 0.90 |
| Recovery window | recovery_window_in_days = 0 | Medium | 0.80 |
| ALB HTTP forward | protocol = "HTTP" then type = "forward", with no "HTTPS" or "redirect" in the file | Medium | 0.85 |
| ECS public IP | assign_public_ip = true | Low | 0.70 |
| Log retention | retention_in_days of 7 or fewer | Low | 0.65 |
The scanner reads only .tf and .tfvars and does not check unencrypted storage, a missing public access block, disabled CloudTrail and flow logs, or default VPC use. It checks open security groups, secret defaults, Secrets Manager recovery, ALB HTTP, ECS public IPs and log retention. It is AWS only. Severity runs from Low to Critical. Findings carry the file path only.