Introduction
If you’ve ever been burned by a simple misconfiguration that escalated into a serious security issue, you’re not alone. As someone who’s been hands-on with DevOps and infrastructure security for over two decades, I’ve seen firsthand how quickly good intentions in code can lead to open S3 buckets or over-permissive IAM roles in production.
Tools like Terraform and Ansible have made it easier for teams to automate infrastructure, but with that speed comes risk. Terraform lets you spin up cloud resources at scale, while Ansible configures them for use. But one wrong IAM policy or a hardcoded secret left in your repo can be all it takes for attackers to get in.
That’s where Infrastructure as Code (IaC) security checks come in. When properly implemented, they help you catch these issues early - before you even get to staging. In this guide, I’ll walk you through how to scan your Terraform and Ansible code using tools like tfsec, Checkov, and ansible-lint. More importantly, I’ll show you how to make these checks part of your development workflow so they just happen - no one-off manual scans or guesswork required.
Let’s get into it.
The Real-World Risks in IaC: Why It Matters
IaC is fantastic when it comes to speed, consistency, and reducing human error - but it’s also dangerously easy to overlook small mistakes that have big consequences. Terraform and Ansible templates live in your codebase, and any misconfiguration gets baked right into your infrastructure. Here are the most common pitfalls I’ve seen crop up:
-
Hardcoded Secrets: I’ve lost count of how many times I’ve seen AWS credentials or API keys hardcoded into
variables.tfor even directly in Ansible playbooks. These end up in version control, and now you’ve got access keys onegit cloneaway from exposure. -
Too Much Access (Overly Permissive IAM): Developers often use wildcard actions like
"*"just to get things working. Understandable under pressure - but you’re basically handing over the keys to your cloud kingdom. -
Publicly Exposed Resources: An open S3 bucket, an unprotected EC2 port, or an SSH-enabled VM on a public IP - it’s frightening how often these still go live undetected.
-
Drift and Configuration Inconsistency: Just because the code says one thing doesn’t guarantee the deployed environment matches. That drift can open quiet, undetected holes.
-
Compliance Blind Spots: If your settings don’t adhere to organizational or industry standards (think CIS or NIST), you could face legal and operational risks - and no one wants to get that call from the auditor.
So how do we avoid this pain? Simple: scan early and scan often.
IaC Security Scanners That Actually Work
We’re going hands-on with three tools that consistently deliver for real-world Terraform and Ansible scanning needs.
tfsec – Built for Terraform
tfsec is my go-to Terraform scanner. It’s straightforward, fast, and doesn’t require you to deploy anything. It just reads the code and gives you real, actionable feedback.
What tfsec does best:
- Flags hardcoded secrets, even in complex var loop structures
- Detects insecure AWS/GCP/Azure settings (like unencrypted storage or open SGs)
- Warns on overly broad IAM permissions
- Maps findings to security standards like CIS and AWS Well-Architected
Try it like this:
tfsec ./terraform/
You’ll get a list of issues with severity levels and descriptions - right down to offending lines of code. It’s practical intelligence for anyone serious about catching problems before they hit staging.
Checkov – The Swiss Army Knife of IaC Scanning
Checkov is incredibly versatile. It handles Terraform, yes, but also covers Ansible, Kubernetes, CloudFormation, and more. I recommend Checkov when you’re operating in a multi-IaC environment or want policy-as-code enforcement baked in.
Why I like Checkov:
- Detects hardcoded credentials and secrets
- Scans for insecure settings across multiple cloud platforms
- Supports custom policies using OPA
- Integrates well into GitHub/GitLab/Jenkins pipelines
Basic usage:
checkov -d ./terraform/
checkov -d ./ansible/
Checkov spits out detailed reports with remediation suggestions, compliance tags, and scores. It’s powerful, especially when you want to align to governance frameworks automatically.
ansible-lint – Lightweight, No-Nonsense Ansible Checker
Ansible can be deceptively simple. I’ve seen teams make rookie mistakes like running dangerous shell commands with become: true across the entire fleet. That’s where ansible-lint shines - it alarms on things you don’t always think to double-check.
What it catches:
- Shell commands that may be unsafe
- Deprecated or bad syntax
- Missing handlers or defaults
- Secrets and credentials stored in plaintext
To run it:
ansible-lint ./playbooks/
This tool enforces community (and customizable) best practices. It’s great for teams trying to enforce consistent, secure playbooks over time.
Shift Left: Integrating Security into Your CI/CD Pipeline
The whole point of scanning is to surface issues early - ideally even before code is committed. Here’s a quick roadmap to making that happen:
Use Pre-Commit Hooks
Add scanning into developer workflows so they kick in even before a push. pre-commit hooks for tfsec and ansible-lint exist and are easy to configure.
Embed in CI Pipelines
Here’s an example using GitHub Actions to run a tfsec scan on every push:
- name: tfsec – Scan Terraform
uses: tfsec/[email protected]
with:
directory: ./terraform
You can make pipeline steps fail if high-severity issues are found. It’s the fastest way to enforce security policy without becoming the “blocking” security team no one wants to deal with.
Educate Your Devs
Make it easy for your developers to understand why certain checks exist. Show them what tfsec or Checkov is flagging and how to fix it. Security culture only sticks when it’s shared.
Pro Tips from the Field
Stop Hardcoding Secrets - Seriously
Always inject secrets dynamically. Use:
- Terraform
datablocks for secrets from Vault or cloud secret managers - Ansible Vault for encrypting sensitive variables
- Environment variables injected at runtime
If you must, also add TruffleHog or GitLeaks to catch accidental secrets in commits.
Strict IAM = Safe IAM
Look, IAM isn’t fun, but least privilege is better than most risk. Avoid the "*" trap. Break roles down. Use tools like terraform-compliance to enforce policy scopes if needed.
Keep Tools and Rules Fresh
New risks emerge every month. A stale tfsec or Checkov install won’t catch everything. Update dependencies regularly and check changelogs - especially when cloud service providers announce changes.
Modularize for Sanity
Use well-defined, secure Terraform modules or Ansible roles with proper input validation. You’ll reduce repetition, centralize fixes, and improve auditability.
Avoiding Pitfalls: Common IaC Scanning Headaches
| Problem | What’s Happening | How to Fix It |
|---|---|---|
| tfsec missing issues | It’s outdated or cache is stale | Update it (brew upgrade tfsec) |
| Checkov false positives | Unclear module references | Use --skip-paths or custom policies |
| ansible-lint breaking builds | Deprecated or invalid syntax | Run Ansible syntax check first |
| Secret leaks still happen | Tool doesn’t parse all formats | Add TruffleHog or GitLeaks to repo |
| Long CI scan times | Too many files or repeated scans | Cache rule downloads, split jobs |
Must-Have Security Habits (Checklist)
- Scanning happens locally and in CI
- Secrets are externalized or encrypted
- IAM permissions are narrowly scoped
- IaC code is modular and versioned
- Tools are updated as part of CI lifecycle
- Alerts are triaged, not ignored
- Devs understand fix strategies
Security isn’t just about finding the issue - it’s about closing the loop.
Useful Resources
Wrapping Up
Securing your infrastructure at the code level isn’t a luxury anymore - it’s table stakes. When Terraform and Ansible are used to manage your entire production environment, a single misconfigured line can cause serious problems. Luckily, with tools like tfsec, Checkov, and ansible-lint, you can build IaC security into your development lifecycle from the beginning - no more last-minute fixes or post-deploy panic.
So start scanning. Bake it into your workflow. educate your teams. And remember:
Infrastructure security doesn’t start in the cloud.
It starts in your code.
Stay safe - and ship with confidence.
Looking to improve container security too? Check these out from INFOiYo: