Forwarding webhooks to Atlantis (Terraform automation tool) on Kubernetes cluster

Atlantis with Terraform

Atlantis is an open source Terraform pull request automation tool. It works by receiving & processing webhooks from various source control management systems such as GitHub, GitLab, Bitbucket, etc. A full list of webhook providers can be found in Atlantis official docs.

In this tutorial, we will deploy Atlantis in a Kubernetes cluster that doesn’t have public access.

Note that while we are using Helm to install both Webhook Relay and Atlantis services, this can be achieved with normal Kubernetes manifests.

Prerequisites

Git host access credentials

Atlantis will need to communicate with our Git hosting provider. Follow official documentation on getting access token that we can later use in the installation. For GitHub steps are:

  1. Create a Personal Access Token by following: https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token#creating-a-token
  2. Create the token with repo scope

Save the access token to your notepad or password manager, we will need it in the next step.

Installation

We will be using the official Atlantis Helm chart that can be found here: https://hub.kubeapps.com/charts/stable/atlantis.

Let’s start by creating a namespace:

kubectl create ns atlantis

And let’s switch context to it:

kubectl config set-context $(kubectl config current-context) --namespace=atlantis

Atlantis

Add repositories:

helm repo add stable https://kubernetes-charts.storage.googleapis.com
helm repo update

And to install the Atlantis chart (don’t forget to set your own details in github.user, github.token and github.secret):

helm upgrade --install atlantis stable/atlantis --version 3.12.2 \
--set=github.user=rusenask \
--set=github.token=XXX \
--set=github.secret=very-secret \
--set=service.type=ClusterIP \
--set=ingress.enabled=false \
--set=orgWhitelist="github.com/webhookrelay/*"

Here, variables are:

To verify your installation, check pods:

kubectl get pods
NAME READY STATUS RESTARTS AGE
atlantis-0 1/1 Running 0 95s

And services:

kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
atlantis ClusterIP 10.99.122.187 <none> 80/TCP 9s

Webhook Relay operator

Once Atlantis is deployed, we will need to create a Webhook Relay operator which will ensure that webhooks will get delivered to our Atlantis pod.

Retrieve your access token key & secret pair from https://my.webhookrelay.com/tokens and set them as an environment variables:

export RELAY_KEY=xxxxxxxxxxxx
export RELAY_SECRET=xxxxx

Add Webhook Relay Operator Helm repository:

helm repo add webhookrelay https://charts.webhookrelay.com
helm repo update

Install it:

helm upgrade --install webhookrelay-operator webhookrelay/webhookrelay-operator \
--set credentials.key=$RELAY_KEY \
--set credentials.secret=$RELAY_SECRET

We should see two pods running in our atlantis namespace:

kubectl get pods
NAME READY STATUS RESTARTS AGE
atlantis-0 1/1 Running 0 6m32s
webhookrelay-operator-65655d7c95-pvtnw 1/1 Running 0 13s

Operator doesn’t forward webhooks on its own. Each created CR will ensure an agent deployment that is configured to route specific buckets.

Next step is to configure webhook forwarding to the atlantis service:

apiVersion: forward.webhookrelay.com/v1
kind: WebhookRelayForward
metadata:
name: forward-to-atlantis
spec:
buckets:
- name: github-to-atlantis
inputs:
- name: public-endpoint
description: "Endpoint for GitHub"
responseBody: "OK"
responseStatusCode: 200
outputs:
- name: atlantis-pod
destination: http://atlantis:80

Save this file as whr-atlantis-cr.yaml and create it:

kubectl apply -f whr-atlantis-cr.yaml 
webhookrelayforward.forward.webhookrelay.com/forward-to-atlantis created

You should see a new pod running in your cluster:

kubectl get pods
NAME READY STATUS RESTARTS AGE
atlantis-0 1/1 Running 0 11m
forward-to-atlantis-whr-deployment-c9bf7fcd7-tz6zq 1/1 Running 0 14s
webhookrelay-operator-65655d7c95-pvtnw 1/1 Running 0 4m43s

Run a kubectl describe on our CRD:

kubectl describe webhookrelayforwards.forward.webhookrelay.com forward-to-atlantis
Name: forward-to-atlantis
Namespace: atlantis
Labels: <none>
Annotations: API Version: forward.webhookrelay.com/v1
Kind: WebhookRelayForward
Metadata:
Creation Timestamp: 2020-08-11T10:50:26Z
Generation: 1
Resource Version: 1582466
Self Link: /apis/forward.webhookrelay.com/v1/namespaces/atlantis/webhookrelayforwards/forward-to-atlantis
UID: fbee4016-787d-4b3b-8915-d6c104f4b88c
Spec:
Buckets:
Inputs:
Description: Endpoint for GitHub
Name: public-endpoint
Response Body: OK
Response Status Code: 200
Name: github-to-atlantis
Outputs:
Destination: http://atlantis:80
Name: atlantis-pod
Status:
Agent Status: Running
Public Endpoints:
https://o0iwkgx6phxnun8wifpxij.hooks.webhookrelay.com
Ready: true
Routing Status: Configured
Events: <none>

Here we can see our public webhooks URL “https://o0iwkgx6phxnun8wifpxij.hooks.webhookrelay.com“. Find yours and let’s add it to the GitHub.

You can also view your bucket configuration and agent connection status through buckets dashboard:

Buckets list

Git host configuration

GitHub configuration instructions can be found here https://www.runatlantis.io/docs/configuring-webhooks.html#github-github-enterprise. However, if you are using any other git hosting provider that Atlantis supports, follow those steps.

Note that my instance endpoint is ‘https://o0iwkgx6phxnun8wifpxij.hooks.webhookrelay.com‘ (yours will be different). Also, custom domains are available if you don’t like the generated one.

If you’re installing on the organization, navigate to your organization’s page, and click Settings. If installing on a single repository, navigate to the repository home page and click Settings.

  1. Select Webhooks or Hooks in the sidebar
  2. Click Add webhook
  3. set Payload URL to http://$WEBHOOKRELAY_URL/events (or https://$WEBHOOKRELAY_URL/events if you’re using SSL) where $WEBHOOKRELAY_URL is Webhook Relay public URL (in my example it’s ‘https://o0iwkgx6phxnun8wifpxij.hooks.webhookrelay.com‘). Be sure to add /events
  4. double-check you added /events to the end of your URL.
  5. Set Content type to application/json
  6. Set Secret to the Webhook Secret you set previously when installing Atlantis helm chart

    Note that if you’re adding a webhook to multiple repositories, each repository will need to use the same secret.

  7. Select Let me select individual events

  8. Check the boxes

    • Pull request reviews
    • Pushes
    • Issue comments
    • Pull requests
  9. Leave Active checked

  10. Click Add webhook

Payload URL and Content Type should look something like this:

Webhook Configuration

Trying it out

Create a new change in GitHub in a file such as main.tf with a resource resource "null_resource" "example-1" {}. Atlantis will receive an event through Webhook Relay and create a plan:

Atlantis plan on PR