tfscan — Security Scanner for Terraform Code

Manish Sharma
6 min readMay 5, 2023

tfsec is an Aqua Security open source project.

As more and more teams are using infrastructure as code to ensure they have consistent, repeatable deployment of infrastructure, it is becoming increasingly important to guard against mis-configurations creeping into the release.

tfsec uses static analysis of your terraform code to find potential misconfigurations. It scan .tf and .tf.json files to guard against misconfigurations.

tfsec takes a developer-first approach to scanning your Terraform templates; using static analysis and deep integration with the official HCL parser it ensures that security issues can be detected before your infrastructure changes take effect.

It’s easy to integrate into a CI pipeline to implement shift-left approach and catch issues early. Example output,

Tfsec Features

  • Checks for misconfigurations across all major (and some minor) cloud providers
  • Hundreds of built-in rules
  • Scans modules (local and remote)
  • Evaluates HCL expressions as well as literal values
  • Evaluates Terraform functions e.g. concat()
  • Evaluates relationships between Terraform resources
  • Compatible with the Terraform CDK
  • Applies user-defined Rego policies
  • Supports multiple output formats: lovely (default), JSON, SARIF, CSV, CheckStyle, JUnit, text, Gif.
  • Configurable (via CLI flags and/or config file)
  • Very fast, capable of quickly scanning huge repositories
  • Plugins for popular IDEs available (JetBrains, VSCode and Vim)
  • Community-driven

Installation

  • MacOS
$ brew install coreutils
$ curl -s https://raw.githubusercontent.com/aquasecurity/tfsec/master/scripts/install_linux.sh -o tfsec_install.sh
$ sh tfsec_install.sh
  • Install using Go Lang
$ go install github.com/aquasecurity/tfsec/cmd/tfsec@latest

Run Tfsec

  • As CLI Tool

The easiest way to run tfsec is to run it in the directory you want to scan. tfsec will traverse the directory till it finds a valid Terraform file, or If you want to run on a specific location, this can be passed as an argument.

$ tfsec .
OR
$ tfsec /src/tf/dev

The exit status will be non-zero if tfsec finds problems, otherwise the exit status will be zero.

  • With Docker

As an alternative to installing and running tfsec on your system, you may run tfsec in a Docker container.

$ docker run --rm -it -v "$(pwd):/src" aquasec/tfsec /src
  • In CI Pipeline

tfsec can be added to any CI pipeline as a command with the exit code dictating if it breaks the build.

Example: GitHub Actions CI pipeline

name: tfsec
on:
push:
branches:
- main
jobs:
tfsec:
name: tfsec sarif report
runs-on: ubuntu-latest

steps:
- name: Clone repo
uses: actions/checkout@main

- name: tfsec
uses: tfsec/tfsec-sarif-action@master
with:
sarif_file: tfsec.sarif

- name: Upload SARIF file
uses: github/codeql-action/upload-sarif@v1
with:
# Path to SARIF file relative to the root of the repository
sarif_file: tfsec.sarif

name: tfsec-pr-commenter
on:
pull_request:
jobs:
tfsec-pr-commenter:
name: tfsec PR commenter
runs-on: ubuntu-latest

steps:
- name: Clone repo
uses: actions/checkout@master

- name: tfsec
uses: tfsec/tfsec-pr-commenter-action@main
with:
github_token: ${{ secrets.GITHUB_TOKEN }}

  1. This pipeline triggers either on push to master/main branch or on pull request.
  2. Push request triggered pipeline job create a new ubuntu github action container and checking out the code for the push to master/main.

2. Once the code has been checked out, tfsec with process everything in the local path and generate a sarif report.

3. Finally, the sarif report will be uploaded and the Security tab updated with the identified checks.

4. On each pull request and subsequent commit, tfsec will run and add comments to the PR where tfsec has failed.

Tfsec Config File

The tfsec config file is a file in the .tfsec folder in the root path named config.json or config.yml and is automatically loaded if it exists.

This config file can also be set with the --config-file option

$ tfsec --config-file tfsec.yml

Config files can be downloaded from remote locations using the --config-file-url

$ tfsec --config-file-url <http-url> .
example: tfsec --config-file-url https://github.com/tfsecconfig/config.json .

Provided tfsec config file can override various tfsec configurations.

Syntax and Overrides in Tfsec Config file

By default, every severity is reported, but you can specify the minimum severity of result that should be reported. Possible values: CRITICAL, HIGH, MEDIUM, LOW.

# JSON
{
"minimum_severity": "MEDIUM"
}

# YAML
---
minimum_severity: MEDIUM

There are occasions where the default severity level for one of the built in checks is too severe or in some cases not strong enough. The config file can be used to override severity for any checks,

# JSON
{
"severity_overrides": {
"CUS002": "ERROR",
"aws-s3-enable-versioning": "LOW"
}
}

#YAML
---
severity_overrides:
CUS002: ERROR
aws-s3-enable-versioning: LOW

In some situations you may want to only scan for a subset of the checks — this may be the case if newly added checks need to be evaluated before adding to the CI.

# JSON
{
"include": ["CUS002", "aws-s3-enable-versioning"]
}

# YAML
---
include:
- CUS002
- aws-s3-enable-versioning

In some situations you may want to exclude few checks,

#JSON 
{
"exclude": ["CUS002", "aws-s3-enable-versioning"]
}

# YAML
---
exclude:
- CUS002
- aws-s3-enable-versioning

For your CI you might want to pull a config file into all of your build processes with a centrally managed config file. If this is the case, you might also want to require a minimum tfsec version to be used.

# JSON
{
"min_required_version": "v1.1.2"
}

# yaml

---
min_required_version: v1.1.2

Ignoring Tfsec Checks

You may wish to ignore some issues. To do so, you can simply add a comment containing tfsec:ignore:<rule> to the offending line in your templates.

resource "aws_security_group_rule" "my-rule" {
type = "ingress"
#tfsec:ignore:aws-vpc-no-public-ingress-sgr
cidr_blocks = ["0.0.0.0/0"]
}

You can ignore multiple rules by concatenating the rules on a single line

#tfsec:ignore:aws-s3-enable-bucket-encryption tfsec:ignore:aws-s3-enable-bucket-logging
resource "aws_s3_bucket" "my-bucket" {
bucket = "foobar"
acl = "private"
}

Issues within third-party modules cannot be ignored with the above method, as you might not have access to modify the module source code.

#tfsec:ignore:AWS052:exp:2022-01-01
module "db" {
source = "terraform-aws-modules/rds/aws"
...

This is a useful feature when you want to ensure ignored issue won’t be forgotten and should be revisited in the future.

#tfsec:ignore:aws-s3-enable-bucket-encryption:exp:2022-01-02
resource "aws_s3_bucket" "my-bucket" {
bucket = "foobar"
acl = "private"
}

If you add the ws: declaration to your ignore it will only be honoured for that workspace.

# tfsec:ignore:AWS006:exp:2221-01-02 #tfsec:ignore:AWS018:ws:development
resource "aws_security_group_rule" "my-rule" {
type = "ingress"

cidr_blocks = ["0.0.0.0/0"]
}

# when tfsec is run with the --workspace flag set to development, this ignore
# will be honoured, but otherwise will be disregarded.
$ tfsec --workspaces development .

Ignoring based on the value that has been provided. This is particularly relevant when using for_each and you want to allow certain values.

locals {
rules = {
http = 80
https = 443
}
}

#tfsec:ignore:aws-vpc-no-public-ingress-sgr[from_port=443]
resource "aws_security_group_rule" "this" {
for_each = local.rules
type = "ingress"
description = "test"
from_port = each.value
to_port = each.value
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]

}

How Tfsec Works

Install Tfsec Visual Studio Code Plugin

--

--

Manish Sharma

I am technology geek & keep pushing myself to learn new skills. I am AWS Solution Architect — Associate, Professional & Terraform Associate Developer certified.