Feature permissions¶
A few of Kopiur's features need the operator to write Secrets in namespaces it manages. That is a broader privilege than a backup operator needs day to day, so those writes are off by default, and each one is gated behind a single Helm flag.
This page explains which features those are, which flag maps to which feature, the security trade-off, and how to recognize and fix the error you get if you turn a feature on in a custom resource but forget the matching flag.
The mental model
The operator always has read-only access to Secrets. It has to, in order to resolve your repository credentials.
The flags on this page only grant the write verbs, meaning create, patch and delete, and only for the feature you opt into.
A feature is configured in two places: the CRD field that turns it on, such as spec.server, and the Helm flag that grants the operator the RBAC to act on it. You need both, because the chart cannot know at install time which features your custom resources will eventually use.
The two flags¶
features:
credentialProjection:
# -- Enable `spec.credentialProjection` (copy a repository's credential
# Secret(s) into each mover Job's namespace) by granting the operator `secrets`
# create+patch+delete. The chief win is a shared ClusterRepository whose Secret
# is pinned to one namespace; the operator also cleans its copies up again
# (legacy-copy sweep, reap-on-shrink, reap-on-disable).
# SECURITY TRADE-OFF: `create` cannot be scoped to a Secret name, so the
# operator can write a Secret in any namespace it manages.
enabled: false
kopiaUi:
# -- Enable `spec.server` (the kopia web-UI) by granting the operator `secrets`
# create+patch+delete. The server needs a generated-auth Secret, a mirror of
# each of a ClusterRepository's credential Secrets in the server namespace, and
# deletion of all of them on teardown.
# SECURITY TRADE-OFF: grants unscoped create/delete on Secrets in any namespace
# the operator manages.
enabled: false
| CRD field you set… | …needs this Helm flag | Grants the operator secrets |
|---|---|---|
spec.credentialProjection on a SnapshotPolicy / Restore / Maintenance |
features.credentialProjection.enabled |
create, patch, delete |
spec.seed.credentialProjection on a Repository / ClusterRepository (migrate-mode seeding) |
features.credentialProjection.enabled |
create, patch, delete |
spec.server on a Repository / ClusterRepository (the kopia web-UI) |
features.kopiaUi.enabled |
create, patch, delete |
Both default to false. With both off, the operator's secrets access is read-only, which is exactly what a plain backup deployment needs.
Why each feature needs it¶
- Credential projection (Movers → projection) copies a repository's credential
Secretinto each mover Job's namespace, so a sharedClusterRepositorywhoseSecretlives in one place works across many workload namespaces.
The operator therefore needs to create and patch Secrets in those namespaces, and to delete them, because a copy only needs to live as long as a mover Job can still read it. Kopiur reclaims each copy once the run that needed it has finished, rather than leaving live repository credentials sitting in your app namespaces. The ownerReference on the copy is a backstop for the case where the whole custom resource is removed; it is not the cleanup mechanism, because a Snapshot is kept for your entire retention window and waiting for garbage collection would mean waiting months.
- Seeding from another repository (Repositories →
seed) is the same mechanism aimed at a different Secret.
A migrate-mode seed opens two repositories from one bootstrap pod, and the source repository's credentials usually live in another namespace. seed.credentialProjection.enabled copies them into the seeding Job's namespace for the run, and the copies are reclaimed when the seed finishes. Without the flag the bootstrap fails closed, with a message naming both the CRD field and the install flag, rather than launching a Job that cannot authenticate.
- The kopia web UI server (Web UI) creates a generated-auth
Secretfor the UI login, whenauth: generate. For aClusterRepositoryit also mirrors the repository's credentials into the server's namespace, because the Deployment'senvFromonly reads the local namespace. Both are deleted on teardown or on a namespace migration, so this feature needscreate,patchanddelete.
Enabling a feature¶
Turn on the flag for the feature you use, in Helm values:
features:
credentialProjection:
enabled: true # if you use spec.credentialProjection
kopiaUi:
enabled: true # if you use spec.server
Or on the command line:
$ helm upgrade kopiur oci://ghcr.io/home-operations/charts/kopiur \
--reuse-values --set features.kopiaUi.enabled=true
A real blast-radius trade-off
create and delete cannot be scoped to a Secret name. The Kubernetes authorizer cannot match a name at create time, and projected and mirrored names are derived per run.
So enabling a flag lets the operator write, and for kopiaUi also delete, a Secret in any namespace it manages. That is the price of the convenience.
Leave a flag false and the operator simply cannot perform that feature's writes; you manage the Secrets yourself instead. A projected or mirrored copy in namespace X is readable by anything that can already read Secrets in X, which is no different from placing it there by hand.
Don't disable features.kopiaUi.enabled while a spec.server is live
Tearing down a server, or letting a ClusterRepository finalizer clean one up, deletes the generated-auth Secret and the mirrored credentials. If you revoke the flag first, that cleanup gets a 403 and the leftover Secrets linger.
Remove spec.server from the repositories first, let the operator tear the server down, then disable the flag.
Symptom → fix¶
If you enable a feature in a custom resource while the matching flag is still false, RBAC forbids the operator's write and the affected resource degrades with a clear, actionable condition. It does not crash, and it heals the moment you grant the flag.
Here is what you will see:
$ kubectl describe snapshotpolicy app-backup -n apps
...
Message: the operator is not permitted to write the projected credentials
Secret `app-backup-...-creds-0` in namespace `apps` (HTTP 403).
Credential projection needs cluster-wide `secrets` create/patch RBAC.
Fix: set `features.credentialProjection.enabled: true` in the Helm
chart, or disable `spec.credentialProjection` ...
$ kubectl describe repository nas-primary -n apps
...
Message: the operator is not permitted to write the kopia web-UI Secret
`nas-primary-kopia-ui-auth` in namespace `apps` (HTTP 403). The kopia
web-UI server (`spec.server`) needs `secrets` create/patch/delete RBAC.
Fix: set `features.kopiaUi.enabled: true` in the Helm chart, or remove
`spec.server` ...
| Symptom | Cause | Fix |
|---|---|---|
SnapshotPolicy/Restore/Maintenance status shows a 403 about a projected credentials Secret |
spec.credentialProjection is on but features.credentialProjection.enabled is false |
Set features.credentialProjection.enabled: true (or manage the Secret yourself and drop spec.credentialProjection) |
Repository/ClusterRepository bootstrap fails naming spec.seed.credentialProjection and the install flag |
spec.seed.credentialProjection.enabled is on but features.credentialProjection.enabled is false |
Set features.credentialProjection.enabled: true (or put the source repository's Secrets in the seeding Job's namespace yourself and drop the block) |
Repository/ClusterRepository status shows a 403 about a kopia web-UI Secret |
spec.server is set but features.kopiaUi.enabled is false |
Set features.kopiaUi.enabled: true (or remove spec.server) |
After you grant the flag, the operator re-reconciles and the condition clears on its own. No restart or manual retrigger is needed.
See also¶
- Movers, RBAC & credentials covers the full credential-projection model.
- Web UI (kopia server) is the
spec.serverfeature guide. - Helm chart values is where these flags live.