The goal of this guide is to quickly understand how TFLint works and to help more developers contribute.
TFLint is just a thin wrapper of Terraform. Configuration loading and expression evaluation etc. depend on Terraform's internal API, and it only provides an interface to do them as linter.
There are three important packages to understand its behavior:
tflint
- This package is the core of TFLint as a wrapper for Terraform. It allows accesses to
terraform/configs.Config
andterraform/terraform.BuiltinEvalContext
and so on.
- This package is the core of TFLint as a wrapper for Terraform. It allows accesses to
rules
- This package is a provider of all rules.
cmd
- This package is the entrypoint of the app.
These processes are described in cmd/cli.go
.
All Terraform's configuration files are represented as configs.Config
. tflint/tflint.Loader
uses the (*configs.Parser) LoadConfigDir
and configs.BuildConfig
to access to configs.Config
in the same way as Terraform.
Similarly, prepare terraform.InputValues
using (*configs.Parser) LoadValuesFile
.
A tflint/tflint.Runner
is initialized for each configs.Config
. These have their own evaluation context for that module, represented as terraform.BuiltinEvalContext
.
it uses (*terraform.BuiltinEvalContext) EvaluateExpr
to evaluate expressions. Unlike Terraform, it provides a mechanism to determine if an expression can be evaluated.
It inspects configs.Config
via tflint.Runner
. All rules implement the Check
method that takes tflint.Runner
as an argument, and emits an issue if needed.
You need Go 1.15 or later to build.
$ make tools
$ make build
You can use the rule generator to add new rules (Currently, this generator supports only AWS rules).
$ go run ./rules/awsrules/generator
Rule name? (e.g. aws_instance_invalid_type): aws_instance_example
Create: rules/awsrules/aws_instance_example.go
Create: rules/awsrules/aws_instance_example_test.go
A template of rules and tests is generated. In order to inspect configuration files, you need to understand the Runner API.
Finally, don't forget to register the created rule with the provider. After that the rule you created is enabled in TFLint.
Some rules are manually maintained, others are automatically generated. You should not edit directly anything that has been generated automatically.
Everything except the ones mentioned later is manually maintained. These can be changed directly.
SDK-based rules are automatically generated from aws-sdk model definitions. For example, the valid regions of the S3 bucket are defined here. Based on this, we can generate a rule that checks whether a valid value is selected.
These definitions are linked to Terraform resource arguments by mapping files. If you update these rules, you should update this mapping instead. The following is an example of a mapping file:
import = "aws-sdk-go/models/apis/ec2/2016-11-15/api-2.json"
mapping "aws_instance" {
instance_type = InstanceType
}
The left is a Terraform argument, and the right is the shape name of the aws-sdk model definition. From this mapping, a rule is automatically generated by the following command:
go generate ./rules/awsrules/model
API-based rules are automatically generated from definition files. An example definition file is shown below:
rule "aws_instance_invalid_iam_profile" {
resource = "aws_instance"
attribute = "iam_instance_profile"
source_action = "ListInstanceProfiles"
template = "\"%s\" is invalid IAM profile name."
}
In this definition file, a rule that checks whether the aws_instance.*.iam_instance_profile
value is included in the return values of source_action
is generated. The rule is generated with go generate
:
go generate rules/awsrules/api
Before commit, please install pre-commit and install pre-commit hooks by running pre-commit install
in root directory of your local checkout.