
What is it?
Infrastructure as code (IaC) has given us many advantages for provisioning and maintaining the infrastructure our application code runs on. Not least, it gives us confidence that the underlying platform is what we intend it to be. However, sometimes direct access to virtual machines and services results in a running environment that no longer looks like the code describing it. We call this drift.
How does it work?
We’ve had drift detection in envzero for some time, originally as an engineered solution that took more steps than we were totally happy with. So we’ve made a significant update and drift detection is now a much simpler process to enable. The docs page details all the steps, but let’s take a brief look at it here.
Schedule a drift detection job under the environment triggers section, using standard crontab syntax

Add notifications under the project settings:

The status of the job is also available to see in the Deployments tab of the Environment UI

How does it help me?
Whenever we talk to customers about their deployment processes, they’re usually trying to move away from the old workflow of maintaining servers. IaC is the foundation of the idea of ephemeral infrastructure elements, of services that are defined by repeatable code. But if the code doesn’t represent reality, it can be hard work trying to change processes for the better. Having a simple signifier that our infrastructure code doesn’t reflect reality is a great step towards aligning code and services.

If you’d like to chat about managing your infrastructure as code, and how to address drift, drop us a line, or even message us on Twitter.
Related Content
The new env zero Agent CLI is available now. Ask your coding agent about your infrastructure in plain English, and it answers from real state, inside the same roles, approvals, and audit trail your team already runs on.
Today we are launching the Agentic Experience (AX) on env zero, powered by the new env zero Agent CLI. The idea is simple. You point your coding agent, whether that is Claude Code, Cursor, Codex, or Copilot, at your env zero infrastructure, ask it a question in plain English, and it answers from your real environments, deployments, and drift instead of guessing. It is available to every account starting now.
Coding agents are already inside your workflow. They read your codebase, propose changes, and increasingly get asked to do the work rather than describe it. The open question is what they are plugged into when they try. Point one at your infrastructure today and, on most platforms, it sees a thin slice of current state, fills the gaps with guesses, and burns tokens scraping an API that was never meant for a machine to reason over. It can talk about your infrastructure. It cannot reliably operate it.
The Agent CLI changes what the agent is standing on. It gives your agent the full picture, every environment, module, template, plan, and the deployment history behind them, in a form built for a context window instead of a browser tab. Ask a question, and the agent reads real state to answer it. Ask for a change, and it acts through the same roles and approvals a person would. The commands in this post are the plumbing. The product is the conversation on top of them.
Ask your infrastructure a question
Here is what the Agentic Experience looks like in practice. Each example is a prompt an engineer types to their agent. Underneath each one is the command the agent actually runs, the receipt for what it did. You never have to type the command yourself.
"Why did payments-staging go red? Is it our change or drift?"
The agent pulls the environment's full context, its state, recent deployments, and a drift or failure summary, in a single request, then tells you whether the failure traces to your last deploy or to something that changed underneath it.
env0 context payments-staging
"Before I merge this, plan the change against prod and tell me if anything gets replaced."
The agent starts an approval-gated deployment, so the plan runs but nothing applies without a human. It reads the plan, flags any resource that would be replaced rather than updated, and leaves the change waiting for your sign-off.
env0 environment deploy prod --requires-approval
"Which environments in data-platform haven't deployed in 30 days, and what are they costing us?"
The agent lists every environment in the project as structured data, filters by last deployment date, and adds up the cost estimates, so you get the stale environments and their spend in one answer.
env0 environment list --project data-platform -o json
"Anything waiting on my approval? Summarize what each one changes."
The agent finds the deployments paused at an approval gate, reads each plan, and gives you a one-line summary of what every pending change would do before you approve or cancel it.
env0 deployment list -o json
None of these require you to know the commands, and that is the point. The Agent CLI hands the agent structured JSON on stdout, errors on stderr, and stable exit codes, so it can chain reads and actions and know exactly what happened at each step without you translating between English and the API.
Governance that already applies to agents
This is the part security teams care about, and it works today.
An agent on the Agent CLI is not a special case that sits outside your controls. It authenticates as a real env zero identity, per user through the browser or per service through an API key, never a shared token, so every read and every action is attributable to someone rather than fired anonymously.
Because your existing role-based access control applies to that identity, you decide what the agent can do simply by choosing the identity you give it. Hand it a read-scoped identity and you get an agent that can diagnose anything and change nothing. It can pull context, list environments, and read plans and logs, while deploy, destroy, and approve are not available to it at all. Give it a broader identity and the approval gates still hold. A deployment that requires approval pauses for a human no matter who or what started it, and destroying infrastructure still takes an explicit confirmation.
So the safe pattern is available now, with no new product to adopt. A read-only agent that investigates and explains, a human in the loop for anything that changes infrastructure, and a full audit trail, because the agent acted as itself and not as a key nobody can trace.
The skill is the seed of your agent operating policy
Getting an agent set up is one command.
env0 skill install
That writes a usage guide into your coding agent's config so it knows the exact commands, flags, and output formats for the version of the Agent CLI you have installed. It sets up Claude Code by default, with --agent cursor, --agent codex, or --agent copilot for the others.
Two things about that guide matter more than they first appear.
It is version-matched. The agent works from the command surface you actually have, not one it half-remembers from training. Invented flags are the fastest way for an agent to lose an engineer's trust on infrastructure, and a version-matched guide is how you keep them out.
And it is a file in your repository, not a hosted black box. You commit it, and you extend it. Add your own conventions on top: the golden-path templates a new environment should start from, a rule that no agent touches prod without approval, a list of projects that are off limits. Once it is committed, every agent that every engineer runs inherits the same operating manual, and it gets reviewed in a pull request like any other code. You are not just installing a skill. You are planting the seed of your team's agent operating policy, in version control, where it belongs.
Why it goes deeper than an API wrapper
A generic CLI wrapped around an API is only as good as the API underneath it. env zero already understands your environments, your modules, your deployment history, and how they connect, and the Agent CLI is built on that understanding rather than layered over it.
The clearest example is env0 context. It returns an environment's state, recent deployments, and drift or failure summary in a single call, so an agent diagnoses a broken deployment in one request instead of stitching the picture together across several. Fewer round trips, less context spent, and an answer grounded in real state.
It also clears the three obstacles we heard about from nearly every team that tried to put agent access in front of a platform. Security teams distrusted a shared, unattributable credential. One enterprise customer's security team blocked our old MCP server outright and started patching around the credential model before they ever raised it with us. Setup was a wall. As one account team put it while describing the self-hosted container, four out of five customers got stuck standing it up. And even where it worked, the surface underneath was thin, showing the latest deployment only, with no history. The Agent CLI answers all three. There is no container to stand up, a real per-identity login replaces the shared token, and the surface is deep enough that an agent never has to fall back to the raw API for context.
The old MCP server keeps working for existing integrations, but new agent capability lands in the Agent CLI now. That is where the Agentic Experience lives going forward.
What's in this release
- Point Claude Code, Cursor, Codex, or Copilot at env zero and ask about your infrastructure in plain English
- Read across environments, deployments, projects, templates, and plans, including full history
- Diagnose a failed environment (state, recent deployments, and drift) in a single env0 context call
- Run core actions when you allow it: create, deploy, destroy, approve, cancel, abort
- Scope agents with your existing roles and approvals, with every action attributable to a real identity
- See cost estimates alongside your reads
- Install a version-matched, extensible skill for your agent with one command
What comes next
Today you scope an agent by choosing the identity you give it. Next, we are making read-only the default for agents regardless of the human behind them, with write access as an explicit, audited step someone has to grant. An engineer with full permissions still gets a read-only agent unless they deliberately elevate it.
We are also expanding what an agent can see, starting with policy and governance configuration, so it can read the guardrails a project runs under and not just its deployments, and we are widening the read surface from there.
The goal has not changed. Give an agent enough real context to be useful, and never more access than it has earned.
Get started today
The env zero Agent CLI is available now. Install it with Homebrew or npm:
brew install env0/tap/env0
- Sign in with:
env0 login - Run and setup your agent with:
env0 skill install - Ask your first question
The full env zero Agent CLI documentation covers every command, flag, and output format.
Want a walkthrough? Schedule a technical demo to see the Agentic Experience in action.
FAQ
What is the env zero Agentic Experience? It is the ability to point a coding agent, such as Claude Code, Cursor, Codex, or Copilot, at your env zero infrastructure and work with it in plain English. The agent answers from your real environments, deployments, and drift, and can take action through the same roles and approvals a person would. It is powered by the new env zero Agent CLI, available now.
How is this different from the old MCP server? The MCP server needed a self-hosted container and a single shared credential, and it only ever saw the latest deployment. The Agent CLI installs directly as a single binary, authenticates per user or per service account, reads the full history and diagnosis surface, and returns structured output an agent can parse without extra tooling. The MCP server keeps working for existing integrations, but new agent capability lands in the Agent CLI.
Can I stop an agent from changing infrastructure? Yes, today. An agent authenticates as a real env zero identity and inherits that identity's role. Give it a read-scoped identity and it can diagnose but not deploy, destroy, or approve. Even with a broader identity, approval gates still pause changes for a human, and every action is recorded against the identity that ran it.
What exactly does the skill do? env0 skill install writes a version-matched usage guide into your agent's config so it knows the real commands and flags for the CLI you have installed, which keeps it from inventing them. Because the guide is a file in your repository, you can commit it and extend it with your own conventions, so every engineer's agent inherits the same rules.
What is on the roadmap? Read-only-by-default access for agents regardless of the human behind them, with an explicit, audited path to write access, broader policy and governance visibility in the CLI, and continued expansion of the read surface.
Get started: install the env zero Agent CLI or read the docs
Announcing the env zero Agentic Experience: Point Your Coding Agent at Your Infrastructure


“All these investments in DevOps and developer productivity and operational efficiency are bottlenecking in these environments on security and compliance.”
This was an observation from Andrew Clay Shafer in a fireside chat with John Willis at DevOps Days Dallas 2022. One such bottleneck can come in the form of audit logs, but auditability doesn’t have to be a blocker.
In this post we’ll take a look at why auditing is necessary for Infrastructure as Code, the benefits of having an audit trail for Terraform and other IaC frameworks (such as Terragrunt, Pulumi, CloudFormation, Kubernetes, and others), and share how you can automate your audit trail easily with env0.
How do you audit Infrastructure as Code?
All you need is a central log management system that can aggregate and parse your audit. env zero delivers a number of benefits for auditability:
- Changes to infrastructure are tracked in the code repository, making it easy to see who made what changes and when.
- Automatically roll back changes that cause problems.
- Audit changes made by third-party vendors.
Audit log walkthrough
There are two ways to access audit logs in env0, 1) through the UI, and 2) through the API. As always, env zero gives you the flexibility to interact with your infrastructure-as-code as it suits your organization, be it programmatically or through a simple user interface. Only an Admin user can access the Audit Logs.
The audit log contains information about who performed the activity, when the action was performed, the activity’s description, and additional data like their IP address.
The audit log shows events related to changes in your:
- Organization
- Projects
- Templates
- Environments
- Teams
- Users
- Roles
- Modules
- Git Tokens
- Cloud credentials
- API keys
- SSH keys
- Variables
- Agent configurations
Through the env zero UI
- Go to the Organization's Settings page.
- Click the Audit Logs tab.
- The audit details are listed in a table.
- Click the row's + sign to reveal additional activity details.
- Click the Show more button at the bottom of the page to see more rows.

Through the env zero API
Use the "Fetch Audit Logs" API to retrieve your organization's audit logs programmatically. Learn more about the audit log in our documentation.
Use an audit log for governance and compliance
With this latest release, we’re continuing to deliver the enterprise-level capabilities to enable DevOps, Platform, and Infrastructure as Code teams to deliver secure software faster while ensuring compliance with internal policies or external regulations. env zero has clearly auditable versioning of infrastructure changes, giving you the answer to questions like, “What was changed, who changed it, and when was it changed?”
We help you avoid the audit and compliance bottleneck, so you can focus on what’s important—shipping software.
You Need Audit Logs for Your Infrastructure as Code, and They’re Easy to Set Up


In a recent blog post, I discussed expanding the idea of “Feature branches” to “Feature environments”. Using Infrastructure-as-Code, we can create an environment for every feature we are working on, thereby giving us a more flexible, isolated development environment, and allowing us to test our code early in the development process.
In this post I’d like to continue down that path, and see how we can automatically create an environment for every pull request, and gain a number of advantages over traditional static staging or qa environments.
Pull Requests & Moving Beyond Static Staging
Pull requests are a well known and common workflow step for many development teams. We usually think of them as a way you “tell others about changes you've pushed”, and where you “can discuss and review the potential changes with collaborators and add follow-up commits before your changes are merged”.
PR’s are more than just a code review - they’re a milestone in a feature’s lifecycle and a way of saying “I’m ready for this to be shared”. Beyond sharing it for feedback with the wider team, this milestone is a critical time to ensure it functions exactly as expected as part of the whole application, including any potential infrastructure or configuration changes. However - just as we wouldn’t want our data migration to run on the shared database at this point, we also want to use dedicated test infrastructure.

Static VS Dynamic PR Environments
At this point, you might ask yourself - I’m already testing my code and infrastructure changes in our dev/qa/staging environment, why complicate things?
Well, there are a number of advantages to moving from traditional, static environments, to dynamic, per-pull-request environments:
- They’re Isolated and Dedicated - having a dedicated environment for each PR means no more confusion of which version or branch is currently in staging, and no coordinating between people who want to test different versions.
- Easier To Share - Because each PR has its own fully functional environment, non technical stakeholders can provide feedback on new features very early in the process. Developers can then iterate over this feedback - without interfering with work being done by other team members.
- No Wasted Resources - Because you’re only provisioning an environment when you actually need it for testing, you’re not wasting (or paying for) resources when you don’t actually need them.
- Removes Bottlenecks In The Release Cycle - Shared development and staging environments are notorious bottlenecks for development teams, especially when they are the first place where new code meets infrastructure. It’s not uncommon to see a queue of who is using the environment for testing their features. Your developers time shouldn’t be spent on waiting.
How Do You Actually Do It?
Ok, so “per pull request environments” is an awesome idea. How are we going to actually get there? There are a number of tools out there that can help you accomplish this task but in this post, I’ll be using env0, a first of it’s kind environment-as-a-service platform - not just to deploy the environments, but to manage them as well.
Your default assumption might be to just use your CI/CD platform to set up your environment. This works, but most CI/CD platforms are built for running short lived tasks, whereas an environment’s lifecycle extends beyond deploying it once: It needs to be updated, monitored, and in the end destroyed. Besides easily automating resource provisioning using Terraform, env zero will help me keep track of which environments are up, which ones have had issues, and will provide me a top level view of how my whole team is using these environments.
Besides env0, I’ll be using Github to host my code and open pull requests, and Github Actions to trigger my environment creation. I’ll be using the same code example from the previous post, which will be deployed on AWS.
If you’d like to try this out yourself, the prerequisites for this tutorial will be
- An env zero account (it’s free, just login)
- A Github account
- An AWS account

Getting Our Hands Dirty
Step one to fully automating anything is to make sure we can run it manually, so you’ll want to get your system set up. In my case, I’ve followed env0’s getting started guide, and taken the key steps of creating my own organization, connecting my AWS account, and creating a template for my Terraform code.
Custom workflows to the rescue
In the example code I’ve used, I also ran a bash script before deploying the environment. We can easily make sure this code runs before our Terraform is applied, using env0’s Custom Flows feature. I’ve already done this in advance and I’ve put my code in the env0.yml file, in our Github repo.
Let ‘er Rip!
We are ready to launch our first environment! Remember - this is just a manual test, to see things are ready for automation.
In the case of env0, just go to your Project Templates pages, and click “Run now” on the template we’ve created before. In the next screen, you can validate your settings, and when you’re ready - click “Run”.

Great!
Integrating into CI/CD
Now that we know our environment management system will properly configure our environments, we need to make it run each time we open a pull request. For that, we’ll be using Github Actions to trigger env0’s CLI.
In order to create an environment on env zero from Github Actions, we need to create an API key for env0.
Next, we’ll need to save the API key and secret as Github Secrets, in the same manner we saved our AWS credentials to env0.

The final step of connecting everything, is telling Github how to trigger our environment deploy. We’ll add the following code to our codebase, in the file `.github/workflows/pr-environments.yml`.
name: "PR Environments"
on:
pull_request:
types: [opened, closed, reopened, synchronize]
jobs:
env0_pr_environment:
name: "PR Environment"
runs-on: ubuntu-16.04
env:
ACTION: deploy
steps:
- name: Set Action
if: github.event.action == 'closed'
run: echo "::set-env name=ACTION::destroy"
- uses: actions/setup-node@v1
with:
node-version: '12'
- uses: actions/checkout@v2
with:
repository: env0/env0-client-integrations
- name: install
working-directory: node
run: yarn
- name: deploy
working-directory: node
run: >
node env0-deploy-cli.js
--apiKey ${{ secrets.ENV0_API_KEY_ID }}
--apiSecret ${{ secrets.ENV0_API_KEY_SECRET }}
--action $ACTION
--organizationId ${{ secrets.ENV0_ORG_ID }}
--projectId ${{ secrets.ENV0_PROJECT_ID }}
--blueprintId ${{ secrets.ENV0_BLUEPRINT_ID }}
--environmentName "${{ github.head_ref }}"
--revision "${{ github.head_ref }}"
In the code above, you can see we
- Determine the action depending on the Github event data
- Fetch the env zero CLI, using the `checkout` action
- Run the env zero cli to deploy, update, or destroy the environment
- The name of the environment will be the branch name
That’s all folks!
We now have a fully functioning pipeline, and our setup will automatically create a new environment for every PR we open! When we deploy a new feature, even if that feature requires new or different infrastructure, the changes in our Terraform code will automatically be reflected in the resources provisioned for the PR environment!


In the case of env0, even though environments will be automatically created and destroyed by our CI/CD integration, we can also use the env zero UI as a control plane, for understanding which environments are up, and what they consist of. You can also use env0’s cost monitoring features, to understand how much each of these environments actually costs.

Thank you for taking the time to read this post, I hope it helps you setting an environment-per-PR pipeline for your team. Once you’ve tried it yourself, I’d love to hear about it! Let me know in the comments below or on Twitter at @envzero.
Why You Should Be Using Per-Pull Request Environments (and how!)


In this guide, we will be exploring three IaC scanning tools, Checkov, tfsec, and Terrascan. We will go into detail of each tool, as well as compare the features of all three. You can explore the other parts of this guide below.
Jump to section:
Checkov vs tfsec vs Terrascan: Which IaC Scanning Tool is the Best?
Infrastructure as Code (IaC) is a popular approach to automate the provisioning and management of cloud computing resources using declarative configuration files. However, IaC also introduces new security challenges and risks that need to be addressed before deploying to production. In this blog post, we will compare three popular IaC scan tools: Checkov, tfsec, and Terrascan. These tools can help you identify and fix security issues in your IaC code before they become vulnerabilities in your cloud environment. We will compare them based on their features, performance, usability, and compatibility with different IaC frameworks and cloud providers.
Comparing IaC Scan Tools: Video walkthrough
Our setup
Let’s take a look at our setup.
Requirements
- A GitHub account (all the hands-on sections will utilize GitHub’s Codespaces so you won’t need to install anything on your machine)
Repository
TL;DR: You can find the repo here.
What is an IaC scan tool and what is it used for?
Alright, before we dig in, let’s get an understanding of a few concepts.
An IaC scan tool is a software application that analyzes your IaC files and detects security vulnerabilities, misconfigurations, compliance violations and other issues. IaC scan tools improve the quality and security of IaC files before they are deployed to cloud environments. These tools can help developers, DevSecOps and DevOps teams identify and fix potential problems in their code early in the development lifecycle, reducing the risk of potential data breaches, data leaks, downtime and other incidents.
What is Static Code Analysis?
Static code analysis is a method that examines the source code of a program without running it. Static code analysis tools can automate this process and detect possible errors, security vulnerabilities, and code quality issues. Static code analysis can help developers find and fix problems early in the development cycle, before they become more costly and difficult to resolve. Static code analysis can also help ensure that the code meets certain standards and guidelines, for such issues as coding style, performance, or compliance.
How does IaC scanning work?
IaC scanning works by applying a set of rules or policies to the IaC configuration files that check for common security best practices, such as encryption, authentication, authorization, logging, and monitoring. The rules or policies can be based on industry standards, such as CIS benchmarks, or customized to fit the specific needs of the organization. The IaC scanning tools can then generate a report that shows the results of the analysis, such as the number and severity of vulnerabilities found, the location of the vulnerable code, and the recommended remediation steps. The scan report itself can also be integrated with other tools, such as GitLab or GitHub, to provide feedback and guidance to developers in their workflows.
Why do you need IaC security scanning?
Imagine you are building a house and you have a blueprint that shows how everything should look and work. You wouldn't want to start construction without checking the blueprint for errors, right? You might end up with a leaky roof, a crooked wall, or faulty wiring. That's why you need IaC security scanning. It helps you find and fix any issues in your infrastructure as code before you deploy it to the cloud. It's like having a quality assurance team for your blueprint. IaC security scanning can save you time, money, and headaches in the long run.
Which IaC scanning tools exist?
Some of the most popular IaC scanning tools are checkov, tfsec, and terrascan. These tools can help you identify common vulnerabilities and best practices in your IaC code, such as Terraform, CloudFormation, Kubernetes, and more. However, they are not perfect and they may have some limitations or false positives. Here is a brief comparison of these three tools and later we will dig deeper into each one.
- Checkov: A comprehensive tool that supports Terraform, CloudFormation, Kubernetes, Helm, Serverless Framework, and more. It has a rich set of features and integrations, such as pre-commit hooks, GitHub actions, VS Code extension, etc. However, it may be slower and more complex than other tools.
- tfsec: A fast and lightweight tool that supports Terrafor. It has a simple installation process and a nice output format. However, it may not cover all the resources or scenarios that you need.
- Terrascan: A modular tool that supports Terraform, Kubernetes, Helm, Dockerfiles, and more. It has a flexible architecture that allows you to write your own policies using Open Policy Agent (OPA). However, it may have a steeper learning curve and less documentation than other tools.
As you can see, there is no one-size-fits-all solution for IaC scanning. You may need to try different tools and see which one works best for your use case. Or you may need to use a combination of tools to achieve the best results. The important thing is to scan your IaC code regularly and fix any issues that you find before they become a problem.
Which IaC Scanning Tool is the Best?: Comparing Checkov vs tfsec vs Terrascan


In this section of the IaC Scanning Tools Guide, we will be looking at tfsec and discussing the benefits, key features, and looking at some real world examples. You can explore the other parts of this guide below.
Jump to section:
- What is an IaC scan tool?
- What is Checkov?
- What is Terrascan?
- Comparing Checkov vs. tfsec vs. Terrascan
What is tfsec?
tfsec is a security scanner for your Terraform code. It performs static analysis of your code and detects potential misconfigurations that could lead to security risks. It supports multiple cloud providers, such as AWS, Azure, and GCP, and has hundreds of built-in rules. It also allows you to define your own custom rules using Rego policies or JSON/YAML custom policies. You can run tfsec locally or in your CI pipelines, and get developer-friendly output in various formats. tfsec is an open-source project backed by Aqua Security that aims to help you secure code in your IaC.
Benefits and Key Features of using tfsec
Some benefits and key features of using tfsec are:
| Feature | Details |
|---|---|
| Scanning IaC | Yes for security and compliance before deployment |
| IaC Frameworks Supported | Only Terraform |
| Reporting | Detailed reports and recommendations for fixing the detected issues in different formats such as text, JSON, CSV, Checkstyle, JUnit, and SARIF. |
| Integrations | Many tools including GitHub Actions, GitLab CI, and VS Code |
| Policy Customizations | Yes using JSON or YAML |
| Open-source | Yes |
| Example of Issues that can be detected | Insecure use of plain text secrets or hard-coded credentials Misconfigured network access rules or firewall settings Unencrypted data storage or communication Missing or outdated security features or patches Non-compliance with industry standards or regulations |
How to get started with tfsec
How to install tfsec?
There are several ways to install tfsec on your system. You can use a package manager such as brew (for macOS or Linux), choco (for Windows), or scoop (for Windows). You can also download the binary for your system from the releases page on GitHub. Alternatively, you can install tfsec with Go using the command:
go install github.com/aquasecurity/tfsec/cmd/tfsec@latest
If you don't want to install tfsec on your system, you can also run it in a Docker container using the command:
docker run --rm -it -v "$(pwd):/src" aquasec/tfsec /src
If you follow along with our GitHub repo using Codespaces, it will be installed for you.
How to use tfsec?
To use tfsec, you simply need to run it on a directory that contains your Terraform code. For example:
tfsec ./Terraform
By default, tfsec will use a lovely output format that shows the severity, description, location, and resolution of each problem. You can change the output format using the --format flag.
For example:
tfsec ./Terraform --format json
This will output the results in JSON format. You can also use other formats such as csv, checkstyle, junit, sarif, text, markdown, html, and gif.
You can also customize the behavior of tfsec using various flags or a configuration file. For example, you can exclude certain checks using the --exclude flag. You can also enable or disable colors, force exit codes, ignore warnings or errors, set custom paths for modules or policies, and more. For a full list of flags you can run tfsec -h
Example use cases of tfsec
Use case 1: Scan your Terraform code for security issues before applying it
One of the most common use cases of tfsec is to scan your Terraform code for security issues before applying it to your cloud environment. This way, you can catch and fix any problems before they cause any damage or expose any vulnerabilities.
Let’s scan the same folder we scanned with checkov. Run the following commands:
tfsec ./Terraform
This will scan all the Terraform files in the current directory and print out a report of any issues found. For example:


As you can see, tfsec provides a clear and concise output that shows the location, severity, and description of each issue. It also provides a link to the documentation page where you can learn more about the issue and how to fix it.
Use case 2: Scan your Kubernetes manifests
Unfortunately, tfsec does not support scanning Kubernetes manifests. It was built specifically to scan Terraform files.
tfsec Custom Policies
Similar to checkov, you can create custom checks in tfsec either using YAML or JSON or using Rego. Let’s create a check similar to the one we did with checkov. We shouldn’t allow an S3 bucket’s ACL to be public-read when it is tagged with the key Scope and the value of PCI.
Custom checks are defined as JSON files or YAML files which sit in the .tfsec folder in the root check path. Any file with the suffix tfchecks.json or tfchecks.yaml will be parsed and the checks included during the run.
Check the pci_policy_tfchecks.yaml in the .tfsec folder in our repo. Below is the content:
---
checks:
- code: CUS999
description: Make sure S3 bucket ACL is NOT public-read if it has a Scope=PCI tag
impact: We would violate our PCI compliance
resolution: Make sure the ACL is not public-read
requiredTypes:
- resource
requiredLabels:
- aws_s3_bucket
severity: CRITICAL
matchSpec:
action : or
predicateMatchSpec :
- action : notContains
name : tags
value:
Scope: "PCI"
- action : notContains
name : acl
value: public
errorMessage: S3 bucket ACL is public-read with Scope=PCI tag
relatedLinks:
- http://internal.acmecorp.com/standards/aws/tagging.html
Use the normal command to run:
tfsec ./Terraform
And examine the output:

What is tfsec: Benefits, Key Features, and Examples


In this section of the IaC Scanning Tools Guide, we will be looking at Terrascan and discussing the benefits, key features, and looking at some real world examples. You can explore the other parts of this guide below.
Jump to section:
What is Terrascan?
Terrascan is a tool that helps you to scan your Infrastructure as Code for security and compliance policy violations. It supports various IaC languages such as Terraform, Kubernetes, Dockerfile, and more. It also integrates with different cloud platforms such as AWS, Azure, and GCP. Terrascan can detect over 500 policies for best practices and prevent risks before provisioning cloud infrastructure. You can run Terrascan locally or in your CI/CD pipeline to automate the scanning process.
Benefits and Key Features of using Terrascan
Some of the benefits and key features of using Terrascan are:
| Feature | Details |
|---|---|
| Scanning IaC | Yes for security and compliance before deployment |
| IaC Frameworks Supported | Multiple IaC frameworks such as Terraform, Kubernetes, Helm, Kustomize, and more |
| Reporting | Detailed reports and recommendations for fixing the detected issues in different formats such as JSON, YAML, XML, JUnit XML, and SARIF |
| Integrations | Many tools including GitHub, GitLab, Jenkins, Azure DevOps, and more |
| Policy Customizations | Yes using Rego, a declarative language for policy enforcement |
| Open-source | Yes |
| User Interface | CLI interface as well as a REST API and a web UI for easy usage and automation |
How to get started with Terrascan
Installing Terrascan
There are several ways to install Terrascan, depending on your preference and platform. You can download the binary from the GitHub releases page, install it using Homebrew or run it as a Docker image. For example, to install Terrascan on macOS using Homebrew, you can run the following command:
brew install terrascan
To verify that Terrascan is installed correctly, you can run:
terrascan version
You should see the output similar to this:
version: v1.18.1
If you’re following along in our GitHub repo with codespaces, terrascan is already installed for you.
Scanning your IaC code
To scan your IaC code for security issues, you can use the terrascan scan command. By default, Terrascan will scan the current directory for Terraform files and report any violations found. You can also specify the type of IaC using the -i flag, such as -i k8s for Kubernetes or -i dockerfile for Dockerfile.
For example, to scan a single Terraform file, you can run:
terrascan scan -f Terraform/s3.tf
You should see the output similar to this:

As you can see, Terrascan has detected one high-severity violation that indicate that the S3 bucket versioning is recommended for easy recovery from unintended user actions.
Example use cases of Terrascan
Use case 1: Scan Terraform Files
Now let’s scan our same Terraform files using Terrascan. Run the following commands:
terrascan scan -d ./Terraform
Let’s examine the output:


Use case 2: Scanning Kubernetes manifests
Let’s see how terrascan performs when it comes to Kubernetes manifests. Run the following commands:
terrascan scan -d ./Kubernetes -i k8s
And here is the output:



Terrascan Custom Policies
Once again, let’s create a custom policy. We will use Rego with Terrascan to check if an S3 bucket has an ACL that is public-read with a tag Scope=”PCI”.
First, you will need to install the OPA binary. On Linux you can use the following script:
curl -L -o opa https://openpolicyagent.org/downloads/v0.51.0/opa_linux_amd64_static
And on Mac use:
curl -L -o opa curl -L -o opa https://openpolicyagent.org/downloads/v0.51.0/opa_darwin_amd64
Once again, if you are following along with GitHub codespaces, it will already be installed for you.
Now let’s examine the files you will need. You need to files, a .json one where you specify a few attributes of the policy and a .rego file where you define the actual policy.
We’ve included these 2 files in the terrascan_custom_policy folder in our repo under the Terraform folder.
Below is the content of the pci_policy_terrascan.json file:
{
"name": "PCI_S3_PUBLIC_READ",
"file": "pci_policy_terrascan.rego",
"policy_type": "AWS",
"resource_type": "aws_s3_bucket",
"template_args": {
"name": "PCI_S3_PUBLIC_READ",
"prefix": "",
"suffix": ""
},
"severity": "HIGH",
"description": "Make sure S3 bucket ACL is NOT public-read if it has a Scope=PCI tag",
"category": "Identity and Access Management",
"version": 1,
"id": "pci_policy_terrascan"
}
And below is the content of the pci_policy_terrascan.rego file:
package accurics
{{.prefix}}{{.name}}{{.suffix}}[array.id] {
array := input.aws_s3_bucket[_]
array.config.acl == "public-read"
array.config.tags == {"Scope": "PCI"}
}
An easy way to generate the above two files is to use the Terrascan Rego Editor VS Code extension.
Now we’re ready to run our scan, you can use the command below that will do it for us. Notice how we use the --policy-path to point to the directory where our custom rego policies live. The second --policy-path flag points to the general place where terrascan stores all its policies. If you omit the last --policy-path you will only run the scans for the custom policy that we created.
terrascan scan --policy-path ./Terraform/terrascan_custom_policy --policy-path ~/.terrascan/pkg/policies/opa/rego}
Finally, the output will be as shown below:

What is Terrascan: Benefits, Key Features, and Examples


