Post

Deploy infrastructure in Azure Cloud with terraform using github actions

Introduction

Using IaC (Infrastructure as Code) to deploy resources has become a common practice these days. However, orchestrating an end-to-end journey for users to deploy infrastructure is something that some people within companies may not fully appreciate. For this reason, integrating a Terraform project with GitHub Actions is a very effective strategy.

There are several benefits to using this approach:

True Infrastructure Versioning: There is a single point of execution for Terraform, providing complete traceability of who executed the deployment, when it was executed, and the outcome, whether successful or not.

IaC as Code and Review Process: Merely having Terraform code is not sufficient today. Deploying through a CI/CD (Continuous Integration/Continuous Deployment) pipeline facilitates easy testing, reviewing, securing, and versioning of the code.

Transforming IaC into a Technological Product: By delivering a pipeline that abstracts the Terraform code, and requires users to only provide some data about the infrastructure, the IaC project evolves from a simple project to something much more valuable for the users.

And more, a lot of more…

Azure with Terraform using Github Actions

Lets begun

There’s five ways to connect Terraform in Azure

  • Authenticating to Azure using the Azure CLI
  • Authenticating to Azure using Managed Service Identity
  • Authenticating to Azure using a Service Principal and a Client Certificate
  • Authenticating to Azure using a Service Principal and a Client Secret
  • Authenticating to Azure using OpenID Connect

In this example we are using “login With a service principal secret” method. This step can be done running:

az ad sp create-for-rbac --role="Contributor" --scopes="/subscriptions/20000000-0000-0000-0000-000000000000"

Expect output is something like:

1
2
3
4
5
6
7
{
  "appId": "00000000-0000-0000-0000-000000000000",
  "displayName": "azure-cli-2017-06-05-10-41-15",
  "name": "http://azure-cli-2017-06-05-10-41-15",
  "password": "0000-0000-0000-0000-000000000000",
  "tenant": "00000000-0000-0000-0000-000000000000"
}

These values map to the Terraform variables like so:

  • appId is the client_id defined above.
  • password is the client_secret defined above.
  • tenant is the tenant_id defined above.

After creating a service principal in Azure, it is necessary to create a GitHub Secret with its content, in this example, the AZURE_CREDENTIALS secret.

After that, parsing this JSON in a step is sufficient to pass the Terraform environment variables to the pipeline context like:

1
2
3
4
5
6
7
8
9
10
11
12
13
      - name: JSON Parse
        id: parse
        env:
          AZURE_CREDENTIALS: $
        run: |
          ARM_CLIENT_ID=$(echo $AZURE_CREDENTIALS | jq -r '.["clientId"]')
          ARM_CLIENT_SECRET=$(echo $AZURE_CREDENTIALS | jq -r '.["clientSecret"]')
          ARM_TENANT_ID=$(echo $AZURE_CREDENTIALS | jq -r '.["tenantId"]')
          ARM_SUBSCRIPTION_ID=$(echo $AZURE_CREDENTIALS | jq -r '.["subscriptionId"]')
          echo ARM_CLIENT_ID=$ARM_CLIENT_ID >> $GITHUB_ENV
          echo ARM_CLIENT_SECRET=$ARM_CLIENT_SECRET >> $GITHUB_ENV
          echo ARM_TENANT_ID=$ARM_TENANT_ID >> $GITHUB_ENV
          echo ARM_SUBSCRIPTION_ID=$ARM_SUBSCRIPTION_ID >> $GITHUB_ENV

And a terraform action to execute project

1
2
3
4
      - name: Set up Terraform
        uses: hashicorp/setup-terraform@v3
        with:
         terraform_version: 1.1.7

And now, we have a context with all elements to run, init, plan and apply commands

1
2
3
4
5
6
7
8
9
10
11
      - name: Terraform Init
        run: terraform init

      - name: Terraform Validate
        run: terraform validate

      - name: Terraform Plan
        run: terraform plan

      - name: Terraform Apply
        run: terraform apply --auto-approve

The full workflow looks like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
name: "Terraform: deploying my infrasctructure"

on: [workflow_dispatch]

jobs:
  terraform-apply:
    runs-on: ubuntu-latest
    defaults:
      run:
        working-directory: infra/azure/my-awesome-terraform-project

    steps:

      - name: Checkout repository
        uses: actions/checkout@v3

      - name: JSON Parse
        id: parse
        env:
          AZURE_CREDENTIALS: $
        run: |
          ARM_CLIENT_ID=$(echo $AZURE_CREDENTIALS | jq -r '.["clientId"]')
          ARM_CLIENT_SECRET=$(echo $AZURE_CREDENTIALS | jq -r '.["clientSecret"]')
          ARM_TENANT_ID=$(echo $AZURE_CREDENTIALS | jq -r '.["tenantId"]')
          ARM_SUBSCRIPTION_ID=$(echo $AZURE_CREDENTIALS | jq -r '.["subscriptionId"]')
          echo ARM_CLIENT_ID=$ARM_CLIENT_ID >> $GITHUB_ENV
          echo ARM_CLIENT_SECRET=$ARM_CLIENT_SECRET >> $GITHUB_ENV
          echo ARM_TENANT_ID=$ARM_TENANT_ID >> $GITHUB_ENV
          echo ARM_SUBSCRIPTION_ID=$ARM_SUBSCRIPTION_ID >> $GITHUB_ENV   

      - name: Set up Terraform
        uses: hashicorp/setup-terraform@v3
        with:
         terraform_version: 1.1.7
        
      - name: Terraform Init
        run: terraform init

      - name: Terraform Validate
        run: terraform validate

      - name: Terraform Plan
        run: terraform plan

      - name: Terraform Apply
        run: terraform apply --auto-approve

TIP: In the case of a multi-repo Terraform project, it’s easy to control which deployment is used by simply changing the working directory. This can be done by using the working-directory parameter like so: - working-directory: infra/azure/my-awesome-terraform-project.

And finally, place the workflow within a GitHub Actions structure. .github/workflows/deploy-azure.yaml

Considerations

Using this method, it’s possible to enhance our IaC delivery. We can add a Checkov Terraform step to increase security, incorporate Terraform linting, or ensure that if a Terraform plan command returns any failures, our pipeline halts before beginning the apply process.

Conclusion

In just a few steps, we can empower our dear users by enabling them to execute infrastructure tasks themselves, using modules or Terraform projects governed by SRE teams. Furthermore, users can contribute to an inner source process, utilizing Git as the IaC source of truth, for real.

Any sugests or doubt?

Feel free to reach out to me on social media: twitter ,linkedin and github.

You can also email me directly at rmnobarra@gmail.com.

Support

Did you really enjoy my content? Consider buying me a coffee through my Bitcoins wallets:

Donate with Bitcoin

Bitcoin Wallet:

bc1quuv5hml9fjkf7azgwkt4xp867pzdwzyga33qmj

Bitcoin wallet QRCODE

Donate through Lightning Network

Lighting Address:

lnbc1pjue6mkpp5yj737e7fm6efhlj6sns42a875pmkencqmvdshf4ghlnntaet5llsdqqcqzzsxqrrsssp5d9hxl686w839qkwmkm0m30cf5gp4gnzxh68kss393xqzlsg0wr3q9qyyssqp3933zc3fg46nk3vafh63r3lqd0jn2p04w5xrz77h33rrr3xm7ckegg6s2ss64g4rf4jg87zdjzkl5tup7umqpghy2qnk65tqzsnplcpwv6z4c

Lighting wallet QRCODE

Bye!

This post is licensed under CC BY 4.0 by the author.