wissel.net

Usability - Productivity - Business - The web - Singapore & Twins

Coming of age - encrypt your environment

This article is part of a mini series. Read them all:

  1. Harden your developer setup with age and direnv
  2. Using age in Github actions

Using age in Github actions

Hero image for Using age in Github actions

In the last article I introduced age and a working setup for macOS. Now let's look at Github actions integration

TL/DR

In a nutshell: create an age key just for GitHub actions, commit it to secrets, add the public key to recipients.txt and add it to your github job.

Step by step

There are a few consideration for each step you need to be aware off. Nothing dramatic, just stumbling blocks, I stumbled over, so you don't have to.

Create a key for CI

Generate the key:

age-keygen -o ci-key.txt
chmod 600 ci-key.txt

When you opted for a repo based key, you can save yourself a step by adding it directly to recipients.txt

CIKEY=$(age-keygen -o ci-key.txt 2>&1 | sed -n 's/^Public key: //p')
echo $CIKEY >> recipients.txt
age -d -i <(security find-generic-password -s age-corporate -a "$USER" -w) .env.age \
  | age -R recipients.txt -o .env.age.tmp && mv .env.age.tmp .env.age

Add to GitHub

You have a choice between

  • repository based keys (https://github.com/<your_org_or_user>/<yourrepo>/settings/secrets/actions)
  • organization based keys (https://github.com/organizations/<your_org>/settings/secrets/actions)

Organization based keys are convenient, but allow any repo to decode your secrets. So choose wisely. Give it the name AGE_KEY_CI

You need the line that starts with AGE-SECRET-KEY-1. Once saved, delete ci-key.txt.

Use it in a GitHub Action

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
      - name: Install age
        run: sudo apt-get update && sudo apt-get install -y age
      - name: Decrypt secrets
        shell: bash
        env:
          AGE_KEY_CI: ${{ secrets.AGE_KEY_CI }}
        run: |
          set -euo pipefail
          age -d -i <(printf '%s' "$AGE_KEY_CI") .env.age | awk '
            /^export / {
              line = $0; sub(/^export /, "", line)
              key = line; sub(/=.*/, "", key)
              val = line; sub(/^[^=]+=/, "", val); gsub(/^["'"'"']|["'"'"']$/, "", val)
              if (length(val) > 5) print "::add-mask::" val
              print key "=" val >> ENVIRON["GITHUB_ENV"]
            }'

This will make all your variables available in the github environment. The beauty is having a single source of environment truth in .env.age The awkcommand adds the variables to the GitHub environment and ensures that the values are masked.

Next up: Yubikey and SSH.

As usual YMMV


Posted by on 24 August 2026 categories: DevelopmentGitHub

Add your comment…

Comments

  1. No comments yet, be the first to comment