@@ -5,21 +5,26 @@ kind: Component
55# Include from an app kustomization with:
66# components:
77# - ../../common/kopiur-backup
8- # then add a per-PVC stub (SnapshotPolicy + SnapshotSchedule + Restore carrying
9- # only the VARYING bits: name, sources.pvc.name, identity, schedule.cron, and the
10- # Restore mover UID) plus `dataSourceRef -> <pvc>-restore` on the app's PVC.
8+ # then add a per-PVC stub (SnapshotPolicy + SnapshotSchedule + Restore). The
9+ # stub carries the per-PVC VARYING bits — name, sources.pvc.name, identity,
10+ # schedule.cron, AND the mover securityContext (run the mover as the DATA owner
11+ # uid:gid + supplementalGroups[gid]). Plus `dataSourceRef -> <pvc>-restore` on
12+ # the app's PVC.
1113#
12- # This component injects every UNIFORM field by kind, so the per-PVC stub stays
13- # tiny and the fumble-prone fields (repository ref, populator, mover SC nesting)
14- # live in ONE place. Prereqs (once per namespace): label the namespace
15- # `kopiur.home-operations.com/repo: cluster-kopia` (ESO cred fanout + repo
16- # tenancy via the ClusterRepository allowedNamespaces selector).
14+ # WHY the mover UID is per-PVC, not injected here: under baseline Pod Security
15+ # the mover can't use capabilities (no CAP_DAC_READ_SEARCH), and kopiur's
16+ # privilegedMode does NOT add caps — so a root mover cannot read non-root /
17+ # mode-600/700 data. The mover MUST run as the data's owner (proven 2026-06-26:
18+ # n8n 1000, gitea 700-dir 1000, mysql 999:568). Ownership also varies within a
19+ # namespace (project-nomad: 1000 / 999:568 / 568), so it can't be uniform here.
20+ # This component injects only the truly-uniform, non-mover fields by kind.
1721#
18- # Why not selector-based (one policy backs up all labeled PVCs)? kopiur's
19- # selector-policy + per-PVC populator-Restore combo is undocumented (0.4.x), so
20- # we use the per-PVC pattern proven by the 2026-06-26 karakeep DR drill.
22+ # Prereqs (once per namespace): label `kopiur.home-operations.com/repo:
23+ # cluster-kopia` (ESO cred fanout + repo tenancy via the ClusterRepository
24+ # allowedNamespaces selector). The privileged-movers namespace annotation is
25+ # only needed for stubs whose mover runs as root (uid 0).
2126patches :
22- # --- SnapshotPolicy: uniform backup config ------------------------- ------
27+ # --- SnapshotPolicy: uniform backup config (mover lives in the stub) ------
2328 - target :
2429 kind : SnapshotPolicy
2530 group : kopiur.home-operations.com
@@ -35,18 +40,6 @@ patches:
3540 value:
3641 kind: ClusterRepository
3742 name: cluster-kopia
38- # Privileged root mover — reads any source ownership and preserves
39- # original UID/GID on restore (the analog of VolSync privileged-movers,
40- # which every backed-up namespace already used). Uniform across apps, so
41- # no per-app UID. Requires the namespace annotation
42- # kopiur.home-operations.com/privileged-movers: "true" (else MoverPermitted=False).
43- - op: add
44- path: /spec/mover
45- value:
46- securityContext:
47- runAsUser: 0
48- runAsNonRoot: false
49- privilegedMode: true
5043 # --- SnapshotSchedule: uniform scheduling --------------------------------
5144 - target :
5245 kind : SnapshotSchedule
@@ -58,7 +51,7 @@ patches:
5851 - op: add
5952 path: /spec/schedule/runOnCreate
6053 value: false
61- # --- Restore: uniform passive-populator config ------------------------- --
54+ # --- Restore: uniform passive-populator config (mover lives in the stub) --
6255 - target :
6356 kind : Restore
6457 group : kopiur.home-operations.com
@@ -76,13 +69,3 @@ patches:
7669 path: /spec/policy
7770 value:
7871 onMissingSnapshot: Continue
79- # Same privileged root mover — restores files with their ORIGINAL owner
80- # (the consumer pod doesn't exist during a cold DR restore, so inherit
81- # can't resolve; privilegedMode chowns to the backed-up UID/GID).
82- - op: add
83- path: /spec/mover
84- value:
85- securityContext:
86- runAsUser: 0
87- runAsNonRoot: false
88- privilegedMode: true
0 commit comments