Secrets backends (k3s)
The k3s target decouples what the app reads from how
secrets are stored. Every workload consumes plain k8s Secrets,
boringstack-secrets (app env) and ghcr-registry-secret (GHCR pull), plus the
CloudNativePG-generated boringstack-db-app that carries DATABASE_URL. The
manifests never reference Vault directly, so the producer is a swappable
Kustomize component in overlays/prod/secrets/.
Switch backends by editing one line under # Secrets backend (pick ONE) in
overlays/prod/kustomization.yaml.
Option A: Vault + Vault Secrets Operator (default)
Section titled “Option A: Vault + Vault Secrets Operator (default)”Requires Vault and the VSO
on the cluster. The component ships VaultConnection, VaultAuth, and
VaultStaticSecret resources that sync Vault KV-v2 into the k8s Secrets.
Seed Vault (KV-v2 mount secret):
# App env. Full key list: the api env validator, documented at# /reference/env-vars/. DATABASE_URL is injected by CNPG, so it's not here.vault kv put secret/boringstack \ JWT_SECRET="$(openssl rand -base64 48)" \ MFA_ENCRYPTION_KEY="$(openssl rand -base64 32)" \ VALKEY_PASSWORD="$(openssl rand -base64 24)" \ GLITCHTIP_SECRET_KEY="$(openssl rand -base64 50)" \ FRONTEND_URL="https://<domain>" PUBLIC_API_URL="https://<domain>" \ QUEUES_ENABLED=true CACHE_PROVIDER=valkey \ # ...email / OAuth / Stripe / VAPID as needed...
# GHCR pull creds. One key holding a full docker config.jsonvault kv put secret/boringstack-registry DOCKER_CONFIG_JSON=@dockerconfig.jsonBind a Vault Kubernetes-auth role so the operator can read those paths:
vault write auth/kubernetes/role/boringstack-prod-role \ bound_service_account_names=default \ bound_service_account_namespaces=boringstack-prod \ policies=boringstack-read ttl=10mOption B: Sealed Secrets
Section titled “Option B: Sealed Secrets”No external Vault. Encrypt the two Secrets with kubeseal and commit the
SealedSecret manifests; the Bitnami controller decrypts them in-cluster. Full
steps in overlays/prod/secrets/sealed/README.md.
Option C: plain Secret from .env
Section titled “Option C: plain Secret from .env”Simplest. Kustomize’s secretGenerator builds boringstack-secrets from a
gitignored secret.env; create ghcr-registry-secret with
kubectl create secret docker-registry. Steps in
overlays/prod/secrets/plain/README.md.
A pure-GitOps caveat: option C keeps secret values outside git, so it suits a cluster you apply to yourself rather than a fully declarative pipeline.