Masking Input Parameters in GitHub Actions

jeremy-kaltenbach - Apr 26 '23 - - Dev Community

GitHub actions allow you to add input parameters, which will then be used during runtime of the workflow. The inputs can be passed from a different workflow that is calling the specified workflow (via the workflow_call event) or when the workflow is manually triggered (via workflow_dispatch). For the latter, GitHub will prompt for the inputs in a dialog box before kicking off the workflow.

Note that in the workflow logs, the input parameters will be logged in plain text. So what do we do if one or more inputs contain sensitive information? The common approach would be to use Secrets. These are very useful for encrypting sensitive information, such as API keys and will not be logged in plain sight.

But lets say there is a use-case where a manual workflow will be triggered by multiple users supplying their own credentials. Inputs would be an easier solution here instead of having to frequently update the secrets. Luckily there is a way to make sure those sensitive inputs don't get logged.

In the example below, we have a workflow that will prompt the user for their username and password, and then it will call an API using those credentials (with the help of the http-request-action). The username input is safe to log, but the password should not be shown.

name: Call API Example

on:
  workflow_dispatch:
    inputs:
      username:
        required: true
        type: string
      password:
        required: true
        type: string

jobs:
  do_the_thing:
    runs-on: ubuntu-latest
    steps:
    - name: Mask Password
      run: |
        API_PASSWORD=$(jq -r '.inputs.password' $GITHUB_EVENT_PATH)
        echo ::add-mask::$API_PASSWORD
        echo API_PASSWORD=$API_PASSWORD >> $GITHUB_ENV
    - name: Call API
      uses: fjogeleit/http-request-action@v1.11.1
      with:
        url: https://www.example.com/api/awesome/stuff
        method: 'POST'
        username: ${{ github.event.inputs.username }}
        password: ${{ env.API_PASSWORD }}
Enter fullscreen mode Exit fullscreen mode

To mask the password, a step will need to be added before calling the API. In the step, "Mask Password", we'll make use of the workflow command ::ask-mask::{value}.
Unfortunately, calling add-mask on the input directly (such as ::add-mask::${{ github.event.inputs.password }}) will still expose the input in the log (more info on the bug here: https://github.com/actions/runner/issues/643). But as a workaround, the input parameter needs to first be set to a variable. Then calling add-mask on that variable will properly mask it.
In the workflow example, the 'password' input is first assigned to the variable named API_PASSWORD. Then the add-mask command called with the variable. Finally, API_PASSWORD is set as an environment variable to be used in any following steps of the job.

The output log will then look something like this:

> Mask Password
Run API_PASSWORD=$(jq -r '.inputs.password' $GITHUB_EVENT_PATH)
  API_PASSWORD=$(jq -r '.inputs.password' $GITHUB_EVENT_PATH)
  echo ::add-mask::$API_PASSWORD
  echo API_PASSWORD=$API_PASSWORD >> $GITHUB_ENV
  shell: /usr/bin/bash -e {0}

> Call API
Run fjogeleit/http-request-action@v1.11.1
  with:
    url: https://www.example.com/api/awesome/stuff
    method: POST
    username: bobsmith
    password: ***
    data: {}
    files: {}
    timeout: 5000
  env:
    API_PASSWORD: ***
…
Enter fullscreen mode Exit fullscreen mode
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .