Welcome to the NZRT Wiki Podcast. Today we’re looking at Secrets and Tokens.
If you’ve spent any time working with GitHub Actions at NZRT, you’ve probably heard the term secrets thrown around. So let’s break down what they actually are, how NZRT uses them, and what you need to know to keep things secure.
At the most basic level, GitHub Secrets are encrypted environment variables. Think of them as a secure vault that GitHub Actions can reach into during a workflow run. Once a secret is stored, you can never read it back out through the GitHub interface — it’s write-only. The only time it appears is when a workflow actively uses it, and even then, GitHub automatically masks the value in your logs, replacing it with three asterisks so nothing sensitive ever gets printed.
Now, secrets come in three flavours. Repository secrets are encrypted and tied to a single repository. Organization secrets sit at the org level and can be shared across multiple repos. And environment secrets are scoped to specific deployment environments, like staging or production. This gives you a layered system where sensitive values live exactly where they need to be and nowhere else.
Here’s what NZRT currently has set up at the repository level. There are six secrets in use. The first two are SSH private keys — one called STAGING DEPLOY KEY for the staging server, and PROD DEPLOY KEY for production. Both are used by the deploy workflow. Then there’s the DOLIBARR API KEY, which sync workflows use to talk to the Dolibarr REST API. There’s a SLACK WEBHOOK secret for sending notifications from within jobs. A CODECOV TOKEN for coverage reporting during test runs. And finally, GITHUB TOKEN, which GitHub generates automatically and is available to all workflows.
At the organization level, NZRT shares two secrets across multiple repos. PROD DEPLOY KEY covers both the dolibarr-custom and nzrt-scripts repositories. And GITHUB TOKEN is available to everything in the org.
So how do you actually use a secret inside a workflow? The example in the wiki shows a deployment job where secrets are mapped to environment variables within a step. The deploy key and the API key are pulled in by name, and the shell script then references those environment variables. You’re never hard-coding the actual values — the workflow just knows to look for them by name and GitHub injects them at runtime. If you accidentally tried to print one of these values, GitHub would replace it with asterisks automatically. But the best practice is to simply not log secrets at all, even though masking protects you.
Let’s talk about how you create these secrets in the first place. For a GitHub personal access token, you go into your account settings, then Developer Settings, then Personal Access Tokens. You generate a new classic token, select the scopes you need — typically repo, admin repo hook, workflow, and read org — then copy the token and store it in your repository secrets.
For SSH deployment keys, the process is a two-step command-line workflow. First, you generate a new RSA key pair at 4096 bits with no passphrase — the no passphrase part matters because automation can’t type a password interactively. Then you take the private key, encode it in base64, and store that encoded value in GitHub Secrets. The matching public key goes onto the production server’s list of authorized keys. That way, GitHub Actions can authenticate over SSH without the actual private key ever appearing in a script.
NZRT also follows a naming convention for custom tokens. The pattern is a prefix, then the environment, then the type — so for example NZRT STAGING DEPLOY KEY or NZRT PROD DEPLOY KEY. This makes it immediately clear what each secret does and where it belongs.
Now, secrets don’t last forever — and they shouldn’t. The wiki includes a rotation checklist you should keep in mind. SSH deploy keys should be rotated every six months. API tokens every three months. Database passwords quarterly. You should also regularly review secret access in the GitHub audit log, remove secrets tied to anyone who leaves the team, and revoke anything that gets accidentally exposed the moment you discover it. That last point is non-negotiable — treat a leaked secret as fully compromised from the instant you find out.
One final thing worth remembering: secrets are only accessible during a workflow run. They’re never embedded in your code, never visible in the repository, and never returned through the GitHub API once stored. That’s the whole point — they stay in the vault until Actions needs them, and then they’re gone again.
That’s it for this episode of the NZRT Wiki Podcast. Thanks for listening.