-
Notifications
You must be signed in to change notification settings - Fork 0
Secrets & Credentials
This page covers the design and management of secrets across the NAS-as-Code project — how they're stored, how they flow into deployments, and what you need to know when adding or rotating them.
🔗 For the official Azure KeyVault documentation, see Azure Key Vault Overview.
Early on I made the decision to never store secrets in the repository — not even encrypted. Instead, I use Azure KeyVault as the single source of truth for all sensitive values. GitHub Actions pulls them at runtime, and they only exist in memory during the workflow execution.
Why Azure KeyVault over just GitHub Secrets?
- Centralised — one place to manage secrets consumed by both repos
- Auditable — KeyVault logs who accessed what and when
- Rotation-friendly — update the secret in one place, both repos pick it up next run
- Separation of concerns — GitHub Secrets hold the access credentials to KeyVault; KeyVault holds the application secrets
💡 Think of it as: GitHub Secrets are the "keys to the safe", KeyVault is the "safe" itself.
Azure KeyVault (source of truth)
│
│ az keyvault secret list / show
▼
GitHub Actions environment variables (masked, ephemeral)
│
│ #{TOKEN}# replacement in .yml / .env files
▼
Config files on NAS (deployed, never committed)
All application-level secrets. Examples:
| Secret Name (KeyVault) | Env Var Name | Used By |
|---|---|---|
samba-password |
SAMBA_PASSWORD |
Samba role (sets SMB user password) |
nut-password |
NUT_PASSWORD |
NUT client role (UPS monitoring auth) |
*various container secrets* |
*VARIOUS* |
Container .env files |
⚠️ Naming convention: KeyVault secret names use lowercase-with-hyphens. The workflow converts these to UPPERCASE_WITH_UNDERSCORES for environment variable injection (e.g.my-secret→MY_SECRET).
Credentials for accessing infrastructure — not application secrets:
| Secret | Purpose |
|---|---|
AZURE_SPN_CREDENTIALS |
Service Principal JSON for Azure login |
AZURE_KEYVAULT_NAME |
Name of the KeyVault to read from |
SSH_PRIVATE_KEY |
SSH key for connecting to the NAS |
HOST_FINGERPRINT |
Pinned SSH host key of the NAS |
WG_CONFIG_FILE |
Full WireGuard config (private key, peer, endpoint) |
Non-sensitive configuration values:
| Variable | Purpose |
|---|---|
HOST_IP |
NAS IP address (routable over WireGuard) |
HOST_USER |
SSH user on the NAS |
ENV_NAME |
Environment name (test or production) |
Secrets flow into configuration files via a token replacement pattern. Any file containing #{SECRET_NAME}# will have that token replaced with the matching environment variable value at deployment time.
In nas-as-code (Ansible group_vars):
# inventory/group_vars/production.yml
samba_password: "#{SAMBA_PASSWORD}#"
nut_password: "#{NUT_PASSWORD}#"In nas-containers-as-code (.env files):
# media/.env
PLEX_TOKEN=#{PLEX_TOKEN}#
SONARR_API_KEY=#{SONARR_API_KEY}#The replacement happens via:
- A Python script in the workflow that uses
re.subfor safe handling of special characters
The following outlines the key decisions made when setting up the Azure side. For step-by-step commands, refer to the official docs linked below.
A dedicated SPN with minimal permissions is used by GitHub Actions to authenticate to Azure:
- Only has
Key Vault Secrets Userrole on the specific KeyVault resource - No broader subscription-level access
- Credentials stored as
AZURE_SPN_CREDENTIALSin GitHub
- RBAC authorization (not access policies) — cleaner, more standard
- Soft-delete enabled — protection against accidental deletion
- Purge protection — prevents permanent deletion during retention period
- No network restrictions — accessed from GitHub-hosted runners (dynamic IPs)
-
Add to Azure KeyVault — use the portal or
az keyvault secret set --vault-name <name> --name "my-new-secret" --value "the-value" -
Reference in config — add
#{MY_NEW_SECRET}#to the relevant.ymlor.envfile - Commit and push — the next workflow run will pick up the new secret automatically
No changes needed to the workflow itself — it dynamically lists and pulls all KeyVault secrets.
- Update the value in Azure KeyVault
- Next workflow run picks up the new value automatically
- No code changes or PRs required
If you need to rotate the SSH key, SPN credentials, or WireGuard config:
- Generate the new credential
- Update the corresponding GitHub Secret in both environments (test + production)
- For SSH keys — also update the authorized_keys on the NAS and the
HOST_FINGERPRINTif host keys changed
⚠️ Unlike KeyVault secrets, GitHub Secrets require manual updates in the repository settings UI (Settings → Environments → [environment] → Secrets).
Overview
Secrets & Networking
Ansible
- Ansible Structure
- Role: Docker
- Role: Storage
- Role: Samba
- Role: NUT Client
- Role: Backup
- Role: Coral TPU
Pipelines
Operations