Setup Github Actions For Terraform

3 minute read

Description:

Similar to my Setup Azure Devops post, this post is how I connected to Azure via Github Actions instead of Azure Devops Pipelines.

Note: You can see the code for this post on my Github repo.

To Resolve:

  1. The first thing to do if you want to connect to Azure from Github is to store your Service Principle credentials in Githubs Repo encrypted:

    1
    2
    3
    4
    
    AZURE_CLIENT_ID
    AZURE_CLIENT_SECRET 
    AZURE_SUBSCRIPTION_ID
    AZURE_TENANT_ID
    
  2. Next, in your repo, you will create a .github folder and a workflows subfolder. Then you can create as many *.yml files as you want and these will be the same as your azure-pipelines.yaml you may be used to if you are coming from AzDo. For now, while I’m still new at Terraform, I will continue to separate my builds and my releases in seperate files so I created the seperate.

  3. OK, so first thing to do is to turn of Continous Integration for now so that we can only run these pipelines from the UI. We will turn it back on later once we have everything working as intended. For that, you will use the on keyword with the workflow-dispatcher flow.

  4. Next, you will use the Terraform Github Action by Hashicorp to use the Terraform CLI in your pipeline to deploy to Azure as normal.

  5. Since we are using the ubuntu build agents and forcing the use of Bash, I like to add a | for all run commands and then write multiline scripts. For example:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
    - name: Terraform Plan
       id: plan
       run: |
          cd ./2022-08-03-github-actions-setup
          terraform plan \
          -var="subscription_id=$ARM_SUBSCRIPTION_ID" \
          -var="tenant_id=$ARM_TENANT_ID" \
          -var="client_id=$ARM_CLIENT_ID" \
          -var="client_secret=$ARM_CLIENT_SECRET" \
          -out "tf.plan"
       continue-on-error: false
    
    • So the first line cd ./2022-08-03-github-actions-setup has a line break and the yaml will accept that because of run: | which is a literal block scalar (see ‘keep newlines’ in Block Scalar Style) in yaml.

    • But the next line that starts our long terraform plan \ uses a line continuation character that bash uses which will put all the following lines as spaces.

    • A few lines above is where we are forcing the build agent to use bash even if it is a windows machine:

    1
    2
    3
    
    defaults:
       run:
          shell: bash
    
  6. Anyways, running our build we can see that it successfully connect to Azure and runs a plan.

    • One thing I noticed different between how I have Azure Devops working and Github Actions is that I’m no longer passing the storage account’s Access Key as a var like I was before (see line 38).

    • I’m not sure why I was passing that before but I think it had to do with Terraforms backend provider and maybe the version of Terraform CLI I was using with Azure Devops? See When authenticating using the Access Key associated with the Storage Account: at the previous link. I think now we are just connecting as a Service Principle.

    • Looking into this more, I found this post which says that since I’m authenticating as Owner as my Service Principle, I can list keys which will then get me access to blobs on the storage account. See here where it says:

    1
    
    However, if a user has been assigned a role with Microsoft.Storage/storageAccounts/listKeys/action permissions, then the user can use the portal with the storage account keys, via Shared Key authorization. To use the storage account keys, Shared Key access must be permitted for the storage account. For more information on permitting or disallowing Shared Key access, see Prevent Shared Key authorization for an Azure Storage account.
    
    • So I think this means that setting Allow storage account key access under Configuration of the Storage Account, then I would need to give my Service Principle Storage Blob Data Contributor role in order to read/write blobs using the Azure RBAC route instead of Shared Key.

    • Putting this together means that currently Github Actions is using my Service Principle to store the state file in blob storage using Shared Key authorization.

  7. Another thing about Github Actions is that since the .github/workflows folders are at the root of the repo, I have it setup to where I will cd to the correct folder in my steps ( see lines 33 and 44 ) and then create a pipeline for each blog post to share about.