Secure GitOps with GitLab CI/CD, Terraform & TFSec End-to-End IaC Security


Typically, after writing a Terraform script, you would manually run terraform apply
in the terminal to deploy your resources. However, GitOps simplifies this process. By integrating your version control system ike GitHub, GitLab, or Bitbucket. now you can automate deployments with a simple git push
. This triggers your Terraform pipeline to provision infrastructure automatically. In this project, we'll be using GitLab to demonstrate the GitOps workflow.
Objectives
- Automate Infrastructure Deployment with GitLab and Terraform
Requirements
Gitlab Account
Terraform
AWS Account
For this tutorial we have already prepared a terraform script that provisions AWS ec2 instance and install some applications like jenkins and sonarqube. You can clone it from here.
To create resources in AWS using terraform we need to configure access and secret key with admin full access. If you have not configured this before ๐ Check out my detailed guide: Mastering IAM in AWS.
After cloning this repo https://gitlab.com/devsecops-projects2/gitops-with-terraform.then we need cd into the folder
cd gitops-with-terraform
Open terraform.tvars and change the private_key to an already existing key in your aws account.
Create a file and name it gitlab-ci.ymal
- The next step is to define stages inside the gitlab-ci.yml
stages:
- init
- test
- build
- deploy
- Pull terraform hashicorp images
image:
name: hashicorp/terraform:latest
entrypoint: [""]
- Define variables (You need to setup the variables inside github variables)
variables:
AWS_DEFAULT_REGION: "us-east-1"
AWS_ACCESS_KEY_ID: $AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY: $AWS_SECRET_ACCESS_KEY
TF_VAR_env_prefix: "dev"
TF_VAR_runner_registration_token: $RUNNER_TOKEN
- initialize terraform
init:
stage: init
script:
- echo "Initializing Terraform..."
- terraform init
artifacts:
paths:
- .terraform
- .terraform.lock.hcl
- Validate your terraform script
validate:
stage: test
script:
- echo "Validating Terraform..."
- terraform validate
allow_failure: true
- implement tfsec
tfsec:
stage: test
image:
name: aquasec/tfsec
entrypoint: [""]
script:
- tfsec .
allow_failure: true
artifacts:
when: always
paths:
- tfsec-report.json
reports:
codequality: tfsec-report.json
- Review resources to be deployed
build:
stage: build
script:
- echo "Terraform plan..."
- terraform plan -out "planfile"
artifacts:
paths:
- planfile
- Deploy application
deploy:
stage: deploy
script:
- echo "Terraform deploy..."
- terraform apply input=false "planfile"
- Putting everything together
stages:
- init
- test
- build
- deploy
image:
name: hashicorp/terraform:latest
entrypoint: [""]
variables:
AWS_DEFAULT_REGION: "us-east-1"
AWS_ACCESS_KEY_ID: $AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY: $AWS_SECRET_ACCESS_KEY
TF_VAR_env_prefix: "dev"
TF_VAR_runner_registration_token: $RUNNER_TOKEN
init:
stage: init
script:
- echo "Initializing Terraform..."
- terraform init
artifacts:
paths:
- .terraform
- .terraform.lock.hcl
validate:
stage: test
script:
- echo "Validating Terraform..."
- terraform validate
allow_failure: true
tfsec:
stage: test
image:
name: aquasec/tfsec
entrypoint: [""]
script:
- tfsec .
allow_failure: true
artifacts:
when: always
paths:
- tfsec-report.json
reports:
codequality: tfsec-report.json
build:
stage: build
script:
- echo "Terraform plan..."
- terraform plan -out "planfile"
artifacts:
paths:
- planfile
deploy:
stage: deploy
script:
- echo "Terraform deploy..."
- terraform apply input=false "planfile"
then do git add, git commit and git push
You pipeline suppose look like this if everything is successful
if we click on tfsec. We will see something like this
You can see the state of the terraform script. critical issues is 13. and other issues as well.
If we click on build. We will see something like this
In other to deploy the resources. you need to click on the play button of the deploy panel.
After deployment is complete and you click on deploy you should see something like this
You can copy the public ip address and paste with port number 8080 and you will see jenkins like this
- To destroy or delete the instance click on play beside the destroy
Subscribe to my newsletter
Read articles from Oshaba Samson directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Oshaba Samson
Oshaba Samson
I am a software developer with 5 years + experience. I have working on web apps ecommerce, e-learning, hrm web applications and many others