What Is infrastructure As Code (IaC) Scanning?

This article was brought to you by Kumar Harsh, draft.dev.

Infrastructure as code (IaC) is a popular practice in modern DevOps security and automation workflows. By treating infrastructure as code, teams can automate resource provisioning and deployments and significantly reduce efforts spent on manual configurations. 

However, just as with application code, IaC configurations can introduce vulnerabilities and security misconfigurations when not adequately secured. They can even expose sensitive data or provide unintended access to cloud resources.

Misconfigured and unsecured IaC files are a leading cause of cloud security breaches. They’re part of the reason why Gartner says that through 2025, 99 percent of cloud security failures will be the customer’s fault.

To address this proactively, IaC scanning has emerged as a critical security practice. IaC scanning tools detect vulnerabilities, identify risky configurations, and verify compliance early in the development lifecycle—long before any infrastructure goes live.

In this article, you’ll discover why IaC scanning is essential and how it works and explore popular scanning tools like Checkov, Trivy, and Terrascan. You’ll also see how TeamCity simplifies integrating IaC scanning into your automated pipelines by providing built-in mechanisms to ensure your infrastructure remains secure and compliant from code to cloud.

TL;DR

  • What is IaC scanning?
    Infrastructure as Code (IaC) scanning is the process of statically analyzing infrastructure configuration files (like Terraform, CloudFormation, Kubernetes manifests) to detect misconfigurations, security vulnerabilities, and policy violations before they are deployed.
  • Why does it matter?
    IaC scanning helps catch issues early in the development pipeline, ensuring secure cloud infrastructure, preventing breaches, and supporting compliance with standards like SOC 2, ISO 27001, and NIST.
  • How does TeamCity support it?
    TeamCity allows seamless integration of IaC scanning tools into your CI/CD workflows. You can:
    • Add build steps for tools like Trivy or Checkov
    • Configure failure conditions based on scan results
    • Manage pipeline logic with Kotlin DSL
    • Use the TeamCity Terraform Provider for full infrastructure-as-code CI/CD configuration
  • Which tools are covered?
    This article explores three leading open-source IaC scanning tools:
    • Checkov (Bridgecrew / Palo Alto Networks)
    • Trivy (Aqua Security)
    • Terrascan (Tenable / Accurics)

Why IaC scanning is important

As teams adopt IaC tools to automate provisioning, infrastructure definitions become as critical as application code. However, they often receive far less scrutiny. IaC allows developers to spin up complex cloud environments with a few lines of code, but small mistakes in these configurations can lead to outsized consequences.

Common IaC security issues include hard-coded secrets, overly permissive IAM roles, and unencrypted storage buckets, each capable of exposing your organization to breaches, data loss, or compliance violations. If left unchecked, these misconfigurations can quietly propagate across environments.

IaC scanning tools are foundational to IaC security practices, helping catch these risk points early in the production lifecycle. By analyzing your Terraform, CloudFormation, or Kubernetes manifests before deployment, scanning tools help you catch vulnerabilities and ensure adherence to organizational and regulatory standards like SOC 2, ISO 27001, and NIST.

How IaC works

IaC tools use static analysis, meaning they inspect the code directly without executing it, to identify configuration risks early in the lifecycle. Many scanners operate using a policy-as-code approach, where best practices and compliance requirements are defined as machine-readable rules.

For example, a policy might require that all storage buckets be encrypted or that no security group exposes port 22 to the public internet.

Tools like Checkov, Trivy, and Terrascan each offer extensive built-in policies for security, code compliance, and operational best practices. These rule sets can be extended or customized to match the standards your organization needs to follow (such as SOC 2, ISO 27001, or NIST).

The real value of these tools emerges when they’re embedded into your development workflow, especially your CI/CD pipelines. Instead of relying on ad hoc reviews or post-deployment audits, every commit or pull request can automatically trigger a scan.

Unsafe changes can be flagged or blocked entirely before they reach production. Developers receive fast, actionable feedback, and platform teams can enforce security and compliance at scale without slowing down releases.

This approach is often referred to as “shifting security left,” meaning moving checks earlier in the software delivery process. By catching issues during development rather than after deployment, teams reduce remediation costs, avoid downtime, and build infrastructure that’s secure by default.

Choosing an IaC scanning tool

Now that you understand what IaC scanning is and how it works, it’s time to choose a tool for your use case. Before you start looking at your options, here are five factors to keep in mind when evaluating these tools:

  • IaC framework support: Ensure your selected tool aligns with your chosen IaC platform (Terraform, Kubernetes, CloudFormation, etc.).
  • Customizability and policy enforcement: Look for tools with robust, extensible policy-as-code capabilities that allow tailored compliance enforcement.
  • CI/CD integration: Verify ease of integration with your CI/CD pipeline (such as TeamCity) to ensure smooth automation and clear feedback to developers.
  • Speed and performance: Pick a tool optimized for fast scanning to avoid slowing down your development process.
  • Community and ecosystem: Consider tools backed by active communities that provide consistent updates, rich documentation, and responsive support.

Let’s now take a closer look at three popular tools that have gained significant traction within the IaC community.

IaC scanning tools comparison

FeatureCheckovTrivyTerrascan
Supported platformsTerraform, CloudFormation, Azure ARM, Kubernetes, Helm, ServerlessTerraform, Kubernetes, CloudFormation, Docker, Helm, YAML, JSONTerraform, Kubernetes, CloudFormation, Azure ARM, Dockerfile, Helm
Policy customizationPython/YAML-based custom rules; 750+ built-inCustom rules supported; broad coverage inherited from tfsecRego (OPA) based policies; 500+ built-in; highly extensible
TeamCity integrationEasy via script steps or Docker; CI-friendly output formatsVery easy; single-line install, fast scan, great for pipelinesModerate; supports JSON/XML output for build parsing
Reporting formatsCLI output, JSON, JUnit, SARIF, GitHub PR commentsCLI, JSON, JUnit, GitHub annotations, SBOMJSON, JUnit XML, SARIF, file output formats

Notes:

  • Checkov is the most mature for multi-framework support and compliance presets.
  • Trivy is extremely lightweight and ideal for Terraform-first or speed-focused pipelines.
    Terrascan stands out for enterprise policy control via OPA/Rego, but may require more setup.

Here’s a detailed description of each tool.

Checkov (by Bridgecrew)

Checkov is an open source tool from Bridgecrew (part of Palo Alto Networks) that supports an impressive array of IaC frameworks, such as Terraform, CloudFormation, Azure Resource Manager, Kubernetes, Helm, and Serverless Framework.

Checkov provides over 750 built-in policies covering security best practices. Its extensible framework also allows custom policy creation using Python or YAML, making it a flexible choice for teams with specific regulatory requirements.

You can integrate Checkov easily with popular CI/CD platforms like GitHub Actions, GitLab CI, Jenkins, and more to get concise, actionable feedback directly within build results. This can help you remediate issues swiftly and confidently.

Its robust reporting capabilities and compatibility with popular CI tools, including TeamCity, make Checkov a widely used, versatile choice.

Trivy (by Aqua Security)

Trivy (the successor of tfsec) is a fast, developer-friendly IaC scanning tool from Aqua Security that has great support for Terraform projects.

tfsec was designed with speed and usability in mind. It could parse Terraform code directly, quickly identifying common security vulnerabilities like unencrypted resources, overly permissive IAM policies, or potential network exposure.

Trivy retains all that, along with access to more languages and features in the same tool, as well as additional integrations with external tools and services.

Trivy offers support for IaC scanning in a wide range of configurations, including Kubernetes, Docker, Terraform, CloudFormation, Azure ARM templates, Helm, YAML, and JSON. Trivy is straightforward to install and use in continuous integration workflows. This makes it easy to integrate with TeamCity and other CI/CD tools for clear and actionable insights within pipeline outputs.

Just like Checkov, Trivy includes a comprehensive library of prebuilt security checks and also supports custom rule definitions. This flexibility, combined with exceptional ease of use, has earned tfsec and Trivy widespread popularity among Terraform-centric development teams.

Terrascan (by Accurics/Tenable)

Terrascan is another leading open source IaC scanning tool, developed by Accurics (now part of Tenable). It supports multiple IaC frameworks—including Terraform, Kubernetes, AWS CloudFormation, Helm, Dockerfile, and Azure ARM templates—making it ideal for teams managing multicloud or hybrid infrastructure.

Terrascan adopts a policy-as-code approach powered by Rego, Open Policy Agent’s policy language. This allows teams to easily create detailed, custom code compliance rules aligned with security standards like CIS Benchmarks, NIST SP 800-53, PCI DSS, and SOC 2.

This is in addition to the 500 policies it ships with out of the box. Terrascan is well-suited for organizations with complex compliance and policy enforcement requirements.

The use of the flexible Open Policy Agent framework differentiates Terrascan from other tools in the list. Integration into CI/CD pipelines is seamless as well; Terrascan easily exports results in formats such as JUnit XML or JSON, streamlining integrations with tools like TeamCity.

Using TeamCity for IaC scanning

Once you’ve selected an IaC scanning tool, the next step is to operationalize it within your CI/CD pipeline. That’s where TeamCity comes in.

As a powerful on-premise CI/CD solution, TeamCity allows you to automate your software and infrastructure deployments. TeamCity supports embedding IaC scanning seamlessly into its pipelines, enhancing security and compliance without compromising productivity.

This section explores how you can leverage TeamCity On-Premises to integrate popular IaC scanning tools (such as Checkov, Trivy, or Terrascan) into your build pipelines. We’ll demonstrate how you can set up automated scanning steps, define automatic failure conditions, and ensure secure infrastructure deployments by managing everything as code.

💡Read also: Configuration as Code for TeamCity Using Terraform

Automating infrastructure deployments with TeamCity pipelines

TeamCity pipelines are defined through intuitive build configurations and enable easy orchestration of infrastructure automation tasks, such as Terraform plans and applys, Kubernetes deployments, or CloudFormation stack creations.

To start scanning your IaC definitions, you’d first need a working build pipeline set up in TeamCity. Typically, this involves cloning your repository containing IaC files and configuring TeamCity build steps to validate, plan, and deploy infrastructure.

You can use this example repository if you want to follow along. This repo contains an example Terraform setup that’s used to create an app_server resource in an AWS platform and print its ID and public IP when done.

The pipeline consists of four steps:

  1. “Install Terraform,” which follows the instructions from the Terraform Linux docs to install it.
  2. “Initialize Terraform,” which runs terraform init -input=false.
  3. “Plan Terraform changes,” which runs terraform plan -input=false -compact-warnings -out=plan.file.
  4. “Apply Terraform changes,” which runs terraform apply -input=false -compact-warnings plan.file.

You’ll also need to add two environment variables to your build configuration: env.AWS_ACCESS_KEY_ID (with your AWS access key ID value) and env.AWS_SECRET_ACCESS_KEY (with your AWS secret access key value).

NB:This tutorial uses the AWS access key and secret to connect to AWS for simplicity. However, TeamCity provides a dedicated connection to Amazon Web Services to help you better manage your AWS credentials. It’s always recommended to take a few extra moments to set it up, particularly through IAM roles, for enhanced security and ease of use.

Here’s what a pipeline’s build logs will look like when it’s successfully set up:

Example pipeline

Running IaC scanning tools as part of the build process

Integrating IaC scanning into your TeamCity pipeline is straightforward. After your code is cloned, you can add a dedicated build step for the scanner of your choice. Let’s use Trivy as an example.

You can use the following custom script to Trivy and output any issues detected with your Terraform configuration:

wget https://github.com/aquasecurity/trivy/releases/download/v0.61.0/trivy_0.61.0_Linux-64bit.deb
sudo dpkg -i trivy_0.61.0_Linux-64bit.deb

trivy config .

You would need to add this step before the final Apply Terraform changes step in your pipeline:

Order of steps in the pipeline

The principle is identical regardless of the tool you select: install it first, then configure it to run within a build step that suits your workflow.

Here’s what the output logs will look like when the tool detects any issues:

Trivy output logs

Configuring automatic failure conditions for security misconfigurations

To reinforce security, you can configure automatic failure conditions within TeamCity. These conditions will stop pipeline execution immediately if your IaC scans detect critical or high-priority issues, ensuring misconfigurations never reach production.

Let’s look at how you’d configure such a condition using Trivy.In your build configuration settings, navigate to the Failure Conditions tab:

Navigating to the Failure Conditions tab

Click the Add failure condition button to add a condition that fails the build if the output log from the IaC scanner does not contain the text Failures: 0:

Creating a new failure condition

This will only happen when Trivy catches and displays any policy failures in the output logs. You can try out other conditions as well. You can test the condition on one of your recent builds by clicking the Test on finished build button in the dialog box:

Testing the failure condition

Managing server settings with Kotlin DSL

One significant benefit of using TeamCity is its support for storing server and build configurations as code via the Kotlin Domain-Specific Language (Kotlin DSL). With Kotlin DSL, you can version-control your entire CI/CD setup alongside your IaC definitions to enhance auditability and transparency.

Your IaC scanning steps, build pipeline settings, and even failure conditions can be declared in Kotlin DSL scripts. For example, here’s what the pipeline you’ve built so far would look like:

package _Self.buildTypes

import jetbrains.buildServer.configs.kotlin.*
import jetbrains.buildServer.configs.kotlin.buildFeatures.perfmon
import jetbrains.buildServer.configs.kotlin.buildSteps.script
import jetbrains.buildServer.configs.kotlin.failureConditions.BuildFailureOnText
import jetbrains.buildServer.configs.kotlin.failureConditions.failOnText
import jetbrains.buildServer.configs.kotlin.triggers.vcs

object Build : BuildType({
    name = "Build"

    params {
        text("env.AWS_SECRET_ACCESS_KEY", "MXXXXXXXXXXXXXXXXXXXXXXXXXXXc", display = ParameterDisplay.HIDDEN, allowEmpty = true)
        text("env.AWS_ACCESS_KEY_ID", "AXXXXXXXXXXXXXXXXO", display = ParameterDisplay.HIDDEN, allowEmpty = true)
    }

    vcs {
        root(HttpsGithubComKrharsh17teamcityTerraformScanRefsHeadsMain)
    }

    steps {
        script {
            name = "Install Terraform"
            id = "Install_Terraform"
            scriptContent = """
                sudo apt-get update && sudo apt-get install -y gnupg software-properties-common
                
                wget -O- https://apt.releases.hashicorp.com/gpg | \
                gpg --dearmor | \
                sudo tee /usr/share/keyrings/hashicorp-archive-keyring.gpg > /dev/null
                
                gpg --no-default-keyring \
                --keyring /usr/share/keyrings/hashicorp-archive-keyring.gpg \
                --fingerprint
                
                echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] \
                https://apt.releases.hashicorp.com ${'$'}(lsb_release -cs) main" | \
                sudo tee /etc/apt/sources.list.d/hashicorp.list
                
                sudo apt update
                
                sudo apt-get install terraform
                
                terraform -help plan
            """.trimIndent()
        }
        script {
            name = "Initialize Terraform"
            id = "Initialize_Terraform"
            scriptContent = "terraform init -input=false"
        }
        script {
            name = "Plan Terraform changes"
            id = "Plan_Terraform_changes"
            scriptContent = "terraform plan -input=false -compact-warnings -out=plan.file"
        }
        script {
            name = "Scan Terraform configs"
            id = "Scan_Terraform_configs"
            scriptContent = """
                wget https://github.com/aquasecurity/trivy/releases/download/v0.61.0/trivy_0.61.0_Linux-64bit.deb
                sudo dpkg -i trivy_0.61.0_Linux-64bit.deb
                
                trivy config .
            """.trimIndent()
        }
        script {
            name = "Apply Terraform changes"
            id = "Apply_Terraform_changes"
            scriptContent = "terraform apply -input=false -compact-warnings plan.file"
        }
    }

    triggers {
        vcs {
        }
    }

    failureConditions {
        failOnText {
            conditionType = BuildFailureOnText.ConditionType.CONTAINS
            pattern = "Failures: 0"
            failureMessage = "Please check and fix IaC scan errors."
            reverse = true
            stopBuildOnFailure = true
        }
    }

    features {
        perfmon {
        }
    }
})

You can access the DSL code of any TeamCity build configuration in the TeamCity UI by clicking the View as code button on the top-right area of the build configurations page:

Accessing the DSL code for a pipeline

TeamCity’s Terraform Provider

Kotlin DSL gives you fine-grained control over build configuration and makes versioning pipelines easy, but it’s primarily scoped to individual project-level configurations. So, what if you need to automate the TeamCity platform itself to set up new projects, VCS roots, build templates, or common pipeline structures across teams and environments?

The TeamCity Terraform Provider allows platform and infrastructure teams to define and manage their CI/CD setup as code.

With the Terraform Provider, your entire TeamCity configuration becomes version-controlled and declarative. You can provision new build projects, VCS roots, build templates, and parameterized pipelines using standard Terraform modules, just like any other infrastructure component.

This dramatically reduces the friction of onboarding new teams, duplicating pipelines, and managing consistency across multiple environments. It can also come in handy when spinning up test environments, standardizing pipelines across teams, or rolling out policy-enforced IaC workflows.

For example, rather than clicking through the UI to replicate a common pipeline pattern across projects, teams can write reusable Terraform modules that define standardized CI/CD pipelines—complete with secure parameters, failure conditions, and artifact dependencies.

These modules can then be reviewed (both through IaC scanning tools and by manual reviewers), approved, and rolled out through pull requests, giving platform teams full control over the CI/CD infrastructure lifecycle.

This approach works especially well for teams managing large environments across multiple repos and/or products. It enables drift detection, automated rollback, and easier collaboration across infrastructure and DevOps teams.

By defining your TeamCity configuration in Terraform, you also gain the benefits of automated audits, consistent formatting, and change history tracking—without sacrificing TeamCity’s powerful build capabilities.

Getting started with the provider is straightforward. There are a bunch of examples to help you along the way as well. Here’s a quick video to give you a walkthrough of how it works.

Best practices for secure IaC workflows

Securing your IaC workflows requires a shift-left mindset—embedding security checks early and often. Here are some best practices you could follow to implement that:

  • Scan during development, not just deployment: Integrate IaC scanning tools like Checkov or Terrascan into your IDE or pre-commit hooks to catch misconfigurations before they reach your repository.
  • Make scanning a required CI/CD step: Ensure your pipelines enforce IaC scans. Tools like TeamCity allow you to block builds based on scan results, helping prevent insecure changes from being deployed.
  • Combine scanning with manual code reviews: Pair automated scans with peer reviews to maintain accountability and encourage shared understanding of infrastructure decisions.
  • Use version control for everything: Store both IaC files and CI/CD configurations (such as using Kotlin DSL or the Terraform Provider with TeamCity) in version control for traceability and quick rollback if needed.
  • Treat security policies as code: Define and manage security rules using policy-as-code tools. Keep these policies updated to align with frameworks like SOC 2, ISO 27001, or NIST.
  • Automate and centralize security checks: Reduce manual overhead by automating policy enforcement and storing all infrastructure definitions and rules in version-controlled repositories.

Conclusion

Infrastructure as code has changed how teams provision and manage infrastructure, but with that power comes the responsibility to secure every line of code that defines your environment. IaC scanning ensures that misconfigurations, vulnerabilities, and compliance gaps are caught early, well before they reach production.

By integrating tools like Checkov, Trivy, and Terrascan directly into your CI/CD workflows, you can build a continuous feedback loop that reinforces security best practices without slowing down delivery.

With TeamCity, this integration becomes even more seamless. You can run scans as part of your build process, configure automated failure conditions, and manage everything—from pipeline definitions to infrastructure policies—as code.

Ready to secure your infrastructure? Try integrating IaC scanning with TeamCity today and take the first step toward safer, smarter deployments.

image description