Enhancing Terraform Deployments with TFLint in GitHub Actions

Infrastructure as Code (IaC) has changed the way we manage and deploy cloud environments.  By combining Terraform with CI/CD tools like GitHub Actions, we can automate infrastructure deployment, ensuring consistency and reliability. But even the most well-designed workflows can benefit from an extra layer of validation. That’s where TFLint, a Terraform linter, comes into play.

In this blog, we’ll dive into how you can enhance your Terraform workflows in GitHub Actions by incorporating TFLint. We’ll explore what TFLint is, why it’s essential, and how to seamlessly integrate it into your deployment pipeline.

Why use TFLint?

TFLint is a tool designed to catch potential issues in your Terraform code before they cause deployment errors. It enforces best practices, detects misconfigurations, and identifies code inconsistencies. Here’s why it’s worth adding to your workflow:

  • You can spot problems like misaligned provider versions or unused variables before they reach production.
  • You can ensure your Terraform code adheres to industry or team-specific standards.
  • It can help prevent failed deployments and reduce debugging efforts.
  • Use custom rules and plugins tailored to your needs.

Incorporating TFLint into your GitHub Actions workflow ensures that every deployment is backed by thorough code checks, saving time and reducing risk.

Integrating TFLint into your workflow

Let’s walk through how to integrate TFLint into a GitHub Actions pipeline that already deploys Terraform.

Prerequisites

  • A GitHub repository with your Terraform configuration files.
  • A .tflint.hcl file to configure TFLint rules.
  • Secrets for accessing your cloud provider (e.g., Azure credentials).

Create your tflint.hcl file
We are going to build on work we did previously in the Terraform with GitHub Actions CI/CD Pipeline blog.  So please check there to see how to build up your GitHub repository and create the relevant Terraform and GitHub files.  And then come back here to build on that and add the TFLint checks. 

The first thing we’re going to do is add the relevant .tflint.hcl file to our GitHub repository. 

Head over to https://www.github.com and browse to the repository where your files are. 

Click on Add file > Create new file

Add new file to GitHub repository

Name the file .tflint.hcl and then paste in the following code:

plugin "azurerm" {
    enabled = true
    version = "0.27.0"
    source  = "github.com/terraform-linters/tflint-ruleset-azurerm"
}

# General Terraform rules
rule "terraform_deprecated_interpolation" {
  enabled = true
}
 
# Disallow variables, data sources, and locals that are declared but never used.
rule "terraform_unused_declarations" {
enabled = true
}
 
# Disallow // comments in favor of #.
rule "terraform_comment_syntax" {
enabled = false
}
 
# Disallow output declarations without description.
rule "terraform_documented_outputs" {
enabled = true
}
 
# Disallow variable declarations without description.
rule "terraform_documented_variables" {
enabled = true
}
 
# Disallow variable declarations without type.
rule "terraform_typed_variables" {
enabled = true
}

# Azure-specific rules

# Additional customisations as needed

Once you’ve pasted in the code, Commit changes

Commit changes to GitHub file

This TFLint configuration file enables the Azure provider plugin to enforce Terraform best practices and custom rules during linting.

It includes general Terraform rules, such as requiring outputs and variables to have descriptions, ensuring variables have types, and checking for deprecated interpolation usage. Azure-specific rules can also be added, but I haven’t defined any in this file yet.

Updating Your GitHub Actions Workflow

The next thing we need to do is modify our GitHub Actions workflow so that it includes the TFlint check using the file we’ve just created. 

Within your repository browse to the .github folder and open your GitHub Actions workflow file. 

Edit it and paste in the following code:

name: Terraform deploy Log Analytics with TFLint checks

on:
  workflow_dispatch:

jobs:
  terraform:
    runs-on: ubuntu-latest
    env:
      ARM_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
      ARM_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}
      ARM_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
      ARM_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
      TF_VAR_client_id: ${{ secrets.AZURE_CLIENT_ID }}
      TF_VAR_client_secret: ${{ secrets.AZURE_CLIENT_SECRET }}
      TF_VAR_subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
      TF_VAR_tenant_id: ${{ secrets.AZURE_TENANT_ID }}
    
    steps:
      - name: Checkout code
        uses: actions/checkout@v4.2.2

      - name: Set up Terraform
        uses: hashicorp/setup-terraform@v2
        with:
          terraform_version: 1.5.5
      
      - name: Cache plugin dir
        uses: actions/cache@v4
        with:
          path: ~/.tflint.d/plugins
          key: ${{ matrix.os }}-tflint-${{ hashFiles('.tflint.hcl') }}
        
      - name: Setup TFLint
        uses: terraform-linters/setup-tflint@v4
        with:
          tflint_version: v0.52.0
    
      - name: Show version
        run: tflint --version

      - name: Init TFLint
        run: tflint --init
        env:
            # https://github.com/terraform-linters/tflint/blob/master/docs/user-guide/plugins.md#avoiding-rate-limiting
          GITHUB_TOKEN: ${{ github.token }}

      - name: Run TFLint
        run: tflint -f compact

      - name: Terraform Init
        run: terraform init

      - name: Terraform Plan
        run: terraform plan   

      - name: Terraform Apply
        if: github.ref == 'refs/heads/main'
        run: terraform apply -auto-approve

Once pasted Commit changes to the file.

Breaking Down the Workflow

Caching TFLint Plugins

The actions/cache step speeds up workflows by caching downloaded TFLint plugins. This is especially useful for large configurations or frequent deployments.

Setting Up TFLint

The terraform-linters/setup-tflint action installs the specified TFLint version, ensuring compatibility with your codebase.

Running TFLint

  • The tflint --init command initialises the plugins specified in .tflint.hcl.
  • The tflint -f compact command runs TFLint, formatting the output for readability.

If TFLint detects any issues, the workflow will fail, prompting you to fix the errors before deployment proceeds.

Terraform steps

After TFLint checks, the workflow continues with the usual Terraform steps (terraform init, terraform plan, and terraform apply).

Run the pipeline

We’ve configured this pipeline to only run when it’s manually triggered. To run it follow these steps:

  • Click on Actions at the top of your repository.
  • Select the pipeline name.
  • Click on Run workflow.
Run GitHub Actions workflow
  • Refresh your browser and you will see the pipeline running and can monitor it. 

Best Practices for TFLint

  • Adjust .tflint.hcl to include rules specific to your project or organisation.
  • Use the latest version to benefit from new features and bug fixes.

Use TFLint alongside tools like Terrascan or Checkov for a comprehensive IaC security strategy.

Conclusion

Integrating TFLint into your Terraform deployment pipeline ensures that your infrastructure code is robust, consistent, and error-free. By catching issues early, TFLint saves time and reduces the risk of costly mistakes in production.

Whether you’re managing simple deployments or complex cloud environments, TFLint is an invaluable addition to your CI/CD workflows. Take the next step in improving your Terraform practices—integrate TFLint today!