Terraform is a powerful Infrastructure as Code (IAC) tool that simplifies the process of automating infrastructure tasks across various cloud service providers and custom in-house solutions. With its ability to manage existing and popular cloud providers, it has become a popular choice among DevOps engineers. In this article, we will explore how integrating tools like Tflint, Tfsec, and Checkov into your GitHub Actions workflow can assist you in maintaining clean and efficient Terraform code. By implementing these checks, you can ensure that your Terraform code adheres to best practices, is free of security vulnerabilities, and is ready for deployment to production.

Tflint and Tfsec are open-source tools that can be used to perform automated checks on Terraform code. These tools can be integrated into a GitHub Actions workflow to run checks on Terraform code as part of the CI/CD pipeline.

Step by Step Process

We are first going to create a github actions workflow which will be running terraform checks  using the tools tflint and Tfsec and would run creating resources using Terraform. There will be 3 jobs running in that workflow . The first job will be of Tflint-checks , if Tflint passes then Tfsec-checks job will run and if it passes then Terraform will create AWS resources.

In GitHub Actions, a workflow is a set of one or more jobs that are executed in a specific order. Each job represents a specific task or set of tasks that need to be executed, such as building the code, running tests, deploying to a staging environment, etc.

Jobs are defined in the workflow file, which is typically named “main.yml” and located in the “.github/workflows” directory of the repository. The syntax of the workflow file is in YAML format.

A job is defined by a set of steps that are executed sequentially. Each step is a command or action that is executed in the virtual environment of the job. Steps can be defined using various actions provided by GitHub Actions or by using your own custom actions.

For example, a job can be defined to run terraform plan and terraform apply commands, and another job can be defined to run the tests. The jobs are executed in the order they are defined in the workflow file.

Jobs can also be configured to run in parallel. This allows multiple tasks to be executed simultaneously, which can reduce the overall execution time of the workflow.

To create a workflow, go to Actions in your GitHub Repository and choose a template yml file or click “set up a workflow yourself

Tools

Terraform TfLint — It is a linter that checks possible errors (like invalid instance types) for Major Cloud providers (AWS/Azure/GCP). It also help identify provider-specific issues before errors occur during a Terraform run. It warns you about deprecated syntax, unused declarations and enforce best practices, naming conventions. For example : If you want to create an ec2 instance of instance type as “t2.micro” but accidentally reference an invalid instance type like “t2.micrro” , Tflint will show an error.

To use in AWS Cloud , first create a .tflint.hcl file and install the plugin

plugin “aws” {
enabled = true
version = “0.21.1”
source  = “github.com/terraform-linters/tflint-ruleset-aws”
}

To use in Github Actions — create a workflow

name: Create resources using Terraform

on:
push:
branches:
– main

jobs:

tflint-checks:
runs-on: ubuntu-latest
steps:

# Checkout Repository
– name : Check out Git Repository
uses: actions/checkout@v3

# TFLint – Terraform Check
– uses: actions/cache@v2
name: Cache plugin dir
with:
path: ~/.tflint.d/plugins
key: ${{ matrix.os }}-tflint-${{ hashFiles(‘.tflint.hcl’) }}

– uses: terraform-linters/setup-tflint@v2
name: Setup TFLint
with:
github_token: ${{ secrets.CI_GITHUB_TOKEN }}

# Print TFLint version
– name: Show version
run: tflint –version

# Install plugins
– name: Init TFLint
run: tflint –init

# Run tflint command in each directory recursively
– name: Run TFLint
run: tflint -f compact –recursive –force

 

In this the first step is for cloning the repository and second step we are caching plugin directory for Tflint and setting up the Tflint and in the third step we are seeing the Tflint version and fourth step we are installing the plugins using “tflint — init” and fifth step we are running Tflint commands and giving as a compact output.

We have deliberately added some errors to see the tflint checks. Here we have added wrong instance_type . Instead of “t2.micro” added “t2.micrro”.

Terraform Tfsec — This tool uses static analysis of your terraform code to spot potential security issues. It checks for different misconfigurations across all major (and some minor) cloud providers( GCP,AWS,Azure ) based on hundreds of built-in-rules. It evaluates relationships between Terraform resources and is compatible with the Terraform CDK and supports multiple output formats like lovely (default), JSON, SARIF, CSV, CheckStyle, JUnit, text, Gif. Example: If you are creating security group and if it is open to whole world (0.0.0.0/0) . It will show an error.

To use in Github Actions — create a workflow

tfsec-checks:
runs-on: ubuntu-latest
needs: tflint-checks

steps:
# Checkout Repository
– name : Check out Git Repository
uses: actions/checkout@v2

# Tfsec – Security scanner for your Terraform code
– name: Run Tfsec
uses: aquasecurity/tfsec-action@v1.0.0

The Tfsec-checks job will run only if tflint-checks job. Here, “needs” parameter in GitHub Actions is used to specify the dependencies between jobs in a workflow. This parameter allows you to specify that one job must complete successfully before another job can start.

Here, we are first cloning the repository and then in the second step we are using aquasecurity/tfsec-action@v1.0.0 action to run the Tfsec security checks on Terraform Code.

Added “0.0.0.0/0” in security group

To ignore this error we need to add a syntax in the terraform code :

tfsec:ignore:<rule>

Like in the above error we will be adding this line in terraform code(Security Group) :

#tfsec:ignore:aws-vpc-no-public-ingress-sgr

#tfsec:ignore:aws-ec2-no-public-egress-sgr

resource “aws_security_group” “allow_sg” {
name        = “${var.name}-SG”
description = “Allow tls inbound traffic”

ingress {
description = “SSH from VPC”
from_port   = 22
to_port     = 22
protocol    = “tcp”
cidr_blocks = var.cidr_blocks
}

ingress {
description = “Jfrog Port from VPC”
from_port   = 8082
to_port     = 8082
protocol    = “tcp”
cidr_blocks = var.cidr_blocks
}

ingress {
description = “SonarQube Port from VPC”
from_port   = 9000
to_port     = 9000
protocol    = “tcp”
cidr_blocks = var.cidr_blocks
}

egress {
description      = “TLS from VPC”
from_port        = 0
to_port          = 0
protocol         = “-1”
cidr_blocks      = [“0.0.0.0/0”] #tfsec:ignore:aws-ec2-no-public-egress-sgr
ipv6_cidr_blocks = [“::/0”]
}

tags = {
Name = “${var.name}-SG”,
ENV  = var.ENV
}
}

To get the whole code : Checkout the DevOps Project in Github 

 

Leave a comment

Your email address will not be published. Required fields are marked *