How to Hide Sensitive Things in GitHub Actions Logs

Recently, whilst I was on an adventure in the wonderful GitHub Actions, I discovered that your GitHub Actions logs are public. 🚨 Oh no! Now people will discover that I’ve been deploying websites to filthyfansofpeanutbutter.com. How can I hide sensitive URLs from the logs, so people can’t see my niche interests?

I’m working on a GitHub Actions CI/CD pipeline (or, as GitHub calls it, a “Workflow”), and I want to make sure that private URLs aren’t visible in the logs.

So I’d like to prevent URLs from appearing in the logs, so they’re either masked like this ******, or hidden altogether.

Why bother trying to hide anything?

“Why bother,” you ask.

Well, I like your approach of starting with ‘Y tho’.

And this isn’t really an earth-shattering problem. If URLs are printed in the logs, then so what?

But leaking private URLs is just something that I just don’t want. Not because security by obscurity is how I roll, but because it’s a piece of data that people don’t need to know about. And I’d like to share things on a need-to-know basis only.

And while I love open source, that doesn’t also mean I want to open everything (like sharing where I’ve been, and what my shopping list looks like).

(Although for the sake of clarity here, I’ll say that my shopping list currently includes oatcakes, Tony’s Chocolonely and a bumper pack of toilet paper.)

So, if you’ve decided that you want to reduce what you’re sharing in your logs, how do you mask, or hide, any sensitive data in GitHub Actions logs? The answer, for me, was to add a new step in a Workflow.

Introducing the ‘add-mask’ step

There are a few GitHub Actions commands that you can use in a Workflow, which control the way that GitHub Actions behaves.

add-mask is one of these actions. When you call it from a Workflow, with a string, it will hide that string in the logs.

So I added it to my existing workflow, at the beginning of the workflow:

jobs:
  my-peanut-butter-job:

    steps:
    - name: Add mask
      run: |
        echo "::add-mask::filthyfansofpeanutbutter.com" 

(I’ve added it at the beginning of the workflow, because I think the mask takes effect when the command gets executed. So you want to execute it as early as possible in the workflow.)

The problem with doing it this way though, is that anyone who can see your Workflow file will be able to see the exact string that you’re trying to hide.

This kinda defeats the purpose of the exercise, doesn’t it?

So how do we “hide” the string that we want to mask, and also make it configurable?

The way I did it is to use a Secret.

Make it dynamic… with a Secret

Secrets in GitHub Actions are a nice way to inject private configuration values into a Workflow. It’s a perfect vehicle to inject the secret hostname that I want to hide.

So I go into GitHub and create a secret (in Repository → Settings → Secrets). The name I choose for the Secret is CLUSTER_URL:

Repository Secrets in GitHub

Secrets in GitHub let you store sensitive config data

Repository Secrets in GitHub by Tutorial Works is licensed under CC BY-SA 4.0

Now I’ve created the Secret, I can refer to it in the Workflow using ${{ secrets.SECRET_NAME }}.

So the ever-so-slightly-improved mask step looks like this:

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - name: Add mask
        run: |
          echo "::add-mask::${{ secrets.SECRET_URL }}" 

Now, whenever the workflow runs, if any of the steps cause a line to be written to the logs containing my sensitive URL, GitHub will will replace it with asterisks. So nosey parkers won’t be able to see it.

This is what the masked output looks like in the logs, when I try to echo that secret:

Masking a Secret in the logs of GitHub Actions

Successfully masked!

Masking a Secret in the logs of GitHub Actions by Tutorial Works is licensed under CC BY-SA 4.0

Cool!

You might find this useful if you’re working on open source projects, but you’re using GitHub Actions for CI, and you don’t want nosey people to see any private URLs you’re deploying to. 👀

A full example

If you want to see this in action, then you can check out a demo Workflow file here:

See a demo repo on GitHub

Comments

Got any thoughts on what you've just read? Anything wrong, or no longer correct? Sign in with your GitHub account to leave a comment.

(All comments get added as Issues in our GitHub repo here, using the comments tool Utterances)