TFLint is Terraform linter for detecting errors that can not be detected by terraform plan
Terraform is a great tool for infrastructure as a code. It generates an execution plan, we can rely on this plan to proceed with development. However, this plan does not verify values used in template. For example, following template is invalid configuration (t1.2xlarge is invalid instance type)
resource "aws_instance" "web" {
ami = "ami-b73b63a0"
instance_type = "t1.2xlarge" # invalid type!
tags {
Name = "HelloWorld"
}
}
If you run terraform apply
for this template, it will obviously produce an error. However, terraform plan
can get an execution plan without causing an error. This is often not a desirable result. In order to solve this problem, TFLint validates values used in template.
Download binary built for your architecture from latest releases. After downloading, place the binary on the directory on the PATH. An example of installation by command is as follows.
$ wget https://github.com/wata727/tflint/releases/download/v0.3.5/tflint_darwin_amd64.zip
$ unzip tflint_darwin_amd64.zip
Archive: tflint_darwin_amd64.zip
inflating: tflint
$ mkdir -p /usr/local/tflint/bin
$ export PATH=/usr/local/tflint/bin:$PATH
$ install tflint /usr/local/tflint/bin
$ tflint -v
macOS users can also use Homebrew to install TFLint:
$ brew tap wata727/tflint
$ brew install tflint
We provide Docker images for each version on DockerHub. With docker, you can run TFLint without installing it locally.
$ docker run --rm -v $(pwd):/data --workdir=/data -t wata727/tflint
Try running TFLint under the directory where Terraform is executed. It detect if there is a issue and output the result. For example, run on the previous invalid template.
$ tflint
template.tf
NOTICE:1 "iam_instance_profile" is not specified. If you want to change it, you need to recreate instance. (Only less than Terraform 0.8.8)
ERROR:3 "t1.2xlarge" is invalid instance type.
Result: 2 issues (1 errors , 0 warnings , 1 notices)
Two issues were reported. One is for invalid instance type, the other one is for beat practices about IAM instance profile. If you would like to know more about these issues please check the documentation.
If you want to parse only a specific template, not all templates, you can specify a filename as an argument.
$ tflint template.tf
Please show tflint --help
Usage:
tflint [OPTIONS] [FILE]
Application Options:
-v, --version Print TFLint version
-f, --format=[default|json|checkstyle] Output format (default: default)
-c, --config=FILE Config file name (default: .tflint.hcl)
--ignore-module=SOURCE1,SOURCE2... Ignore module sources
--ignore-rule=RULE1,RULE2... Ignore rule names
--var-file=FILE1,FILE2... Terraform variable file names
--deep Enable deep check mode
--aws-access-key=ACCESS_KEY AWS access key used in deep check mode
--aws-secret-key=SECRET_KEY AWS secret key used in deep check mode
--aws-profile=PROFILE AWS shared credential profile name used in deep check mode
--aws-region=REGION AWS region used in deep check mode
-d, --debug Enable debug mode
--error-with-issues Return error code when issues exist
--fast Ignore slow rules. Currently, ignore only aws_instance_invalid_ami
Help Options:
-h, --help Show this help message
By default, TFLint loads .tflint.hcl
under the current directory. The configuration file is described in HCL, and options available on the command line can be described in advance. Following example:
config {
deep_check = true
aws_credentials = {
access_key = "AWS_ACCESS_KEY"
secret_key = "AWS_SECRET_KEY"
region = "us-east-1"
}
ignore_rule = {
aws_instance_invalid_type = true
aws_instance_previous_type = true
}
ignore_module = {
"github.com/wata727/example-module" = true
}
varfile = ["example1.tfvars", "example2.tfvars"]
}
If you want to create a configuration file with a different name, specify the file name with --config
option.
$ tflint --config other_config.hcl
TFLint supports various credential providers. It is used with the following priority:
- Static credentials
- Shared credentials
- Environment credentials
- Default shared credentials
If you have access key and secret key, you can specify these credentials.
$ tflint --aws-access-key AWS_ACCESS_KEY --aws-secret-key AWS_SECRET_KEY --aws-region us-east-1
config {
aws_credentials = {
access_key = "AWS_ACCESS_KEY"
secret_key = "AWS_SECRET_KEY"
region = "us-east-1"
}
}
If you have shared credentials, you can specify credentials profile name. However TFLint supports only ~/.aws/credentials
as shared credentials location.
$ tflint --aws-profile AWS_PROFILE --aws-region us-east-1
config {
aws_credentials = {
profile = "AWS_PROFILE"
region = "us-east-1"
}
}
TFLint looks AWS_ACCESS_KEY_ID
and AWS_SECRET_ACCESS_KEY
, AWS_REGION
environment values. This is useful when you do not want to explicitly specify credentials.
$ export AWS_ACCESS_KEY_ID=AWS_ACCESS_KEY
$ export AWS_SECRET_ACCESS_KEY=AWS_SECRET_KEY
TFLint can interpret part of interpolation syntax. We now support only variables. So you cannot use attributes of resource, outputs of modules and built-in functions. If you are using them, TFLint ignores it. You can check what is ignored by executing it with --debug
option.
If you use variable files, Please specify it by arguments or configuration file. TFLint interprets variables as well as Terraform. In other words, when variables are conflicting, It will be overridden or merged correctly.
Deep check is an option that you can actually search resources on AWS and check invalid references and duplicate resources. You can activate it by executing it with --deep
option as following:
$ tflint --deep
template.tf
ERROR:3 "t1.2xlarge" is invalid instance type.
ERROR:4 "invalid_profile" is invalid IAM profile name.
Result: 2 issues (2 errors , 0 warnings , 0 notices)
In the above example, an IAM instance profile that does not actually exist is specified, so it is an error. In order to refer to actual resources, AWS credentials are required. You can use command line options, configuration files, environment variables, shared credentials for these specifications.
If you want to build TFLint at your environment, you can build with the following procedure. Go 1.8 or more is required.
$ make build
go get github.com/Masterminds/glide
glide install
[INFO] Downloading dependencies. Please wait...
...
go test $(go list ./... | grep -v vendor | grep -v mock)
...
go build -v
...
github.com/wata727/tflint