Published on

Step-by-step Guide to Setting up Atlantis with Gitlab

Authors

Introduction

In our previous post, we explored the powerful features of Atlantis and how it automates Terraform. Now, it's time to get hands-on and set up Atlantis with GitLab. This tutorial will walk you through the entire process, from installation to configuration, ensuring you can leverage Atlantis for your Terraform projects seamlessly.

Prerequisites

Before we begin, make sure you have the following prerequisites:

  1. A GitLab account with access to a repository.
  2. A Kubernetes cluster to host Atlantis.
  3. Basic knowledge of Terraform.

If you want to follow along and need a Kubernetes cluster, you can check out this post that shows you how to run a local Kubernetes cluster using KinD.

Step 1: Gitlab Integration for Atlantis

Before we can deploy Atlantis, we first need to configure two things for our Gitlab integration:

  1. Gitlab Access Credentials: We need to grant Atlantis access to the Gitlab API.
  2. Webhook Secrets: Atlantis uses webhooks and the secret is being used for validation.

Gitlab Access Credentials

First, we need to create an access token for Atlantis that will be stored in a Kubernetes secret. For more information on this, you can follow Atlantis Documentation on this topic.

From Gitlab, on the left side, select your profile and select "Preferences":

atlantis-gitlab-preferences

Then select "Access Tokens":

atlantis-gitlab-access-tokens

From the "Personal Access Tokens" page, you can select "Add new token" on the right hand side to create a new access token:

atlantis-gitlab-create-access-token

Provide a name for your access token. If you want your token to expire after some time, you can provide the date of expiry and select the api scope, which will provide read and write access to the Gitlab API.

Then, select "Create personal access token". The token value will be provided to you on the top of the screen where you can copy the value, as we will need it in the next step.

Create a file named /tmp/gitlab_token and store the token value in there. We will create a Kubernetes secret from this file later.

echo -n 'glpat-xx-example' > /tmp/gitlab_token

Atlantis Webhook Secret

Webhooks are used by Atlantis to validate that the webhooks being received are actually from the legitimate source.

Generate a random string and output the value to /tmp/gitlab_secret where we will use it later to create the Kubernetes secret from:

echo -n $(openssl rand -hex 32) > /tmp/gitlab_secret

Kubernetes Secret

In our Atlantis deployment, we will reference a secret called atlantis-vcs, which will contain the gitlab-token and gitlab-webhook-secret.

We will now create this secret from the two files that we have defined earlier. First we need to create the namespace:

kubectl create namespace atlantis

Now that we have our Atlantis namespace, we can create the secret inside the namespace:

kubectl create secret generic atlantis-vcs \
  --namespace atlantis \
  --from-file=/tmp/gitlab_token \
  --from-file=/tmp/gitlab_secret

Now that we have created our Kubernetes secret, we can continue to deploy Atlantis.

Step 2: Install Atlantis

Atlantis supports other methods to deploy Atlantis, which you can find in their documentation. In this tutorial we will be using Helm to deploy our Atlantis release.

I will be deploying version 5.4.2, but in the future you can follow their releases page to get the most up to date version.

First we want to add the Atlantis helm chart repo to helm:

helm repo add atlantis https://runatlantis.github.io/helm-charts

To get the default helm chart values from the latest version, we can run the following to save the values in our current working directory as values.yaml:

helm inspect values atlantis/atlantis > values.yaml

IMPORTANT: I will be sharing my values that I am using for this demonstration, these values are fitted for my environment and may require some tweaking to fit your environment. I will try to document each configuration option.

values.yaml
---
# https://github.com/runatlantis/helm-charts/blob/atlantis-5.4.2/charts/atlantis/values.yaml

atlantis:
  atlantisUrl: https://atlantis.mydomain.tech       # this is your ingress url
  orgAllowlist: 'gitlab.com/rbekker87/*'  # specifies which repositories you want to allow atlantis to work from
  gitlab:
    user: rbekker87                                  # the gitlab user of your account

  vcsSecretName: 'atlantis-vcs'                      # the kubernetes secret that we created earlier

  repoConfig: |-                                     # atlantis server side repo configuration
    repos:                                           # https://www.runatlantis.io/docs/server-side-repo-config
    - id: /.*/
      apply_requirements: [approved, mergeable]
      import_requirements: [approved, mergeable]
      workflow: default
      allowed_overrides: [workflow, apply_requirements]
      allow_custom_workflows: true
    workflows:
      default:
        plan:
          steps: [init, plan]
        apply:
          steps: [apply]    

  hidePrevPlanComments: true                         # neatens up your previous comments be collapsing them
  enableDiffMarkdownFormat: true                     # provides a nice markdown preview

  service:
    type: ClusterIP

  ingress:
    enabled: true
    ingressClassName: nginx                          # provide your ingress class
    path: /events                                    # ensure to have /events here
    pathType: ImplementationSpecific
    host: atlantis.mydomain.tech                     # the ingress host
    tls:                                             # the ingress tls configuration
      - secretName: sektorlab-tech-tls
        hosts:
        - atlantis.mydomain.tech

  environment:                                       # the atlantis server configuration
    ATLANTIS_GITLAB_USER: "rbekker87"                # https://www.runatlantis.io/docs/server-configuration.html
    ATLANTIS_AUTOMERGE: true
    ATLANTIS_AUTOPLAN_MODULES: true
    ATLANTIS_ALLOW_COMMANDS: "version,plan,apply,unlock,import,state,approve_policies"

  environmentSecrets:                                # here we are referencing the secrets that we created earlier 
    - name: ATLANTIS_GITLAB_TOKEN
      secretKeyRef:
        name: atlantis-vcs
        key: gitlab-token
    - name: ATLANTIS_GITLAB_WEBHOOK_SECRET
      secretKeyRef:
        name: atlantis-vcs
        key: gitlab-webhook-secret

Now that we have our helm release custom values defined, we can install Atlantis to our Kubernetes cluster using:

helm upgrade --install atlantis atlantis/atlantis \
  --create-namespace \
  --namespace atlantis \
  --version 5.4.2 \
  --values values.yaml

After we deployed atlantis, we can check if our pods are running:

kubectl get pods -n atlantis

We can verify if our ingress was created:

kubectl get ingress -n atlantis

We are running a statefulset for Atlantis, so we can monitor the logs from our statefulset:

kubectl logs -f sts/atlantis -n atlantis

If everything looks good we can continue to configure our webhook for our Gitlab project.

Step 3: Configure Gitlab Webhooks

I have created a repository atlantis-demo, and inside the project I need to add a webhook to this project so that Merge Request events can be sent from Gitlab to Atlantis.

From the project, select "Settings" on the left and then select "Webhooks":

atlantis-gitlab-webooks-navigate

Then select "Add new webhook" on the right and provide your events ingress url, it should contain the /events suffix at the end, for example:

  • https://atlants.mydomain.tech/events

Then provide the following:

  • Name: The name will be used as an identifier in your Gitlab webhooks.
  • Secret: This is the secret that we created earlier, which you can access with cat /tmp/gitlab_secret.
  • Trigger: Push events, Comments and Merge request events.

If your ingress uses SSL and is verified then you can select Enable SSL verification and then select "Add webhook.

Step 4: Configure Your Terraform Repository

In our Terraform Repository (atlantis-demo), add an atlantis.yaml file in the root of our project, where we define our environment name, our workspace and since I am testing this project on my own I will be overriding my apply requirements that I don't require approvals on my merge request:

atlantis.yaml
version: 3
projects:
- dir: environments/dev
  workspace: dev
  apply_requirements: [undiverged]
  autoplan:
    when_modified: ["*.tf", "../../modules/**/*", ".terraform.lock.hcl"]
    enabled: true

Lets define some Terraform code that will output a random uuid. In environments/dev/main.tf define:

environments/dev/main.tf
resource "random_uuid" "uuid" {}

terraform {
  required_providers {
    random = {
      source = "hashicorp/random"
      version = "3.5.1"
    }
  }
}

provider "random" {}

output "uuid" {
  value       = random_uuid.uuid.result
  sensitive   = false
}

Now we can commit this to a branch and create a merge request.

Step 6: Test Your Setup

When we review the workflow of how Atlantis works from our previous post, we can summarize it as follows:

  1. A Merge Request (MR) gets opened and the event gets sent to Atlantis.
  2. A Terraform plan execution gets triggered by Atlantis and the output gets sent back to the MR.
  3. The user comments atlantis apply which is sent to the webhook and terraform apply gets executed on the Atlantis pod.
  4. The output gets sent as a comment and Atlantis merges the MR.

atlantis-workflow

First, I Open a Merge Request in my GitLab repository and watch Atlantis in action, our Merge Request diff looks like the following:

gitlab-terraform-merge-request

You should see Atlantis automatically comment with the output of terraform plan in the Merge Request overview:

terraform-atlantis-plan

You can also rerun the plan by commenting atlantis plan. If you are happy with the changes that Terraform will create, you can comment atlantis apply:

terraform-atlantis-apply

And once Atlantis applied the Terraform changes, Atlantis will then merge the Merge Request.

Atlantis Commands

In our atlantis.yaml we have defined some defaults like our dir: environments/dev and workspace: dev, so everytime we have a commit in that directory, atlantis will automatically do a plan, and resulting in the following command:

atlantis plan -d environments/dev -w dev

I will provide a couple of examples of atlantis commands that we can run.

  1. Run a plan in all environments:
atlantis plan
  1. Run a plan in a different workspace:
atlantis plan -d environments/dev -w test
  1. Run a plan against a target:
atlantis plan -d environments/dev -w dev -- -target=module.vpc
  1. Plan a delete
atlantis plan -d environments/dev -w dev -- -destroy
  1. Remove Terraform state:
atlantis state -d environments/dev -w dev rm 'module.acm[0].this'
  1. Import Terraform state:
atlantis import -d environments/dev -w dev module.this.resource resource.this.something
  1. Atlantis help
atlantis --help

Conclusion

Setting up Atlantis with GitLab streamlines your Terraform workflow, making infrastructure changes more efficient and secure. By following this guide, you can automate Terraform operations, enforce best practices, and improve collaboration within your team.

Stay tuned for more tutorials and tips on Terraform and infrastructure management. Happy automating!

Thank You

If you found this guide helpful, share it with your colleagues and friends. Don't forget to subscribe to our newsletter for more insights and tutorials on DevOps and infrastructure management. Follow me at @ruanbekker on Twitter.

Join my Newsletter?
Buy Me A Coffee