Photo by Georg Bommeli

How to use environment variables and secrets using GitHub Actions

Overview of the different ways of using variables

Posted by Damien Aicheh on 04/15/2021 · 7 mins

When you create a workflow inside GitHub Actions you always have multiples environment variables that you need to use or reuse at different steps to achieve your goal. This can be environnement path, folder path, logins, passwords, etc.

In this tutorial we will discover the different ways to declare and use environment variables and store and retrieve your certificates using secrets.

Define an environment variable for a step

The most basic way to define an environment variable is to declare it directly in a step:

- name: Basic variable usage
  run: |
    echo Let\'s define a variable:
    VERSION_PREFIX=MyPrefix

    echo Display the version prefix: $VERSION_PREFIX
    echo And use it multiple times: $VERSION_PREFIX

As you can see above the variable VERSION_PREFIX is defined directly into the step and can then be used multiple times inside it. This is useful when you define variables all along your scripts.

Another equivalent syntax which do the same thing is this one:

- name: Display local environment variable
  env:
    VERSION_PREFIX: MyPrefix
  run: |
    echo We can use a variable multiple time: $VERSION_PREFIX
    echo inside a multi-line script: $VERSION_PREFIX

The advantage of this syntax is that the environment variables have a specific area called env above the script. The env keyword is a dedicated property defined by the GitHub Actions to declare our variables. Better to use this one, if you know all the values of each variable at the beginning of the script.

Define an environment variable across the entire job

Sometimes you want to define an environment variable to reuse it multiple times accross your jobs, for example a build configuration, a file suffix, etc. So you need to define it globally inside the job. To do that you have a property env accessible at the job level where you can do that:

job1:
  runs-on: ubuntu-latest
  env:
    OUTPUT_SUFFIX: MySuffix
  steps:
    - name: Use environment variables from entire job
      run: echo We display the $OUTPUT_SUFFIX define for the entire job1

    - name: Use environment variables from entire job
      run: echo We reuse the output suffix $OUTPUT_SUFFIX multiples time in the entire job1

As demonstrated above you have the ability to reuse the OUTPUT_SUFFIX environment variable across multiple steps in your job.

Define an environment variable across the entire workflow

If you have multiple jobs in your workflow you will probably need to share some global variables between each jobs.

Fortunately you have an env property available at the workflow level, that you can use like this:

name: Variables

on:
  push:
    branches: [main]

env:
  BUILD_CONFIGURATION: Release

jobs:
  job1:
    runs-on: ubuntu-latest
    steps:
      - name: First script from job1
        run: echo We use the global workflow variable $BUILD_CONFIGURATION

  job2:
    needs: job1
    runs-on: ubuntu-latest
    steps:
      - name: First script from job2
        run: echo And here again we use the same workflow variable $BUILD_CONFIGURATION

As you see above the BUILD_CONFIGURATION variable is defined for the entire workflow and is used in the job1 and job2

Store a certificate inside GitHub Actions

To have access to your certificates inside your workflows you need to use something call secrets. This allows you to store these files securely inside GitHub Actions.

Don’t store your certificates and passwords directly to your GitHub repositories, these files contains data that only you needs to know.

To store these files go to your GitHub project and go to Settings and then Secrets.

Secrets tab

Inside this menu click on New repository secret button to add the first one. As you have probably already noticed there is no way to upload your certificates directly to this interface. To solve this issue we need to transform our file into a base64 string.

To encode your certificate, depending on your local machine you can do:

Windows

certutil -encode data.txt tmp.b64 && findstr /v /c:- tmp.b64 > data.b64 && del tmp.b64

Mac

base64 -i data.txt -o data.b64

Ubuntu

base64 data.txt > data.b64

Then we can store this string securely inside GitHub Actions secrets. For example if we store a keystore inside the secrets we will have something like this:

Secrets example

Inside your job you can retrieve this file by decoding it, for instance with an Ubuntu runner:


- name: Get secret from base64
  env:
    KEYSTORE_BASE64: ${{ secrets.KEYSTORE_BASE64 }}
  run: |
    echo import certificate from secrets and regenerate the file
    echo $KEYSTORE_BASE64 | base64 -d > $RUNNER_TEMP/my_production.keystore

For other runners, the syntax to get a file from a base64 string are:

Windows

echo $YOUR_STRING > data.b64 && certutil -decode data.b64 data.txt

Mac

echo $YOUR_STRING | base64 -D  -o data.txt

Ubuntu

echo $YOUR_STRING | base64 -d > data.txt

Final touch

You will find a full example in this GitHub repository. As you can see in this tutorial, you have multiple ways to use environment variables inside GitHub Actions, be sure to check the context to apply the right one.

Sources:

Do not hesitate to follow me on to not miss my next tutorial!