tfscan — Security Scanner for Terraform Code
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 }}
- This pipeline triggers either on push to master/main branch or on pull request.
- 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"]
}