Secrets
This page describes how Canasta tracks secret state β database passwords, the MediaWiki secret key, backup credentials, and similar β for both orchestrators, and what your recovery pathways look like if a host or cluster is destroyed. Operators evaluating production deployments should read this alongside Help:Backup and restore (which covers what gets captured in Restic snapshots) and the orchestrator-specific pages.
What counts as secret state
Every Canasta instance holds a small set of secret values:
- Database credentials β
MYSQL_PASSWORD(the wiki user's password) and, for bundled-DB instances,MYSQL_ROOT_PASSWORD(the DB server's root password). MW_SECRET_KEYβ MediaWiki's$wgSecretKey. Used for HMACs, session tokens, password-reset tokens, and CSRF tokens. Rotating it invalidates all of those across the wiki β treat it as a one-shot value.- Backup credentials (when configured) β
RESTIC_PASSWORDand the cloud-provider keys for the chosen backend (AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEYfor S3,AZURE_*for Azure Blob, etc.). - SMTP credentials (when email is configured).
These values originate in the envfile the operator passes to canasta create (or are generated by Canasta if not supplied). Where they live after creation is the part that differs by orchestrator.
Source of truth shifts at create time
For both orchestrators, the operator's envfile is the input β but after canasta create finishes, the runtime view (what the wiki actually authenticates with) lives in different places:
| Orchestrator | Runtime view | On-disk record |
|---|---|---|
| Docker Compose | The instance directory's .env file (typically ~/canasta/<id>/.env, mode 0600). The bundled db container reads it at startup; the wiki reads it via PHP's getenv(). There is no indirection β the .env on disk IS what the wiki uses. |
(same file) |
| Kubernetes | In-cluster K8s Secret resources: <id>-db-credentials (with MYSQL_PASSWORD and, for bundled DB, MYSQL_ROOT_PASSWORD) and <id>-mw-secrets (with MW_SECRET_KEY). The Helm chart's web and jobrunner pods reference them via secretKeyRef. |
~/canasta/<id>/.env on the operator workstation. After create, this is a record/snapshot β pods don't read from it.
|
This divergence is the reason the two orchestrators behave differently when you try to rotate a secret.
Updating secrets via canasta config set
Compose
canasta config set MYSQL_PASSWORD=<new> updates .env, and the next canasta restart recreates the containers, which re-read the env on startup. Rotation propagates correctly.
The caveat: if you're rotating MYSQL_PASSWORD for the bundled DB, you also need the password to actually exist on the database. Changing the env var alone makes the wiki try to connect with a password the DB doesn't recognize. The supported flow is to rotate at the DB layer first (ALTER USER ... IDENTIFIED BY '<new>') or via the migration pattern documented in Help:Upgrading.
For external DB, rotation is operator-owned at the DB server (RDS, Aurora, etc.) β change the password there first, then canasta config set MYSQL_PASSWORD=<new> + canasta restart.
Kubernetes
canasta config set refuses to change MYSQL_PASSWORD, WIKI_DB_PASSWORD, MYSQL_ROOT_PASSWORD, or MW_SECRET_KEY on a K8s instance. Updating .env alone wouldn't change what the running wiki authenticates with β the pods read from K8s Secrets, not from .env β so the command fails fast with the kubectl-based rotation recipe instead of silently no-op'ing.
To rotate one of these credentials on a K8s instance:
- Update the value at its source (e.g., the database server for
MYSQL_PASSWORD; generate a fresh random value forMW_SECRET_KEYβ and accept that all sessions and password-reset tokens will be invalidated). - Update the K8s Secret in the cluster:
kubectl create secret generic <id>-db-credentials \ --from-literal=MYSQL_PASSWORD='<new-value>' \ --dry-run=client -o yaml | kubectl apply -f -
- For
MW_SECRET_KEY, target<id>-mw-secrets. To rotate multiple keys atomically, list them all in the same--from-literalcall.
- Restart the wiki pods so they pick up the new value:
canasta restart -i <id>
Other secret-bearing keys (backup credentials like RESTIC_PASSWORD, cloud-credential keys, SMTP_PASSWORD) flow through a different K8s Secret β canasta-<id>-backup-env β which Canasta rebuilds from .env on every canasta start / restart. Those keys are mutable via canasta config set followed by canasta restart on K8s.
Recovery pathways shipped today
Compose
| Pathway | Captures | Restored by |
|---|---|---|
Restic snapshot's .env |
The full instance .env (DB creds, MW_SECRET_KEY, RESTIC_*, AWS_*, ...) | canasta backup restore
|
GitOps repo's hosts/<host>/vars.yaml (git-crypt encrypted) |
Same content, encrypted in a separate forge | canasta gitops pull after providing the git-crypt key
|
The two pathways are independent: if the Restic backend is unreachable, the gitops repo + git-crypt key brings everything back. If the gitops repo (or git-crypt key) is gone, Restic still has it.
Kubernetes
| Pathway | Captures | Restored by |
|---|---|---|
Restic snapshot's secrets-<id>.yaml |
<id>-db-credentials and <id>-mw-secrets as kubectl apply-able YAML |
canasta backup restore re-applies them via the web pod's kubectl
|
K8s ships a single in-Canasta recovery pathway. The encrypted-secrets-in-gitops-repo idea was considered and dropped β operators who need a third independent backup pathway should layer their preferred secrets manager on top (see below).
Adding a third independent pathway via a secrets manager
For deployments where the threat model includes "Restic backend AND host or cluster destroyed simultaneously," operators should layer a corporate secrets manager. This applies to both orchestrators.
Brief pointers, in rough order of integration cost:
- Manual convention. Paste the instance's secret material into a 1Password / Vault / Bitwarden / etc. Secure Note titled
Canasta: <instance-id>. Recovery is a manual copy/paste back into a new envfile andcanasta create -e envfile. Zero Canasta-side code; works today. - AWS Secrets Manager (K8s with external-secrets-operator) β operator stores secrets in AWS, ESO reconciles them into cluster Secrets matching Canasta's expected names (
<id>-db-credentials,<id>-mw-secrets). - HashiCorp Vault (K8s with ESO or Vault Agent injector) β same shape, vendor-neutral.
- sealed-secrets (K8s only) β encrypt the canasta-managed K8s Secrets with the cluster's public key, commit the sealed manifests anywhere (including the gitops repo); the in-cluster controller decrypts them. Useful when you want secrets in version control without a separate vault service.
- 1Password Connect, Doppler, Akeyless, etc. β similar shape, vendor-managed.
Canasta doesn't endorse one of these β it documents what the runtime locations contain and lets operators choose escrow that fits their compliance posture.
What a secrets manager does and doesn't change
For Kubernetes, layering a secrets manager that reconciles into <id>-db-credentials / <id>-mw-secrets does shift the source of truth β the secrets-manager operator becomes the upstream, and canasta create's initial Secret population is overwritten on the next reconcile. That's a coherent operating model with real benefits (rotation, audit log, role-based access).
For Docker Compose, the equivalent does not change the in-use threat model. Docker Compose reads env vars from .env on the host filesystem; whatever secrets the wiki actually uses must live in plaintext on the host while the wiki is running. Anyone with root on the host can cat ~/canasta/<id>/.env regardless of whether the off-host backup lives in 1Password, in the gitops repo (encrypted), or both.
What a secrets manager does improve for Compose:
- Audit log β who accessed which credentials when. git-crypt provides none.
- Access control β role-based sharing rather than the all-or-nothing of "send a teammate the git-crypt key file."
- Rotation tooling β vault-side workflows for periodic credential rotation.
- No git-crypt key escrow burden β one less key to manage off-line.
So 1Password (or any equivalent) is "additionally available" for Compose rather than "filling a gap." git-crypt does most of what's needed for the secret-storage part; the secrets manager adds operator hygiene around audit, sharing, and rotation.
Disaster recovery
Compose
If the host is destroyed:
- Provision a fresh host that meets the target-host requirements.
- Restore one of the off-host secret pathways:
- From Restic snapshot:
canasta backup restoreagainst the new host (will pull the .env contents along with the rest of the instance state). - From gitops repo:
canasta gitops pullafter providing the git-crypt key. The .env is reconstructed fromhosts/<host>/vars.yaml. - From a secrets manager: pull the secret material into a fresh envfile, then
canasta create -e envfile -i <id>on the new host, followed by import of any backed-up data.
- From Restic snapshot:
- Verify the wiki is reachable and authenticates correctly. See Help:Troubleshooting for common post-restore symptoms.
Kubernetes
If the cluster is destroyed:
- Provision a fresh cluster (or re-provision via your cluster-as-code tooling). See Help:Multi-node Kubernetes for the topology requirements and Help:User journeys/Canasta on AWS EKS with RDS for an EKS worked example.
- Set up cluster-scoped infrastructure: ingress controller, cert-manager, EBS / NFS / EFS CSI driver, Argo CD if you use GitOps.
- Restore the canasta-managed Secrets via one of:
- Restic snapshot (the in-Canasta pathway):
canasta backup restorewill re-applysecrets-<id>.yamlas part of the restore flow. - Secrets manager (the third-pathway): use your operator (ESO, sealed-secrets controller, etc.) to materialize
<id>-db-credentialsand<id>-mw-secretsin the new instance namespace.
- Restic snapshot (the in-Canasta pathway):
- Run
canasta create -i <id> --orchestrator k8swith the same envfile content as the original. The Secrets you restored in step 3 will be picked up rather than overwritten if their names match. - Verify pods come up, certificate issues, ingress is reachable, wiki authenticates.
See also
- Help:Backup and restore β what Restic snapshots capture and how restore works.
- Help:External database β points Canasta at a managed DB; the password rotation flow there involves the DB server you control.
- Help:GitOps β version-controlled multi-environment config management; relevant for the Compose gitops-repo recovery pathway.
- Help:Multi-node Kubernetes β multi-replica web requires shared (RWM) storage; the secret-flow described here applies regardless of replica count.
- Help:Storage β persistent volume model; secrets are independent of storage classes.