Skip to content

Field reference

Every spec and status field of all nine CRDs in kopiur.home-operations.com/v1alpha1, with its type, schema default, and a one-line meaning taken straight from the Rust doc comments.

This page is generated from the kopiur-api CRD schemas by cargo xtask gen-docs (run mise run gen); it is drift-checked in CI, so it can never go stale against the shipped CRDs. To change an entry, edit the doc comment on the field in crates/api — not this file. For the task-oriented explanations (mental model, which knobs you actually change), see the per-CRD pages under CRD reference.


Scope: Namespaced · Short names: kopiarepo · Print columns: Phase, Backend, Server, IndexBlobs, Age

Field Type Default Description
backend union required Exactly one storage backend.
encryption object required Repository password (a Secret reference).
bootstrap object — Tuning for the bootstrap/discovery mover Job (<name>-discovery) that connects/creates an object-store repository the operator cannot reach in-process (and re-runs for catalog re-scans).
catalog object — Bounds materialization of origin: discovered Snapshot CRs from the kopia catalog.
concurrency object — Concurrency limits for mover Jobs against this repository (absent = unlimited).
create object — What to do when the repository does not yet exist (absent means it must already exist).
deletionProtection object — Mass-deletion circuit breaker for this repository’s Snapshots.
health object — Repository health thresholds (tunes the index-blob-count warning).
identityDefaults object — Identity defaults (CEL *Expr) applied when consumers don’t override. Set cluster when this repository’s backend is shared across clusters (e.g. one bucket backed up from more than one Kubernetes cluster) — the default kopia identity hostname then becomes <namespace>.<cluster> instead of bare <namespace>, so same-named namespaces on different clusters never collide. Same semantics as ClusterRepository’s field of the same name (ADR-0004 §5); a consumer’s explicit spec.identity still wins over anything here.
maintenance object — Maintenance control; when absent or enabled the reconciler creates and owns a Maintenance CR.
mode enum: ReadWrite | ReadOnly ReadWrite Access mode: ReadWrite (default) or ReadOnly (serves restores only).
moverDefaults object — Base mover configuration inherited by every mover this repository spawns.
onNamespaceDelete enum: Orphan | Delete Orphan What happens to this repository’s snapshots when a consuming namespace is deleted.
parameters object — Mutable kopia repository parameters, re-applied on bootstrap whenever they drift.
scheduleDefaults object — Scheduling defaults (timezone, jitter) inherited by consumers that don’t set their own equivalent field — backup, verification, replication, and maintenance schedules; set once here instead of repeating it on every cron.
seed object — Initialize this repository from an existing replica on its FIRST bootstrap (issue #380) — a disaster-recovery entry point.
Armed only while the repository has never been initialized (status.uniqueId unset) and the mover’s connect reports the backend uninitialized; on an already-initialized repository it is a documented no-op (Seeded=True, reason AlreadyInitialized), so it is safe to leave standing in a GitOps manifest. When armed it also replaces spec.create’s fallback: the repository is seeded or the bootstrap fails, never silently created empty.
server object — Optional kopia web-UI server, exposed via a Service in this namespace.
suspend boolean — Pause this repository: skip connect/bootstrap and maintenance projection.

Validation rules (enforced at admission):

  • create.splitter is immutable after creation
  • create.hash is immutable after creation
  • create.encryption is immutable after creation
  • create.ecc is immutable after creation

Externally tagged — set exactly one of: azure · b2 · filesystem · gcs · gdrive · rclone · s3 · sftp · webDav.

Field Type Default Description
azure object — Azure Blob Storage.
b2 object — Backblaze B2.
filesystem object — A local filesystem path, backed by a PVC the operator mounts into the mover.
gcs object — Google Cloud Storage.
gdrive object — Google Drive via kopia’s native gdrive provider (service-account JSON). kopia marks this provider experimental / not maintained, and a native gdrive repository is not interchangeable with an rclone-backed Drive remote.
rclone object — Any rclone remote (kopia shells out to rclone), broadening reach to providers without a native kopia backend.
s3 object — Amazon S3 or any S3-compatible object store (MinIO, RustFS, Ceph RGW, …).
sftp object — SFTP server.
webDav object — WebDAV endpoint.
Field Type Default Description
container string required Blob container holding the kopia repository.
auth object — Access credentials (Secret ref / workload identity).
prefix string — Blob-name prefix within the container; empty/absent means the container root.
storageAccount string — Storage-account name (when not inferred from credentials).
Field Type Default Description
secretRef object — Secret holding the backend’s static access credentials (mutually exclusive with workloadIdentity).
workloadIdentity object — Use a cloud-federated ServiceAccount instead of static keys (mutually exclusive with secretRef).
Repository spec.backend.azure.auth.secretRef
Section titled “Repository spec.backend.azure.auth.secretRef”
Field Type Default Description
name string required Name of the Secret.
namespace string — Namespace of the Secret; absent = same namespace as the referrer. A ClusterRepository is cluster-scoped and has no namespace of its own, so when IT reads the Secret (to connect, to bootstrap, or to run its repository server) an absent namespace means the operator’s namespace (KOPIUR_NAMESPACE). A workload mover (Snapshot/Restore/Maintenance) still needs the Secret in its OWN namespace — envFrom is namespace-local — so put it there, or use credentialProjection, which needs this namespace set EXPLICITLY to know what to copy. Set it whenever anything other than the operator itself reads the Secret.
Repository spec.backend.azure.auth.workloadIdentity
Section titled “Repository spec.backend.azure.auth.workloadIdentity”
Field Type Default Description
serviceAccountName string required Name of the ServiceAccount the mover pod runs as, resolved in the Job’s own namespace.
Field Type Default Description
bucket string required B2 bucket holding the kopia repository.
auth object — Access credentials (application key ID/key Secret); Secret-only.
prefix string — Object-name prefix within the bucket; empty/absent means the bucket root.
Field Type Default Description
secretRef object — Secret holding the backend’s access credentials, read by well-known keys.
Field Type Default Description
name string required Name of the Secret.
namespace string — Namespace of the Secret; absent = same namespace as the referrer. A ClusterRepository is cluster-scoped and has no namespace of its own, so when IT reads the Secret (to connect, to bootstrap, or to run its repository server) an absent namespace means the operator’s namespace (KOPIUR_NAMESPACE). A workload mover (Snapshot/Restore/Maintenance) still needs the Secret in its OWN namespace — envFrom is namespace-local — so put it there, or use credentialProjection, which needs this namespace set EXPLICITLY to know what to copy. Set it whenever anything other than the operator itself reads the Secret.
Field Type Default Description
path string required Mount path inside the mover pod where kopia writes the repository (e.g. /repo).
volume union — What backs path: a PVC or an inline NFS export; absent for a path already on the node/image.

Externally tagged — set exactly one of: nfs · pvc.

Field Type Default Description
nfs object — An inline NFS export mounted directly (no PVC).
pvc object — A PersistentVolumeClaim mounted read-write at the repo path.
Repository spec.backend.filesystem.volume.nfs
Section titled “Repository spec.backend.filesystem.volume.nfs”
Field Type Default Description
path string required Exported path on the NFS server (e.g. /export/kopia or /mnt/eros/Media).
server string required NFS server hostname or IP (e.g. nas.lan or expanse.internal).
Repository spec.backend.filesystem.volume.pvc
Section titled “Repository spec.backend.filesystem.volume.pvc”
Field Type Default Description
name string required Name of the PersistentVolumeClaim to mount (in the mover’s namespace).
Field Type Default Description
bucket string required GCS bucket holding the kopia repository.
auth object — Access credentials (service-account key Secret / workload identity).
prefix string — Object-name prefix within the bucket; empty/absent means the bucket root.
Field Type Default Description
secretRef object — Secret holding the backend’s static access credentials (mutually exclusive with workloadIdentity).
workloadIdentity object — Use a cloud-federated ServiceAccount instead of static keys (mutually exclusive with secretRef).
Repository spec.backend.gcs.auth.secretRef
Section titled “Repository spec.backend.gcs.auth.secretRef”
Field Type Default Description
name string required Name of the Secret.
namespace string — Namespace of the Secret; absent = same namespace as the referrer. A ClusterRepository is cluster-scoped and has no namespace of its own, so when IT reads the Secret (to connect, to bootstrap, or to run its repository server) an absent namespace means the operator’s namespace (KOPIUR_NAMESPACE). A workload mover (Snapshot/Restore/Maintenance) still needs the Secret in its OWN namespace — envFrom is namespace-local — so put it there, or use credentialProjection, which needs this namespace set EXPLICITLY to know what to copy. Set it whenever anything other than the operator itself reads the Secret.
Repository spec.backend.gcs.auth.workloadIdentity
Section titled “Repository spec.backend.gcs.auth.workloadIdentity”
Field Type Default Description
serviceAccountName string required Name of the ServiceAccount the mover pod runs as, resolved in the Job’s own namespace.
Field Type Default Description
folderId string required Google Drive folder ID that holds the kopia repository.
credentialsSecretRef object — Secret holding the Google service-account JSON used to reach the folder, read by the well-known key KOPIA_GDRIVE_CREDENTIALS. Absent means kopia falls back to ambient credentials (GOOGLE_APPLICATION_CREDENTIALS or instance metadata).
Repository spec.backend.gdrive.credentialsSecretRef
Section titled “Repository spec.backend.gdrive.credentialsSecretRef”
Field Type Default Description
name string required Name of the Secret.
namespace string — Namespace of the Secret; absent = same namespace as the referrer. A ClusterRepository is cluster-scoped and has no namespace of its own, so when IT reads the Secret (to connect, to bootstrap, or to run its repository server) an absent namespace means the operator’s namespace (KOPIUR_NAMESPACE). A workload mover (Snapshot/Restore/Maintenance) still needs the Secret in its OWN namespace — envFrom is namespace-local — so put it there, or use credentialProjection, which needs this namespace set EXPLICITLY to know what to copy. Set it whenever anything other than the operator itself reads the Secret.
Field Type Default Description
remotePath string required rclone path in remote:path form (the remote name must exist in the supplied rclone config).
configSecretRef object — Secret holding the rclone.conf that defines the remote referenced by remote_path.
startupTimeout string — How long kopia waits for its embedded rclone serve to come up before failing the connect, as a Go duration (e.g. 2m). kopia’s default is 15s; raise it for slow remotes whose repository metadata/indexes load through the rclone/WebDAV bridge and take longer than the default budget.
Repository spec.backend.rclone.configSecretRef
Section titled “Repository spec.backend.rclone.configSecretRef”
Field Type Default Description
name string required Name of the Secret.
namespace string — Namespace of the Secret; absent = same namespace as the referrer. A ClusterRepository is cluster-scoped and has no namespace of its own, so when IT reads the Secret (to connect, to bootstrap, or to run its repository server) an absent namespace means the operator’s namespace (KOPIUR_NAMESPACE). A workload mover (Snapshot/Restore/Maintenance) still needs the Secret in its OWN namespace — envFrom is namespace-local — so put it there, or use credentialProjection, which needs this namespace set EXPLICITLY to know what to copy. Set it whenever anything other than the operator itself reads the Secret.
Field Type Default Description
bucket string required Bucket holding the kopia repository.
auth object — Access credentials (Secret ref / workload identity).
endpoint string — S3 endpoint host. Omit for AWS; set it for MinIO/RustFS/other S3-compatible stores.
prefix string — Key prefix under the bucket, letting several repositories share one bucket (e.g. clusters/prod/). Empty/absent means the bucket root.
region string — S3 region. Required by AWS and some compatible providers.
tls object — TLS overrides for self-signed CAs or HTTP-only endpoints.
Field Type Default Description
secretRef object — Secret holding the backend’s static access credentials (mutually exclusive with workloadIdentity).
workloadIdentity object — Use a cloud-federated ServiceAccount instead of static keys (mutually exclusive with secretRef).
Field Type Default Description
name string required Name of the Secret.
namespace string — Namespace of the Secret; absent = same namespace as the referrer. A ClusterRepository is cluster-scoped and has no namespace of its own, so when IT reads the Secret (to connect, to bootstrap, or to run its repository server) an absent namespace means the operator’s namespace (KOPIUR_NAMESPACE). A workload mover (Snapshot/Restore/Maintenance) still needs the Secret in its OWN namespace — envFrom is namespace-local — so put it there, or use credentialProjection, which needs this namespace set EXPLICITLY to know what to copy. Set it whenever anything other than the operator itself reads the Secret.
Repository spec.backend.s3.auth.workloadIdentity
Section titled “Repository spec.backend.s3.auth.workloadIdentity”
Field Type Default Description
serviceAccountName string required Name of the ServiceAccount the mover pod runs as, resolved in the Job’s own namespace.
Field Type Default Description
caBundleRef object — CA bundle (PEM) used to verify the endpoint’s certificate, sourced from a ConfigMap.
disableTls boolean — Disable TLS entirely and talk plain HTTP; maps to kopia’s --disable-tls.
insecureSkipVerify boolean — Skip TLS certificate verification (still uses TLS); maps to kopia’s --disable-tls-verification.
Repository spec.backend.s3.tls.caBundleRef
Section titled “Repository spec.backend.s3.tls.caBundleRef”
Field Type Default Description
configMapName string — Name of the ConfigMap holding the value (e.g. a CA bundle). Resolved in the referrer’s namespace for a namespaced Repository, and in the operator’s namespace (KOPIUR_NAMESPACE) for a ClusterRepository (cluster-scoped, no namespace of its own).
key string — Which key inside the ConfigMap to read; defaults to ca.crt when unset.
Field Type Default Description
host string required SFTP server hostname or IP.
path string required Remote path on the server that holds the kopia repository.
auth object — Credentials (SSH private key / known-hosts) sourced from a Secret; Secret-only.
port integer —
min 0; max 65535
TCP port; defaults to 22 when absent.
username string — SSH username to connect as.
Field Type Default Description
secretRef object — Secret holding the backend’s access credentials, read by well-known keys.
Repository spec.backend.sftp.auth.secretRef
Section titled “Repository spec.backend.sftp.auth.secretRef”
Field Type Default Description
name string required Name of the Secret.
namespace string — Namespace of the Secret; absent = same namespace as the referrer. A ClusterRepository is cluster-scoped and has no namespace of its own, so when IT reads the Secret (to connect, to bootstrap, or to run its repository server) an absent namespace means the operator’s namespace (KOPIUR_NAMESPACE). A workload mover (Snapshot/Restore/Maintenance) still needs the Secret in its OWN namespace — envFrom is namespace-local — so put it there, or use credentialProjection, which needs this namespace set EXPLICITLY to know what to copy. Set it whenever anything other than the operator itself reads the Secret.
Field Type Default Description
url string required WebDAV collection URL holding the kopia repository.
auth object — HTTP basic-auth credentials sourced from a Secret; Secret-only.
Field Type Default Description
secretRef object — Secret holding the backend’s access credentials, read by well-known keys.
Repository spec.backend.webDav.auth.secretRef
Section titled “Repository spec.backend.webDav.auth.secretRef”
Field Type Default Description
name string required Name of the Secret.
namespace string — Namespace of the Secret; absent = same namespace as the referrer. A ClusterRepository is cluster-scoped and has no namespace of its own, so when IT reads the Secret (to connect, to bootstrap, or to run its repository server) an absent namespace means the operator’s namespace (KOPIUR_NAMESPACE). A workload mover (Snapshot/Restore/Maintenance) still needs the Secret in its OWN namespace — envFrom is namespace-local — so put it there, or use credentialProjection, which needs this namespace set EXPLICITLY to know what to copy. Set it whenever anything other than the operator itself reads the Secret.
Field Type Default Description
passwordSecretRef object required Repository password, always a Secret reference (never inline).
Repository spec.encryption.passwordSecretRef
Section titled “Repository spec.encryption.passwordSecretRef”
Field Type Default Description
name string required Name of the Secret.
key string — Which key inside the Secret to read.
namespace string — Namespace of the Secret; absent = same namespace as the referrer. A ClusterRepository is cluster-scoped and has no namespace of its own, so when IT reads the Secret (to connect, to bootstrap, or to run its repository server) an absent namespace means the operator’s namespace (KOPIUR_NAMESPACE). A workload mover (Snapshot/Restore/Maintenance) still needs the Secret in its OWN namespace — envFrom is namespace-local — so put it there, or use credentialProjection, which needs this namespace set EXPLICITLY to know what to copy. Set it whenever anything other than the operator itself reads the Secret.
Field Type Default Description
failurePolicy object — Failure policy for the bootstrap Job. activeDeadlineSeconds caps how long a connect may run before the Job is marked failed (default 120s); raise it for a slow backend — e.g. an rclone remote whose repository metadata and indexes load through kopia’s embedded rclone serve/WebDAV bridge, or a large repository whose cold-cache connect outgrows the default. The value is a BASE, not a ceiling: after consecutive deadline-killed attempts the operator escalates the effective deadline itself (doubling per attempt, up to 30 minutes or the configured value, whichever is larger — never below it), so a slow-but-alive backend self-heals without a spec edit. backoffLimit bounds retries. podStartupDeadlineSeconds is accepted for shape parity but is not honored by the bootstrap Job.
Field Type Default Description
activeDeadlineSeconds integer — Mover Job.spec.activeDeadlineSeconds — wall-clock cap after which a running run is killed.
backoffLimit integer — Mover Job.spec.backoffLimit — retries before a failed run is marked failed.
podStartupDeadlineSeconds integer — Seconds a non-starting (wedged) mover pod may sit before the run is failed; default 300s.
Field Type Default Description
adoption enum: Adopt | Ignore — Whether a discovered snapshot whose resolved identity matches a live SnapshotPolicy is automatically adopted — re-attached (stamped with that policy’s config label, status.origin flipped to Adopted) so GFS retention governs it and eventually prunes it, instead of it sitting in the catalog forever as an immortal discovered row.
fallbackNamespace string — Where to materialize discovered Snapshots with no allowed-namespace mapping (ClusterRepository only).
foreignSnapshots enum: Ignore | Fallback — How catalog discovery treats snapshots written by ANOTHER cluster. status.catalog.foreignSnapshotCount counts an identity hostname carrying a different .<cluster> suffix ALWAYS, under either value below, plus — under Ignore only — a bare hostname naming no allowed namespace here. Under Fallback, that same disallowed bare host is NOT counted foreign: it materializes into catalog.fallbackNamespace exactly like a disallowed OwnCluster host would, so it is placed rather than dropped-and-counted (see classify_hostname/decide_cluster_placement). Meaningful only when identityDefaults.cluster is set: without a cluster identity there is no notion of “foreign” and the legacy hostname-names-a-namespace placement applies (validators enforce this).
periodicRefresh boolean — Opt-in: periodically re-scan the repository to keep discovered Snapshot CRs current (re-list snapshots; for object-store / volume-backed repos this recycles the <name>-discovery mover Job every refreshInterval). Off by default — the repository still bootstraps once, re-bootstraps on a spec change, and re-probes on a backup failure, but does not re-run on a timer. Enable it if you rely on discovered snapshots reflecting changes made outside this operator.
refreshInterval string 1h How often to re-scan when periodicRefresh: true (Go-style duration; minimum 30s, default 1h). Inert unless periodicRefresh is enabled.
retain object — How many discovered Snapshot CRs to keep materialized (bounds etcd footprint).
Field Type Default Description
maxAgeDays integer — Expire discovered Snapshot CRs older than this many days (minimum 1); kopia snapshots untouched.
perIdentity integer — Keep the most-recent N discovered Snapshot CRs per identity; 0 disables materialization.
Field Type Default Description
maxConcurrentDeleteJobs integer —
min 1
Ceiling on how many snapshot-delete batch Jobs may run against this repository at once. Absent means 1: one batch at a time, and the next batch starts when the current one finishes.
A batch Job deletes hundreds of snapshots in a single kopia call. kopia serializes manifest deletes on the repository’s index anyway, so running several batches in parallel adds no throughput. Each extra Job only loads the full index again against the same backend (issue #477). Raise it only for a fast local backend with a very large deletion backlog.
Must be at least 1. There is no “unlimited” value. Omit the field for the default. The controller-wide maxConcurrentDeleteJobs Helm value still caps delete Jobs across ALL repositories on top of this.
No schema default: is emitted (api-conventions §4a); the controller resolves absent to 1, so stored repositories carry no diff noise.
maxConcurrentJobs integer —
min 0
Ceiling on how many of this repository’s mover Jobs may be in flight at once. Backup snapshots, restores, and replication runs that READ FROM this repository all draw from ONE pool — a repository’s backend (and the bandwidth to it) is the shared resource, so splitting the budget per work kind would let three “safe” limits still saturate it.
Restores are always admitted and never parked: a restore is a recovery in progress, and holding one behind a queue of routine backups is exactly backwards. An in-flight restore still COUNTS toward the pool, so it displaces backups rather than adding to them.
Excluded from the pool entirely: maintenance (already single-flight per repository), verification, pin, and snapshot-delete batch Jobs. These are operator-driven housekeeping that must not be starved by a saturated backup pool. Delete batches have their own cap, maxConcurrentDeleteJobs.
Absent or 0 means unlimited — the default, and today’s behavior.
No schema default: is emitted for this field (api-conventions §4a): absent and 0 are the SAME state (unlimited), so a materialized default would stamp {maxConcurrentJobs: 0} onto every stored repository — GitOps diff noise for a value that changes nothing.
Field Type Default Description
ecc object — Reed-Solomon ECC parity for a freshly-created repository (creation-time only, immutable after).
enabled boolean true Create the repository if it does not exist yet — on by default. Repository create/connect is idempotent: pointing create at an already-initialized repository just connects to it (it never re-creates or clobbers), so the only effect of the default is that a genuinely-absent repository is bootstrapped instead of erroring. Set false for a strictly read-only or externally-managed repository the operator must never create.
encryption string — kopia encryption algorithm for a freshly-created repository (creation-time only).
hash string — kopia content hash algorithm for a freshly-created repository (creation-time only).
splitter string — kopia object splitter for a freshly-created repository (creation-time only).
Field Type Default Description
algorithm string — ECC algorithm, e.g. REED-SOLOMON-CRC32 (--ecc).
overheadPercent integer — Parity overhead as a percentage (--ecc-overhead-percent).
Field Type Default Description
threshold integer 10
min 0
Pending EXTERNAL destructive Snapshot deletions (deletionTimestamp set, effective deletionPolicy Delete, not operator-pruned) that trip the breaker for this repository: at or above this, those deletions are HELD (finalizers wait) until acknowledged via the kopiur.home-operations.com/allow-mass-deletion annotation. 0 disables the breaker. Default 10.
Field Type Default Description
indexBlobWarnThreshold integer 1000 Index-blob count above which the reconciler raises the IndexBlobHealth warning (0 disables).
probe object — Periodic backend health probe (on by default): re-connect the repository on a timer to confirm the kopia repository still exists at the backend. With the default onFailure: Degrade it doubles as the repository circuit breaker — see probe.onFailure. Disable with probe.enabled: false.
Field Type Default Description
enabled boolean true Whether the probe runs (default true). false disables probing — and with it the circuit breaker, since the probe is its only sensor: a wiped or unreachable backend then goes unnoticed until the next backup fails.
failureThreshold integer 3 How many consecutive failing probes to require before the failure is acted on (default 3): the loud BackendReachable=False condition + event fire, and — under onFailure: Degrade — the repository moves to Degraded. Debounces a single transient blip from alarming, tripping the breaker, or nudging a destructive manual recreate. Any success resets it.
interval string 30m How often to re-probe the backend (Go-style duration like 30m or 1h; minimum 30s, default 30m). Inert when enabled: false.
onFailure enum: Degrade | Alert Degrade What sustained backend-probe failure (past failureThreshold) does to the repository (default Degrade). Degrade moves it to Degraded, pausing backups and replication until a re-connect succeeds — recovery is automatic (maintenance also pauses for a confirmed-unreachable/vanished backend, but keeps running for a probe deadline kill, where index compaction is often the cure). Alert keeps the repository Ready and only raises the BackendReachable condition + Warning event + metric; backups keep running against the failing backend. Neither ever auto-recreates.
Field Type Default Description
cluster string — This cluster’s identity suffix for repositories shared across clusters (an RFC 1123 label, at most 32 characters; dots are rejected — the first . in a hostname is the namespace/cluster delimiter). When set, the default kopia identity hostname becomes <namespace>.<cluster> instead of <namespace>, so two clusters backing up same-named namespaces write distinct identities (and one cluster’s retention prune can no longer touch the other’s snapshots). Also exposed to hostnameExpr/ usernameExpr as the CEL variable cluster.
hostnameExpr string — CEL expression for the kopia identity hostname (e.g. "namespace").
usernameExpr string — CEL expression for the kopia identity username (e.g. "namespace + '-' + policyName").
Field Type Default Description
enabled boolean true Whether the operator manages a Maintenance CR for this repository (default true).
failurePolicy object — Failure handling (backoff/deadline) for the managed Maintenance run.
mover object — Mover overrides for the managed Maintenance.
namespace string — ClusterRepository only: namespace the managed Maintenance CR is created in (default the operator’s namespace).
schedule object — Schedule override; absent uses the default quick-6h / full-daily schedule.
takeoverPolicy enum: Never | PromptCondition | Force — What to do when another owner already holds the lease. Defaults to Never (the safest: never seize a lease another owner holds).
Field Type Default Description
activeDeadlineSeconds integer — Mover Job.spec.activeDeadlineSeconds — wall-clock cap after which a running run is killed.
backoffLimit integer — Mover Job.spec.backoffLimit — retries before a failed run is marked failed.
podStartupDeadlineSeconds integer — Seconds a non-starting (wedged) mover pod may sit before the run is failed; default 300s.
Field Type Default Description
cache object — Override the repository’s CacheDefaults for this recipe’s movers.
inheritSecurityContextFrom union — Copy the UID/GID security context from a live workload rather than hard-coding it.
Requires the workload to pin runAsUser (container or pod level): a UID that comes from the container image’s USER line is invisible in the pod spec and cannot be inherited — the mover would silently run as its own image’s UID instead.
May be combined with securityContext/podSecurityContext, which override it field-wise and act as the fallback when no workload pod can be resolved.
podSecurityContext core/v1 PodSecurityContext — Pod security context for the mover (notably fsGroup for group-writable restore volumes). Same layering as securityContext: highest layer, merged field-wise, and combinable with inheritSecurityContextFrom.
privilegedMode boolean — Opt-in, namespace-gated privileged mode. Never changes the UID. When the mover runs as root (runAsUser: 0), adds the capabilities the operation needs on top of drop: ALL: DAC_OVERRIDE for a backup (read files owned by any uid/gid); CHOWN, DAC_OVERRIDE, FOWNER, FSETID for a restore (reproduce original ownership). Grants nothing for maintenance, or when the mover does not run as root (capabilities are inert for non-root); set runAsUser: 0 yourself.
resources core/v1 ResourceRequirements — Resource requests/limits for the mover container.
securityContext core/v1 SecurityContext — Container security context for the mover; merged field-wise over the hardened base, moverDefaults, and any inherited context — this is the highest layer, so every field set here wins. Combines with inheritSecurityContextFrom: fields you set override the workload’s, fields you omit are inherited, and this context stands in alone when inheritance cannot resolve a pod.
ttlSecondsAfterFinished integer — Per-recipe override of Job.spec.ttlSecondsAfterFinished so finished Jobs self-GC.
Field Type Default Description
capacity string — Size of the PVC backing the mover’s kopia cache (e.g. 10Gi).
contentCacheSizeMb integer — kopia content cache budget in MiB (--content-cache-size-mb).
metadataCacheSizeMb integer — kopia metadata cache budget in MiB (--metadata-cache-size-mb).
mode enum: Ephemeral | Persistent — How a mover’s kopia cache volume is provisioned.
storageClassName string — StorageClass for the cache PVC; absent uses the cluster default.
Repository spec.maintenance.mover.inheritSecurityContextFrom
Section titled “Repository spec.maintenance.mover.inheritSecurityContextFrom”

Externally tagged — set exactly one of: pvcConsumer · snapshot · workloadSelector.

Field Type Default Description
pvcConsumer object — Backup sources only: auto-derive the workload from the PVC this snapshot backs up.
snapshot object — Restores only: inherit the identity RECORDED on the backup itself (Snapshot.status.recorded, decoded from the kopiur-meta kopia tag) — uid/gid/fsGroup the backup mover actually ran as. Needs no live workload pod, so it works on a rebuilt cluster and with target.populator. Rejected at admission on SnapshotPolicy/Maintenance (backups read the live workload; maintenance has no snapshot). Write it as snapshot: {} (an empty sub-object) — a bare snapshot: is null and rejected.
workloadSelector object — Inherit from workload pod(s) matched by an explicit label selector (backup or restore).
Repository spec.maintenance.mover.inheritSecurityContextFrom.pvcConsumer
Section titled “Repository spec.maintenance.mover.inheritSecurityContextFrom.pvcConsumer”
Field Type Default Description
container string — Which container within the matched consumer pod to inherit from; absent uses the first/only.
Repository spec.maintenance.mover.inheritSecurityContextFrom.workloadSelector
Section titled “Repository spec.maintenance.mover.inheritSecurityContextFrom.workloadSelector”
Field Type Default Description
podSelector core/v1 LabelSelector required Label selector matching the workload pod(s) to read context/hooks from.
container string — Which container within the matched pod; absent uses the first/only container.
Field Type Default Description
full object required Cron and jitter for kopia maintenance run --full (content reclamation).
quick object required Cron and jitter for kopia maintenance run (quick, cheap index/log work).
timezone string — IANA timezone both crons are evaluated in; absent means the controller default.
Field Type Default Description
cron string required The cron expression, parsed by croner; may contain an H placeholder for deterministic jitter.
jitter string — Optional deterministic jitter window as a Go-style duration string (e.g. 30m).
timezone string — IANA timezone the cron is evaluated in (e.g. America/Chicago); absent uses the enclosing schedule’s timezone, else the controller default (UTC).
Repository spec.maintenance.schedule.quick
Section titled “Repository spec.maintenance.schedule.quick”
Field Type Default Description
cron string required The cron expression, parsed by croner; may contain an H placeholder for deterministic jitter.
jitter string — Optional deterministic jitter window as a Go-style duration string (e.g. 30m).
timezone string — IANA timezone the cron is evaluated in (e.g. America/Chicago); absent uses the enclosing schedule’s timezone, else the controller default (UTC).
Field Type Default Description
affinity core/v1 Affinity — Pod affinity for every mover.
cache object — kopia cache defaults for every mover.
nodeSelector map[string]string — Pod nodeSelector for every mover.
podAnnotations map[string]string — Extra annotations for every mover pod. Unlike podLabels these are pod-template-only — they are not mirrored onto the Job object, because the common case is a sidecar-injection opt-out (sidecar.istio.io/inject: "false", linkerd.io/inject: disabled, vault.hashicorp.com/agent-inject: "false") that only means anything on the pod a mesh webhook actually sees. A mover is a short-lived batch pod; an injected sidecar that never exits keeps its Job running forever.
Same reserved keys as podLabels, rejected at admission.
podLabels map[string]string — Extra labels for every mover POD (and the Job that owns it), merged UNDER kopiur’s own labels — a key kopiur sets always wins, so a user-supplied value can never break the selectors the controller counts and reaps by.
This is the hook for cluster machinery that keys off pod labels and that kopiur has no field of its own for: a Kueue kueue.x-k8s.io/queue-name to put movers under a cluster queue, a monitoring/NetworkPolicy selector, a service-mesh exclusion label.
Keys under kopiur.home-operations.com/ and the exact key app.kubernetes.io/managed-by are reserved and rejected at admission.
podSecurityContext core/v1 PodSecurityContext — Pod security-context base (notably fsGroup) for every mover.
resources core/v1 ResourceRequirements — Resource requests/limits base for the mover container.
scratch object — Defaults for the deep-verification scratch (restore-test) volume.
securityContext core/v1 SecurityContext — Container security-context base for every mover.
sourceColocation object — How a mover co-locates with its RWO PVC’s node; defaults to SourceColocationMode::Auto.
throttle object — Repository throttle limits applied by every mover after it connects.
tolerations []core/v1 Toleration — Pod tolerations for every mover.
ttlSecondsAfterFinished integer — Job.spec.ttlSecondsAfterFinished for every mover Job so finished Jobs self-GC.
Field Type Default Description
capacity string — Size of the PVC backing the mover’s kopia cache (e.g. 10Gi).
contentCacheSizeMb integer — kopia content cache budget in MiB (--content-cache-size-mb).
metadataCacheSizeMb integer — kopia metadata cache budget in MiB (--metadata-cache-size-mb).
mode enum: Ephemeral | Persistent — How a mover’s kopia cache volume is provisioned.
storageClassName string — StorageClass for the cache PVC; absent uses the cluster default.
Field Type Default Description
capacity string — Size of the ephemeral scratch PVC (e.g. 100Gi); absent falls back to an emptyDir.
storageClassName string — StorageClass for the ephemeral scratch PVC; only applies when capacity is set.
Repository spec.moverDefaults.sourceColocation
Section titled “Repository spec.moverDefaults.sourceColocation”
Field Type Default Description
mode enum: Auto | Required | Disabled — How the mover co-locates with the node an RWO source/destination PVC is attached to.
Field Type Default Description
downloadBytesPerSecond integer — Cap download throughput in bytes/sec (--download-bytes-per-second).
readOpsPerSecond integer — Cap read/list ops/sec (--read-requests-per-second).
uploadBytesPerSecond integer — Cap upload throughput in bytes/sec (--upload-bytes-per-second).
writeOpsPerSecond integer — Cap write ops/sec (--write-requests-per-second).
Field Type Default Description
blobRetention union — Object-lock blob retention (S3/Azure/GCS) — ransomware protection. Absent means “don’t touch it”; use disabled: true to actively turn it off.
epoch object — Epoch-manager tuning — how fast kopia closes epochs and therefore how fast index blobs get compacted.

Externally tagged — set exactly one of: compliance · disabled · governance.

Field Type Default Description
compliance object — COMPLIANCE — nobody can shorten or remove the lock before it expires, including the account root. An oversized period is an unfixable storage-cost commitment; there is no recovery path short of deleting the bucket after expiry.
disabled boolean — Actively disable retention (--retention-mode=none). Must be true.
A bool rather than a unit variant because an externally-tagged unit variant serializes as the bare string "Disabled", mixing string and object forms in one oneOf and breaking the structural schema. Same shape, and same reason, as AllowedNamespaces::All.
This is distinct from omitting blobRetention entirely: absent means “leave the repository alone”, so deleting the block from a manifest can never silently strip ransomware protection someone configured deliberately.
governance object — GOVERNANCE — locked against ordinary deletes, but a sufficiently privileged identity can still shorten or remove the lock. The safe default for most clusters.
Repository spec.parameters.blobRetention.compliance
Section titled “Repository spec.parameters.blobRetention.compliance”
Field Type Default Description
period string required Go-style duration; kopia’s minimum is 24h and there is no maximum.
Accepts h/m/s (or a bare number of seconds) — not d. Note that kopia’s own CLI does take 30d, so a period copied from kopia’s documentation is rejected here; write 30 days as 720h. Kopiur deliberately keeps one duration grammar across every CRD field rather than matching kopia’s per-flag variations.
Repository spec.parameters.blobRetention.governance
Section titled “Repository spec.parameters.blobRetention.governance”
Field Type Default Description
period string required Go-style duration; kopia’s minimum is 24h and there is no maximum.
Accepts h/m/s (or a bare number of seconds) — not d. Note that kopia’s own CLI does take 30d, so a period copied from kopia’s documentation is rejected here; write 30 days as 720h. Kopiur deliberately keeps one duration grammar across every CRD field rather than matching kopia’s per-flag variations.
Field Type Default Description
advanceOnCount integer — Index blobs in an epoch that trigger an advance, once older than minDuration (kopia default 20).
At least 10 — kopia refuses anything lower with “epoch advance on count too low”.
advanceOnSizeMiB integer — Total index size in an epoch that triggers an advance, once older than minDuration (kopia default 10 MiB).
At least 1 — kopia refuses anything lower with “epoch advance on size too low”, and 1 MiB is the smallest threshold the flag can express.
Named MiB, not MB, with an explicit rename rather than the derived camelCase (advanceOnSizeMb, which reads as megabit). The unit is genuinely mebibytes — kopia’s --epoch-advance-on-size-mb multiplies by 1048576, so 10 is 10485760 bytes — even though kopia’s own log renders the result as “MB”. That ambiguity is this field’s main hazard; the API surface should not reproduce it.
checkpointFrequency integer — Epochs between full index checkpoints (kopia default 7).
At least 1 — kopia refuses anything lower with “invalid epoch range compaction period”.
deleteParallelism integer — Parallelism for epoch cleanup deletions (kopia default 4).
At least 1. This floor is kopiur’s own: kopia does not validate the field, so a non-positive value would ask it to run epoch cleanup with no workers.
minDuration string — Minimum epoch age before it may advance (kopia default 24h). A Go-style duration (6h, 90m). The advance gate — no blob count closes an epoch younger than this.
Must be at least 10m (kopia’s absolute floor) AND at least 3x refreshFrequency. When refreshFrequency is not declared, that second bound is measured against kopia’s untouched 20m default, so 10m on its own is rejected: use 60m, or declare a refreshFrequency of a third of it or less alongside it.
refreshFrequency string — How often clients re-read epoch state (kopia default 20m). Go-style duration.
At most 80m: kopia requires cleanupSafetyMargin >= 3x this value, and cleanupSafetyMargin is observable-but-not-settable here, so it stays at kopia’s 4h default and 4h / 3 is a hard ceiling.
Field Type Default Description
jitter string — Deterministic jitter window (Go-style duration, e.g. 10m) applied to every consuming cron that doesn’t set its own jitter — SnapshotSchedule, Maintenance (quick and full), SnapshotPolicy verification (quick and deep), and both replication kinds. Set once here instead of repeating it on every cron, so a whole repository’s schedules spread their load off the top-of-the-hour thundering herd.
The spread is deterministic per (scheduleUID, slot), not random: the same slot always lands on the same instant, so a restart never re-rolls it. Capped at 24h by validation — jitter is a spread WITHIN a cron period, not a schedule offset.
timezone string — IANA timezone name applied to every consuming cron that doesn’t set its own timezone (e.g. America/New_York). Set once here instead of repeating it on every SnapshotPolicy.verification, RepositoryReplication.schedule, and Maintenance.schedule cron.
Field Type Default Description
from union required Where the seed data comes from: exactly one of a bare storage backend (blob mode) or another repository CR (migrate mode).
allowEmptySource boolean — Accept a source that holds zero snapshots (default false).
A mirror that answers but is empty is almost always a mis-pointed bucket/prefix, and silently seeding nothing would hand you a Ready repository with no history — the failure mode #380 is about. By default the bootstrap fails loudly and retries; set this when an empty source is genuinely expected (e.g. re-homing a repository whose history was deliberately pruned to nothing).
credentialProjection object — Opt-in projection of the SOURCE repository’s credential Secrets into the seeding mover Job’s namespace. Migrate mode only in practice — a blob-mode source’s credentials must already be in the namespace the bootstrap Job runs in (this CR’s own namespace for a Repository; for a ClusterRepository the operator’s namespace, unless encryption.passwordSecretRef.namespace pins another, in which case the Job runs there). Requires the operator’s features.credentialProjection install flag.
failurePolicy object — Deadline/backoff for the seeding bootstrap Job. An absent activeDeadlineSeconds means 24h here, rather than the 120s a routine connect gets — a seed copies a whole repository, once. Only applied while the seed is armed; later connects to the now-initialized repository use spec.bootstrap.failurePolicy as before.
migrate object — Tuning for the kopia snapshot migrate copy. Migrate mode only (from.repository); rejected at admission alongside from.backend.
sync object — Tuning for the kopia repository sync-to blob copy. Blob mode only (from.backend); rejected at admission alongside from.repository.

Externally tagged — set exactly one of: backend · repository.

Field Type Default Description
backend union — A bare storage backend holding a byte-for-byte mirror of a kopia repository (blob mode, kopia repository sync-to). The mirror’s format and encryption password are inherited verbatim, so this repository’s encryption.passwordSecretRef must already hold the MIRROR’s password and spec.create’s format knobs are refused as inert.
repository object — Another Repository/ClusterRepository, opened read-only (migrate mode, kopia snapshot migrate). Snapshot identities and times are preserved, so seeded history is restorable by identity/fromPolicy.
A kind: Repository reference with no namespace resolves in the referrer’s own namespace — and, on a cluster-scoped ClusterRepository (which has none), in the operator’s namespace, the same rule its credential secretRefs follow. Set namespace explicitly whenever the source lives anywhere else.

Externally tagged — set exactly one of: azure · b2 · filesystem · gcs · gdrive · rclone · s3 · sftp · webDav.

Field Type Default Description
azure object — Azure Blob Storage.
b2 object — Backblaze B2.
filesystem object — A local filesystem path, backed by a PVC the operator mounts into the mover.
gcs object — Google Cloud Storage.
gdrive object — Google Drive via kopia’s native gdrive provider (service-account JSON). kopia marks this provider experimental / not maintained, and a native gdrive repository is not interchangeable with an rclone-backed Drive remote.
rclone object — Any rclone remote (kopia shells out to rclone), broadening reach to providers without a native kopia backend.
s3 object — Amazon S3 or any S3-compatible object store (MinIO, RustFS, Ceph RGW, …).
sftp object — SFTP server.
webDav object — WebDAV endpoint.
Field Type Default Description
container string required Blob container holding the kopia repository.
auth object — Access credentials (Secret ref / workload identity).
prefix string — Blob-name prefix within the container; empty/absent means the container root.
storageAccount string — Storage-account name (when not inferred from credentials).
Repository spec.seed.from.backend.azure.auth
Section titled “Repository spec.seed.from.backend.azure.auth”
Field Type Default Description
secretRef object — Secret holding the backend’s static access credentials (mutually exclusive with workloadIdentity).
workloadIdentity object — Use a cloud-federated ServiceAccount instead of static keys (mutually exclusive with secretRef).
Repository spec.seed.from.backend.azure.auth.secretRef
Section titled “Repository spec.seed.from.backend.azure.auth.secretRef”
Field Type Default Description
name string required Name of the Secret.
namespace string — Namespace of the Secret; absent = same namespace as the referrer. A ClusterRepository is cluster-scoped and has no namespace of its own, so when IT reads the Secret (to connect, to bootstrap, or to run its repository server) an absent namespace means the operator’s namespace (KOPIUR_NAMESPACE). A workload mover (Snapshot/Restore/Maintenance) still needs the Secret in its OWN namespace — envFrom is namespace-local — so put it there, or use credentialProjection, which needs this namespace set EXPLICITLY to know what to copy. Set it whenever anything other than the operator itself reads the Secret.
Repository spec.seed.from.backend.azure.auth.workloadIdentity
Section titled “Repository spec.seed.from.backend.azure.auth.workloadIdentity”
Field Type Default Description
serviceAccountName string required Name of the ServiceAccount the mover pod runs as, resolved in the Job’s own namespace.
Field Type Default Description
bucket string required B2 bucket holding the kopia repository.
auth object — Access credentials (application key ID/key Secret); Secret-only.
prefix string — Object-name prefix within the bucket; empty/absent means the bucket root.
Field Type Default Description
secretRef object — Secret holding the backend’s access credentials, read by well-known keys.
Repository spec.seed.from.backend.b2.auth.secretRef
Section titled “Repository spec.seed.from.backend.b2.auth.secretRef”
Field Type Default Description
name string required Name of the Secret.
namespace string — Namespace of the Secret; absent = same namespace as the referrer. A ClusterRepository is cluster-scoped and has no namespace of its own, so when IT reads the Secret (to connect, to bootstrap, or to run its repository server) an absent namespace means the operator’s namespace (KOPIUR_NAMESPACE). A workload mover (Snapshot/Restore/Maintenance) still needs the Secret in its OWN namespace — envFrom is namespace-local — so put it there, or use credentialProjection, which needs this namespace set EXPLICITLY to know what to copy. Set it whenever anything other than the operator itself reads the Secret.
Repository spec.seed.from.backend.filesystem
Section titled “Repository spec.seed.from.backend.filesystem”
Field Type Default Description
path string required Mount path inside the mover pod where kopia writes the repository (e.g. /repo).
volume union — What backs path: a PVC or an inline NFS export; absent for a path already on the node/image.
Repository spec.seed.from.backend.filesystem.volume
Section titled “Repository spec.seed.from.backend.filesystem.volume”

Externally tagged — set exactly one of: nfs · pvc.

Field Type Default Description
nfs object — An inline NFS export mounted directly (no PVC).
pvc object — A PersistentVolumeClaim mounted read-write at the repo path.
Repository spec.seed.from.backend.filesystem.volume.nfs
Section titled “Repository spec.seed.from.backend.filesystem.volume.nfs”
Field Type Default Description
path string required Exported path on the NFS server (e.g. /export/kopia or /mnt/eros/Media).
server string required NFS server hostname or IP (e.g. nas.lan or expanse.internal).
Repository spec.seed.from.backend.filesystem.volume.pvc
Section titled “Repository spec.seed.from.backend.filesystem.volume.pvc”
Field Type Default Description
name string required Name of the PersistentVolumeClaim to mount (in the mover’s namespace).
Field Type Default Description
bucket string required GCS bucket holding the kopia repository.
auth object — Access credentials (service-account key Secret / workload identity).
prefix string — Object-name prefix within the bucket; empty/absent means the bucket root.
Repository spec.seed.from.backend.gcs.auth
Section titled “Repository spec.seed.from.backend.gcs.auth”
Field Type Default Description
secretRef object — Secret holding the backend’s static access credentials (mutually exclusive with workloadIdentity).
workloadIdentity object — Use a cloud-federated ServiceAccount instead of static keys (mutually exclusive with secretRef).
Repository spec.seed.from.backend.gcs.auth.secretRef
Section titled “Repository spec.seed.from.backend.gcs.auth.secretRef”
Field Type Default Description
name string required Name of the Secret.
namespace string — Namespace of the Secret; absent = same namespace as the referrer. A ClusterRepository is cluster-scoped and has no namespace of its own, so when IT reads the Secret (to connect, to bootstrap, or to run its repository server) an absent namespace means the operator’s namespace (KOPIUR_NAMESPACE). A workload mover (Snapshot/Restore/Maintenance) still needs the Secret in its OWN namespace — envFrom is namespace-local — so put it there, or use credentialProjection, which needs this namespace set EXPLICITLY to know what to copy. Set it whenever anything other than the operator itself reads the Secret.
Repository spec.seed.from.backend.gcs.auth.workloadIdentity
Section titled “Repository spec.seed.from.backend.gcs.auth.workloadIdentity”
Field Type Default Description
serviceAccountName string required Name of the ServiceAccount the mover pod runs as, resolved in the Job’s own namespace.
Field Type Default Description
folderId string required Google Drive folder ID that holds the kopia repository.
credentialsSecretRef object — Secret holding the Google service-account JSON used to reach the folder, read by the well-known key KOPIA_GDRIVE_CREDENTIALS. Absent means kopia falls back to ambient credentials (GOOGLE_APPLICATION_CREDENTIALS or instance metadata).
Repository spec.seed.from.backend.gdrive.credentialsSecretRef
Section titled “Repository spec.seed.from.backend.gdrive.credentialsSecretRef”
Field Type Default Description
name string required Name of the Secret.
namespace string — Namespace of the Secret; absent = same namespace as the referrer. A ClusterRepository is cluster-scoped and has no namespace of its own, so when IT reads the Secret (to connect, to bootstrap, or to run its repository server) an absent namespace means the operator’s namespace (KOPIUR_NAMESPACE). A workload mover (Snapshot/Restore/Maintenance) still needs the Secret in its OWN namespace — envFrom is namespace-local — so put it there, or use credentialProjection, which needs this namespace set EXPLICITLY to know what to copy. Set it whenever anything other than the operator itself reads the Secret.
Field Type Default Description
remotePath string required rclone path in remote:path form (the remote name must exist in the supplied rclone config).
configSecretRef object — Secret holding the rclone.conf that defines the remote referenced by remote_path.
startupTimeout string — How long kopia waits for its embedded rclone serve to come up before failing the connect, as a Go duration (e.g. 2m). kopia’s default is 15s; raise it for slow remotes whose repository metadata/indexes load through the rclone/WebDAV bridge and take longer than the default budget.
Repository spec.seed.from.backend.rclone.configSecretRef
Section titled “Repository spec.seed.from.backend.rclone.configSecretRef”
Field Type Default Description
name string required Name of the Secret.
namespace string — Namespace of the Secret; absent = same namespace as the referrer. A ClusterRepository is cluster-scoped and has no namespace of its own, so when IT reads the Secret (to connect, to bootstrap, or to run its repository server) an absent namespace means the operator’s namespace (KOPIUR_NAMESPACE). A workload mover (Snapshot/Restore/Maintenance) still needs the Secret in its OWN namespace — envFrom is namespace-local — so put it there, or use credentialProjection, which needs this namespace set EXPLICITLY to know what to copy. Set it whenever anything other than the operator itself reads the Secret.
Field Type Default Description
bucket string required Bucket holding the kopia repository.
auth object — Access credentials (Secret ref / workload identity).
endpoint string — S3 endpoint host. Omit for AWS; set it for MinIO/RustFS/other S3-compatible stores.
prefix string — Key prefix under the bucket, letting several repositories share one bucket (e.g. clusters/prod/). Empty/absent means the bucket root.
region string — S3 region. Required by AWS and some compatible providers.
tls object — TLS overrides for self-signed CAs or HTTP-only endpoints.
Field Type Default Description
secretRef object — Secret holding the backend’s static access credentials (mutually exclusive with workloadIdentity).
workloadIdentity object — Use a cloud-federated ServiceAccount instead of static keys (mutually exclusive with secretRef).
Repository spec.seed.from.backend.s3.auth.secretRef
Section titled “Repository spec.seed.from.backend.s3.auth.secretRef”
Field Type Default Description
name string required Name of the Secret.
namespace string — Namespace of the Secret; absent = same namespace as the referrer. A ClusterRepository is cluster-scoped and has no namespace of its own, so when IT reads the Secret (to connect, to bootstrap, or to run its repository server) an absent namespace means the operator’s namespace (KOPIUR_NAMESPACE). A workload mover (Snapshot/Restore/Maintenance) still needs the Secret in its OWN namespace — envFrom is namespace-local — so put it there, or use credentialProjection, which needs this namespace set EXPLICITLY to know what to copy. Set it whenever anything other than the operator itself reads the Secret.
Repository spec.seed.from.backend.s3.auth.workloadIdentity
Section titled “Repository spec.seed.from.backend.s3.auth.workloadIdentity”
Field Type Default Description
serviceAccountName string required Name of the ServiceAccount the mover pod runs as, resolved in the Job’s own namespace.
Field Type Default Description
caBundleRef object — CA bundle (PEM) used to verify the endpoint’s certificate, sourced from a ConfigMap.
disableTls boolean — Disable TLS entirely and talk plain HTTP; maps to kopia’s --disable-tls.
insecureSkipVerify boolean — Skip TLS certificate verification (still uses TLS); maps to kopia’s --disable-tls-verification.
Repository spec.seed.from.backend.s3.tls.caBundleRef
Section titled “Repository spec.seed.from.backend.s3.tls.caBundleRef”
Field Type Default Description
configMapName string — Name of the ConfigMap holding the value (e.g. a CA bundle). Resolved in the referrer’s namespace for a namespaced Repository, and in the operator’s namespace (KOPIUR_NAMESPACE) for a ClusterRepository (cluster-scoped, no namespace of its own).
key string — Which key inside the ConfigMap to read; defaults to ca.crt when unset.
Field Type Default Description
host string required SFTP server hostname or IP.
path string required Remote path on the server that holds the kopia repository.
auth object — Credentials (SSH private key / known-hosts) sourced from a Secret; Secret-only.
port integer —
min 0; max 65535
TCP port; defaults to 22 when absent.
username string — SSH username to connect as.
Repository spec.seed.from.backend.sftp.auth
Section titled “Repository spec.seed.from.backend.sftp.auth”
Field Type Default Description
secretRef object — Secret holding the backend’s access credentials, read by well-known keys.
Repository spec.seed.from.backend.sftp.auth.secretRef
Section titled “Repository spec.seed.from.backend.sftp.auth.secretRef”
Field Type Default Description
name string required Name of the Secret.
namespace string — Namespace of the Secret; absent = same namespace as the referrer. A ClusterRepository is cluster-scoped and has no namespace of its own, so when IT reads the Secret (to connect, to bootstrap, or to run its repository server) an absent namespace means the operator’s namespace (KOPIUR_NAMESPACE). A workload mover (Snapshot/Restore/Maintenance) still needs the Secret in its OWN namespace — envFrom is namespace-local — so put it there, or use credentialProjection, which needs this namespace set EXPLICITLY to know what to copy. Set it whenever anything other than the operator itself reads the Secret.
Field Type Default Description
url string required WebDAV collection URL holding the kopia repository.
auth object — HTTP basic-auth credentials sourced from a Secret; Secret-only.
Repository spec.seed.from.backend.webDav.auth
Section titled “Repository spec.seed.from.backend.webDav.auth”
Field Type Default Description
secretRef object — Secret holding the backend’s access credentials, read by well-known keys.
Repository spec.seed.from.backend.webDav.auth.secretRef
Section titled “Repository spec.seed.from.backend.webDav.auth.secretRef”
Field Type Default Description
name string required Name of the Secret.
namespace string — Namespace of the Secret; absent = same namespace as the referrer. A ClusterRepository is cluster-scoped and has no namespace of its own, so when IT reads the Secret (to connect, to bootstrap, or to run its repository server) an absent namespace means the operator’s namespace (KOPIUR_NAMESPACE). A workload mover (Snapshot/Restore/Maintenance) still needs the Secret in its OWN namespace — envFrom is namespace-local — so put it there, or use credentialProjection, which needs this namespace set EXPLICITLY to know what to copy. Set it whenever anything other than the operator itself reads the Secret.
Field Type Default Description
name string required Name of the referenced Repository/ClusterRepository.
kind enum: Repository | ClusterRepository Repository Which repository CRD this points at; defaults to RepositoryKind::Repository.
namespace string — Cross-namespace Repository reference; ignored/forbidden for ClusterRepository.
Field Type Default Description
enabled boolean false Copy the repository’s credential Secret(s) into the namespace of each mover Job; off by default.
Field Type Default Description
activeDeadlineSeconds integer — Mover Job.spec.activeDeadlineSeconds — wall-clock cap after which a running run is killed.
backoffLimit integer — Mover Job.spec.backoffLimit — retries before a failed run is marked failed.
podStartupDeadlineSeconds integer — Seconds a non-starting (wedged) mover pod may sit before the run is failed; default 300s.
Field Type Default Description
latestOnly boolean — Copy only each source identity’s most recent snapshot instead of its full history (kopia snapshot migrate --latest). Default false — a seed exists to recover history, so the full copy is the sane default; set this when you only need the latest restore point back quickly.
parallel integer —
min 0
--parallel: snapshots migrated concurrently (kopia default 1 — sequential). Must be >= 1 when set.
policies enum: none | copy | copyOverwrite none Whether the source’s kopia policies are copied along with the snapshots. Defaults to PolicyCopyMode::None (an explicit --no-policies), not kopia’s own copy-by-default: retention in a kopiur-managed repository is driven by Snapshot CRs, and importing the source’s kopia-side policies could delete manifests behind the operator’s back.
throttle object — Bandwidth/ops caps for THIS seed’s copy, per side. A migrate seed opens two repositories under two kopia connections and snapshot migrate has no speed flags of its own, so each side is applied as kopia repository throttle set on that side’s connection:
* source caps the REPLICA — the repository named by spec.seed.from.repository, opened read-only — overriding its moverDefaults.throttle; * destination caps THIS repository, the one being seeded, overriding its own moverDefaults.throttle.
Each side overrides field by field: a knob set here wins, a knob left unset keeps that repository’s default. Absent: both sides use their repository’s defaults. Applies only while the seed is armed — an ordinary connect to the now-initialized repository is capped by moverDefaults.throttle alone.
Field Type Default Description
destination object — Caps for the DESTINATION (write) side, overriding the destination repository’s moverDefaults.throttle field by field. Applied with repository throttle set on the destination connection the migrate writes through.
source object — Caps for the SOURCE (read) side, overriding the source repository’s moverDefaults.throttle field by field. Applied with repository throttle set on the migrate’s read-only source connection — accepted there, so a read-only source is throttled like any other.
Repository spec.seed.migrate.throttle.destination
Section titled “Repository spec.seed.migrate.throttle.destination”
Field Type Default Description
downloadBytesPerSecond integer — Cap download throughput in bytes/sec (--download-bytes-per-second).
readOpsPerSecond integer — Cap read/list ops/sec (--read-requests-per-second).
uploadBytesPerSecond integer — Cap upload throughput in bytes/sec (--upload-bytes-per-second).
writeOpsPerSecond integer — Cap write ops/sec (--write-requests-per-second).
Repository spec.seed.migrate.throttle.source
Section titled “Repository spec.seed.migrate.throttle.source”
Field Type Default Description
downloadBytesPerSecond integer — Cap download throughput in bytes/sec (--download-bytes-per-second).
readOpsPerSecond integer — Cap read/list ops/sec (--read-requests-per-second).
uploadBytesPerSecond integer — Cap upload throughput in bytes/sec (--upload-bytes-per-second).
writeOpsPerSecond integer — Cap write ops/sec (--write-requests-per-second).
Field Type Default Description
maxDownloadSpeedBytesPerSecond integer — --max-download-speed: cap read throughput from the seed source, in bytes/sec (kopia default: unlimited).
maxUploadSpeedBytesPerSecond integer — --max-upload-speed: cap write throughput into this repository, in bytes/sec (kopia default: unlimited).
parallel integer —
min 0
--parallel: concurrent blob-copy workers (kopia default 1 — sequential). Raise it: a first-time seed of a large repository over a WAN is exactly the workload sequential copying is worst at.
Field Type Default Description
auth union — UI authentication mode; omitted ⇒ ServerAuth::Generate (never no-auth).
podSecurityContext core/v1 PodSecurityContext — Pod-level security context for the server pod (notably supplementalGroups for NFS exports).
readOnly boolean — Connect the server’s repository read-only so the UI cannot mutate backups (browse + restore only).
resources core/v1 ResourceRequirements — Resource requests/limits for the server pod.
securityContext core/v1 SecurityContext — Override the hardened default container security context.
service object — How the server is exposed as a Kubernetes Service.

Externally tagged — set exactly one of: generate · insecure · secretRef.

Field Type Default Description
generate object — The operator mints random UI credentials into an owned Secret; the safe default.
insecure object — No UI authentication; requires an explicit acknowledgeInsecure: true.
secretRef object — The user supplies UI credentials via a Secret (name + the two keys).
Field Type Default Description
username string — UI username to provision (default kopia).
Field Type Default Description
acknowledgeInsecure boolean false Must be true; the webhook rejects insecure mode otherwise.
Field Type Default Description
name string required Name of the Secret holding the UI credentials.
passwordKey string required Key within the secret holding the password.
usernameKey string required Key within the secret holding the username.
Field Type Default Description
annotations map[string]string — Annotations applied to the Service — the seam users wire their own Ingress/LoadBalancer controller onto.
port integer 51515
min 0; max 65535
Listen/Service port. Defaults to DEFAULT_SERVER_PORT when omitted.
type enum: ClusterIP | NodePort | LoadBalancer ClusterIP Service type. Defaults to ClusterIP (routing is the user’s responsibility).
Field Type Default Description
backend string — Mirror of spec.backend discriminant for the print column.
catalog object — Catalog-materialization status (how many discovered Snapshots, last refresh).
conditions []object — Standard Kubernetes conditions (e.g. Connected, MaintenanceOwned).
health object — Backend health-probe state (spec.health.probe), when enabled.
lastReverifyAt string — Last reverify-request token honored from a Snapshot’s re-probe nudge (RFC3339); the loop guard that keeps each request a one-shot.
observedGeneration integer — metadata.generation of the spec last reconciled; drives staleness detection.
parameters object — The kopia repository parameters actually observed at the last bootstrap. Compare against spec.parameters to see whether a declared value landed.
phase enum: Pending | Initializing | Ready | Degraded | Failed — Lifecycle phase of a repository. A freshly admitted CR starts in Pending.
resolvedCredentialVersion string — resourceVersion of the password Secret observed at the last connect attempt.
seed object — What the last seed attempt did (spec.seed); absent on a repository that was never seeded.
server object — Resolved kopia server endpoint/auth, pinned by the reconciler.
storageStats object — Repository size and snapshot counts from the last catalog scan.
uniqueId string — Kopia repository unique ID, pinned on the first successful bootstrap.
Its presence is the “this repository has been Ready” flag that makes auto-create one-way in time: spec.create.enabled governs the FIRST bootstrap only, and once this is set kopiur will never create a fresh empty repository over the backend, however empty the backend goes. A wiped backend therefore parks at Failed with reason RepositoryReinitializeBlocked instead of being silently re-created.
To deliberately re-initialize a wiped repository, annotate it with kopiur.home-operations.com/allow-reinitialize set to THIS value; the ack is honored only while it matches, so the new ID minted by a successful re-initialize makes it inert. This discards the history the old repository held.
Field Type Default Description
coverage enum: Complete | Capped | Partial — How much of the repository a catalog scan could see.
discoveredBackupCount integer — How many Snapshot CRs were materialized from the catalog scan.
foreignSnapshotCount integer — Snapshots in the last complete listing classified as another cluster’s (see catalog.foreignSnapshots); never materialized under Ignore. As of catalog.lastRefreshAt — enable periodicRefresh to keep it current.
lastRefreshAt string — RFC 3339 timestamp of the last catalog refresh.
scanRequestAttemptAt string — RFC 3339 timestamp of the last bootstrap/scan attempt initiated BECAUSE OF a pending catalog-scan-requested-at token (i.e. the token arm was the reason the attempt fired). Used only to rate-limit token-driven attempts on a Ready-but-unreachable repository — it is never compared against the token for retirement (that’s scanRequestHonored, by equality).
scanRequestHonored string — The RFC3339 token VALUE of the kopiur.home-operations.com/catalog-scan-requested-at annotation last honored by a completed catalog scan. Compared by equality against the live annotation to decide whether a requested on-demand scan is still pending — deliberately NOT a timestamp comparison against lastRefreshAt (a periodic refresh completing after the request was made would otherwise look like it honored the request even though it started before the annotation was set).
Field Type Default Description
lastTransitionTime string required lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable.
message string required message is a human readable message indicating details about the transition. This may be an empty string.
reason string required reason contains a programmatic identifier indicating the reason for the condition’s last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty.
status string required status of the condition, one of True, False, Unknown.
type string required type of condition in CamelCase or in foo.example.com/CamelCase.
observedGeneration integer — observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditionsx.observedGeneration is 9, the condition is out of date with respect to the current state of the instance.
Field Type Default Description
consecutiveProbeFailures integer — Consecutive failing probes accrued; reset to zero on any success. The loud condition is raised only once this reaches the failure threshold.
firstFailureAt string — RFC 3339 timestamp of the first failure in the current failing streak.
lastHealthyAt string — RFC 3339 timestamp of the last successful probe (backend reachable, repo present).
lastProbeAt string — RFC 3339 timestamp of the last completed probe (success or failure); drives the health_probe_due timer so the probe re-fires on cadence.
probeAttemptAt string — RFC 3339 timestamp at which the last backend health probe was launched (the bootstrap Job created for it), cleared when its result is finalized.
This is the launch-side rate limit, and it is what makes the probe terminate. lastProbeAt is written only at finalize, so gating the launch on that alone recycles the bootstrap Job forever: the gate destroys every Job whose completion would have cleared it (#273). Never compared against lastProbeAt — see kopiur_controller::health::probe_action.
Field Type Default Description
blobRetention object — The blob retention the repository reports.
epoch object — The epoch parameters the repository reports.
Repository status.parameters.blobRetention
Section titled “Repository status.parameters.blobRetention”
Field Type Default Description
enabled boolean required Whether the repository currently has blob retention in force (kopia’s IsRetentionEnabled(): a non-empty mode AND a non-zero period).
mode string required Observed retention mode exactly as kopia reports it (GOVERNANCE, COMPLIANCE, or empty when off).
period string required Observed retention period, as a Go-style duration (720h). Empty-equivalent (0s) when retention is off.
Field Type Default Description
advanceOnCount integer required Observed index-blob count that triggers an epoch advance.
advanceOnSizeMiB integer required Observed total index size (MiB) that triggers an epoch advance, rounded up.
kopia reports this threshold in BYTES and it need not be a whole number of MiB, so the mirror rounds up to keep a sub-MiB remainder visible rather than reporting a value the repository does not actually hold. Drift against spec is computed on the exact byte count, never on this rounded mirror.
checkpointFrequency integer required Observed epochs between full index checkpoints.
cleanupSafetyMargin string required Observed cleanup safety margin, as a Go-style duration. Reported for diagnosis; not settable through spec.parameters.
deleteParallelism integer required Observed epoch-cleanup delete parallelism.
enabled boolean required Whether kopia’s epoch manager is enabled on this repository at all.
minDuration string required Observed minimum epoch age, as a Go-style duration.
refreshFrequency string required Observed epoch-state refresh frequency, as a Go-style duration.
Field Type Default Description
mode enum: blob | migrate — Which copy mechanism a seed ran. Mirrors the SeedSource variant, named after the operation rather than the input so status, metrics (kopiur_repository_seed_total{mode}) and docs share one vocabulary.
seededAt string — RFC 3339 timestamp the seed completed. Set once: a repository is seeded exactly once, at its first bootstrap.
snapshotCount integer — Snapshots observed at the SOURCE when the seed ran. Zero is only ever recorded when allowEmptySource permitted it.
snapshotsCopied integer — Snapshots actually copied into this repository. Migrate mode only — a blob copy moves storage, not manifests, so there is no per-snapshot copy count to report and it leaves this unset; its snapshotCount is the listing taken at the SOURCE before the copy, which for a byte-for-byte mirror is also what this repository ends up holding.
source string — The source the data came from, rendered by SeedSource::describe — the backend discriminant (S3, Filesystem, …) for blob mode, Kind/name for migrate mode. Never a credential or a bucket path.
startedAt string — RFC 3339 timestamp the operator LAUNCHED a seeding bootstrap Job for this repository — the durable seed-attempt marker.
Stamped before the Job is created, and never cleared. Its whole job is to distinguish “a seed this operator started did not finish” from “this backend was initialized by somebody else”: the first must resume the copy, the second must keep the no-clobber AlreadyInitialized path. See seed_resume — the marker is the ONLY input the resume decision is allowed to take, because a resuming migrate writes into whatever repository is at the backend and then re-stamps its maintenance owner.
Field Type Default Description
authMode string — Resolved auth mode discriminant (Generate/SecretRef/Insecure).
endpoint string — In-cluster endpoint, <service>.<namespace>.svc:<port>.
generatedSecretRef object — For Generate mode: the operator-owned Secret holding the UI credentials.
namespace string — Namespace the server objects were last applied to.
readOnly boolean — Effective read-only state of the served connection.
Repository status.server.generatedSecretRef
Section titled “Repository status.server.generatedSecretRef”
Field Type Default Description
name string required Name of the Secret.
namespace string — Namespace of the Secret; absent = same namespace as the referrer. A ClusterRepository is cluster-scoped and has no namespace of its own, so when IT reads the Secret (to connect, to bootstrap, or to run its repository server) an absent namespace means the operator’s namespace (KOPIUR_NAMESPACE). A workload mover (Snapshot/Restore/Maintenance) still needs the Secret in its OWN namespace — envFrom is namespace-local — so put it there, or use credentialProjection, which needs this namespace set EXPLICITLY to know what to copy. Set it whenever anything other than the operator itself reads the Secret.
Field Type Default Description
indexBlobCount integer — Number of content-index blobs (kopia index list): the freshest count available, from either the last bootstrap or the recount a maintenance run takes right after compacting. indexBlobCountAt says when.
indexBlobCountAt string — RFC3339 instant indexBlobCount was observed.
Distinct from lastObservedAt (the catalog scan’s timestamp) and from status.health.lastProbeAt (the backend probe’s): the index-blob count has its own writers, and this is what lets the reconciler decide whether a post-maintenance recount is fresher than the bootstrap’s own count. Without it the two observations were incomparable, so the IndexBlobHealth warning could only ever quote the bootstrap figure — which is pre-compaction, and stayed pre-compaction until the next bootstrap ran (#458).
The two writers mean subtly different things, deliberately. A bootstrap stamps “when this count was FIRST seen at this value”, reusing the previous stamp while the number is unchanged — that arm re-observes on every reconcile, and a stamp that always moved would make the status always-changed and the reconcile a hot loop. A post-maintenance recount always carries its own instant, because it is a distinct observation taken at a known time and its whole purpose is to be comparable.
lastObservedAt string — RFC 3339 timestamp these stats were last observed.
snapshotCount integer — Total COMPLETE snapshots present in the repository (across all identities). Incomplete checkpoints an interrupted kopia snapshot create left behind are not snapshots and are not counted.
totalSize string — Human-readable total on-disk size (e.g. 412Gi).
totalSizeBytes integer — Logical bytes under management (the integer form of total_size): the sum, over each distinct snapshot source, of the most-recent snapshot’s logical size. Exposed to backup preflight as repository.sizeBytes. This is repository total size, not backend free space (object stores don’t report remaining capacity).

Scope: Cluster · Short names: kopiacrepo · Print columns: Phase, Backend, Namespaces, Server, IndexBlobs, Age

Field Type Default Description
allowedNamespaces union required Which namespaces are permitted to reference this repository.
backend union required Exactly one storage backend.
encryption object required Repository password (a Secret reference that must carry an explicit namespace).
bootstrap object — Tuning for the bootstrap/discovery mover Job (<name>-discovery) that connects/creates an object-store repository the operator cannot reach in-process (and re-runs for catalog re-scans).
catalog object — Bounds materialization of origin: discovered Snapshot CRs from the kopia catalog.
concurrency object — Concurrency limits for mover Jobs against this repository (absent = unlimited).
create object — What to do when the repository does not yet exist (absent means it must already exist).
credentialProjection object — Repository-owner gate for projecting credential Secrets into a foreign consumer namespace.
deletionProtection object — Mass-deletion circuit breaker for this repository’s Snapshots.
health object — Repository health thresholds (tunes the index-blob-count warning).
identityDefaults object — Identity defaults (CEL *Expr) applied when consumers don’t override.
maintenance object — Maintenance control; maintenance.namespace selects where the owned Maintenance CR lands.
mode enum: ReadWrite | ReadOnly ReadWrite Access mode: ReadWrite (default) or ReadOnly (serves restores only).
moverDefaults object — Base mover configuration inherited by every mover this repository spawns.
onNamespaceDelete enum: Orphan | Delete Orphan What happens to this repository’s snapshots when a consuming namespace is deleted.
parameters object — Mutable kopia repository parameters, re-applied on bootstrap whenever they drift.
scheduleDefaults object — Scheduling defaults (timezone, jitter) inherited by consumers that don’t set their own equivalent field — backup, verification, replication, and maintenance schedules; set once here instead of repeating it on every cron.
seed object — Initialize this repository from an existing replica on its FIRST bootstrap (issue #380) — a disaster-recovery entry point.
Armed only while the repository has never been initialized (status.uniqueId unset) and the mover’s connect reports the backend uninitialized; on an already-initialized repository it is a documented no-op (Seeded=True, reason AlreadyInitialized), so it is safe to leave standing in a GitOps manifest. When armed it also replaces spec.create’s fallback: the repository is seeded or the bootstrap fails, never silently created empty.
server object — Optional kopia web-UI server (the target namespace is required).
suspend boolean — Pause this cluster repository: skip connect/bootstrap and maintenance projection.

Validation rules (enforced at admission):

  • create.splitter is immutable after creation
  • create.hash is immutable after creation
  • create.encryption is immutable after creation
  • create.ecc is immutable after creation

Externally tagged — set exactly one of: all · list · selector.

Field Type Default Description
all boolean — Allow all namespaces (must be true).
list []string — Explicit namespace names.
selector core/v1 LabelSelector — Match namespaces by label.

Externally tagged — set exactly one of: azure · b2 · filesystem · gcs · gdrive · rclone · s3 · sftp · webDav.

Field Type Default Description
azure object — Azure Blob Storage.
b2 object — Backblaze B2.
filesystem object — A local filesystem path, backed by a PVC the operator mounts into the mover.
gcs object — Google Cloud Storage.
gdrive object — Google Drive via kopia’s native gdrive provider (service-account JSON). kopia marks this provider experimental / not maintained, and a native gdrive repository is not interchangeable with an rclone-backed Drive remote.
rclone object — Any rclone remote (kopia shells out to rclone), broadening reach to providers without a native kopia backend.
s3 object — Amazon S3 or any S3-compatible object store (MinIO, RustFS, Ceph RGW, …).
sftp object — SFTP server.
webDav object — WebDAV endpoint.
Field Type Default Description
container string required Blob container holding the kopia repository.
auth object — Access credentials (Secret ref / workload identity).
prefix string — Blob-name prefix within the container; empty/absent means the container root.
storageAccount string — Storage-account name (when not inferred from credentials).
Field Type Default Description
secretRef object — Secret holding the backend’s static access credentials (mutually exclusive with workloadIdentity).
workloadIdentity object — Use a cloud-federated ServiceAccount instead of static keys (mutually exclusive with secretRef).
ClusterRepository spec.backend.azure.auth.secretRef
Section titled “ClusterRepository spec.backend.azure.auth.secretRef”
Field Type Default Description
name string required Name of the Secret.
namespace string — Namespace of the Secret; absent = same namespace as the referrer. A ClusterRepository is cluster-scoped and has no namespace of its own, so when IT reads the Secret (to connect, to bootstrap, or to run its repository server) an absent namespace means the operator’s namespace (KOPIUR_NAMESPACE). A workload mover (Snapshot/Restore/Maintenance) still needs the Secret in its OWN namespace — envFrom is namespace-local — so put it there, or use credentialProjection, which needs this namespace set EXPLICITLY to know what to copy. Set it whenever anything other than the operator itself reads the Secret.
ClusterRepository spec.backend.azure.auth.workloadIdentity
Section titled “ClusterRepository spec.backend.azure.auth.workloadIdentity”
Field Type Default Description
serviceAccountName string required Name of the ServiceAccount the mover pod runs as, resolved in the Job’s own namespace.
Field Type Default Description
bucket string required B2 bucket holding the kopia repository.
auth object — Access credentials (application key ID/key Secret); Secret-only.
prefix string — Object-name prefix within the bucket; empty/absent means the bucket root.
Field Type Default Description
secretRef object — Secret holding the backend’s access credentials, read by well-known keys.
ClusterRepository spec.backend.b2.auth.secretRef
Section titled “ClusterRepository spec.backend.b2.auth.secretRef”
Field Type Default Description
name string required Name of the Secret.
namespace string — Namespace of the Secret; absent = same namespace as the referrer. A ClusterRepository is cluster-scoped and has no namespace of its own, so when IT reads the Secret (to connect, to bootstrap, or to run its repository server) an absent namespace means the operator’s namespace (KOPIUR_NAMESPACE). A workload mover (Snapshot/Restore/Maintenance) still needs the Secret in its OWN namespace — envFrom is namespace-local — so put it there, or use credentialProjection, which needs this namespace set EXPLICITLY to know what to copy. Set it whenever anything other than the operator itself reads the Secret.
Field Type Default Description
path string required Mount path inside the mover pod where kopia writes the repository (e.g. /repo).
volume union — What backs path: a PVC or an inline NFS export; absent for a path already on the node/image.
ClusterRepository spec.backend.filesystem.volume
Section titled “ClusterRepository spec.backend.filesystem.volume”

Externally tagged — set exactly one of: nfs · pvc.

Field Type Default Description
nfs object — An inline NFS export mounted directly (no PVC).
pvc object — A PersistentVolumeClaim mounted read-write at the repo path.
ClusterRepository spec.backend.filesystem.volume.nfs
Section titled “ClusterRepository spec.backend.filesystem.volume.nfs”
Field Type Default Description
path string required Exported path on the NFS server (e.g. /export/kopia or /mnt/eros/Media).
server string required NFS server hostname or IP (e.g. nas.lan or expanse.internal).
ClusterRepository spec.backend.filesystem.volume.pvc
Section titled “ClusterRepository spec.backend.filesystem.volume.pvc”
Field Type Default Description
name string required Name of the PersistentVolumeClaim to mount (in the mover’s namespace).
Field Type Default Description
bucket string required GCS bucket holding the kopia repository.
auth object — Access credentials (service-account key Secret / workload identity).
prefix string — Object-name prefix within the bucket; empty/absent means the bucket root.
Field Type Default Description
secretRef object — Secret holding the backend’s static access credentials (mutually exclusive with workloadIdentity).
workloadIdentity object — Use a cloud-federated ServiceAccount instead of static keys (mutually exclusive with secretRef).
ClusterRepository spec.backend.gcs.auth.secretRef
Section titled “ClusterRepository spec.backend.gcs.auth.secretRef”
Field Type Default Description
name string required Name of the Secret.
namespace string — Namespace of the Secret; absent = same namespace as the referrer. A ClusterRepository is cluster-scoped and has no namespace of its own, so when IT reads the Secret (to connect, to bootstrap, or to run its repository server) an absent namespace means the operator’s namespace (KOPIUR_NAMESPACE). A workload mover (Snapshot/Restore/Maintenance) still needs the Secret in its OWN namespace — envFrom is namespace-local — so put it there, or use credentialProjection, which needs this namespace set EXPLICITLY to know what to copy. Set it whenever anything other than the operator itself reads the Secret.
ClusterRepository spec.backend.gcs.auth.workloadIdentity
Section titled “ClusterRepository spec.backend.gcs.auth.workloadIdentity”
Field Type Default Description
serviceAccountName string required Name of the ServiceAccount the mover pod runs as, resolved in the Job’s own namespace.
Field Type Default Description
folderId string required Google Drive folder ID that holds the kopia repository.
credentialsSecretRef object — Secret holding the Google service-account JSON used to reach the folder, read by the well-known key KOPIA_GDRIVE_CREDENTIALS. Absent means kopia falls back to ambient credentials (GOOGLE_APPLICATION_CREDENTIALS or instance metadata).
ClusterRepository spec.backend.gdrive.credentialsSecretRef
Section titled “ClusterRepository spec.backend.gdrive.credentialsSecretRef”
Field Type Default Description
name string required Name of the Secret.
namespace string — Namespace of the Secret; absent = same namespace as the referrer. A ClusterRepository is cluster-scoped and has no namespace of its own, so when IT reads the Secret (to connect, to bootstrap, or to run its repository server) an absent namespace means the operator’s namespace (KOPIUR_NAMESPACE). A workload mover (Snapshot/Restore/Maintenance) still needs the Secret in its OWN namespace — envFrom is namespace-local — so put it there, or use credentialProjection, which needs this namespace set EXPLICITLY to know what to copy. Set it whenever anything other than the operator itself reads the Secret.
Field Type Default Description
remotePath string required rclone path in remote:path form (the remote name must exist in the supplied rclone config).
configSecretRef object — Secret holding the rclone.conf that defines the remote referenced by remote_path.
startupTimeout string — How long kopia waits for its embedded rclone serve to come up before failing the connect, as a Go duration (e.g. 2m). kopia’s default is 15s; raise it for slow remotes whose repository metadata/indexes load through the rclone/WebDAV bridge and take longer than the default budget.
ClusterRepository spec.backend.rclone.configSecretRef
Section titled “ClusterRepository spec.backend.rclone.configSecretRef”
Field Type Default Description
name string required Name of the Secret.
namespace string — Namespace of the Secret; absent = same namespace as the referrer. A ClusterRepository is cluster-scoped and has no namespace of its own, so when IT reads the Secret (to connect, to bootstrap, or to run its repository server) an absent namespace means the operator’s namespace (KOPIUR_NAMESPACE). A workload mover (Snapshot/Restore/Maintenance) still needs the Secret in its OWN namespace — envFrom is namespace-local — so put it there, or use credentialProjection, which needs this namespace set EXPLICITLY to know what to copy. Set it whenever anything other than the operator itself reads the Secret.
Field Type Default Description
bucket string required Bucket holding the kopia repository.
auth object — Access credentials (Secret ref / workload identity).
endpoint string — S3 endpoint host. Omit for AWS; set it for MinIO/RustFS/other S3-compatible stores.
prefix string — Key prefix under the bucket, letting several repositories share one bucket (e.g. clusters/prod/). Empty/absent means the bucket root.
region string — S3 region. Required by AWS and some compatible providers.
tls object — TLS overrides for self-signed CAs or HTTP-only endpoints.
Field Type Default Description
secretRef object — Secret holding the backend’s static access credentials (mutually exclusive with workloadIdentity).
workloadIdentity object — Use a cloud-federated ServiceAccount instead of static keys (mutually exclusive with secretRef).
ClusterRepository spec.backend.s3.auth.secretRef
Section titled “ClusterRepository spec.backend.s3.auth.secretRef”
Field Type Default Description
name string required Name of the Secret.
namespace string — Namespace of the Secret; absent = same namespace as the referrer. A ClusterRepository is cluster-scoped and has no namespace of its own, so when IT reads the Secret (to connect, to bootstrap, or to run its repository server) an absent namespace means the operator’s namespace (KOPIUR_NAMESPACE). A workload mover (Snapshot/Restore/Maintenance) still needs the Secret in its OWN namespace — envFrom is namespace-local — so put it there, or use credentialProjection, which needs this namespace set EXPLICITLY to know what to copy. Set it whenever anything other than the operator itself reads the Secret.
ClusterRepository spec.backend.s3.auth.workloadIdentity
Section titled “ClusterRepository spec.backend.s3.auth.workloadIdentity”
Field Type Default Description
serviceAccountName string required Name of the ServiceAccount the mover pod runs as, resolved in the Job’s own namespace.
Field Type Default Description
caBundleRef object — CA bundle (PEM) used to verify the endpoint’s certificate, sourced from a ConfigMap.
disableTls boolean — Disable TLS entirely and talk plain HTTP; maps to kopia’s --disable-tls.
insecureSkipVerify boolean — Skip TLS certificate verification (still uses TLS); maps to kopia’s --disable-tls-verification.
ClusterRepository spec.backend.s3.tls.caBundleRef
Section titled “ClusterRepository spec.backend.s3.tls.caBundleRef”
Field Type Default Description
configMapName string — Name of the ConfigMap holding the value (e.g. a CA bundle). Resolved in the referrer’s namespace for a namespaced Repository, and in the operator’s namespace (KOPIUR_NAMESPACE) for a ClusterRepository (cluster-scoped, no namespace of its own).
key string — Which key inside the ConfigMap to read; defaults to ca.crt when unset.
Field Type Default Description
host string required SFTP server hostname or IP.
path string required Remote path on the server that holds the kopia repository.
auth object — Credentials (SSH private key / known-hosts) sourced from a Secret; Secret-only.
port integer —
min 0; max 65535
TCP port; defaults to 22 when absent.
username string — SSH username to connect as.
Field Type Default Description
secretRef object — Secret holding the backend’s access credentials, read by well-known keys.
ClusterRepository spec.backend.sftp.auth.secretRef
Section titled “ClusterRepository spec.backend.sftp.auth.secretRef”
Field Type Default Description
name string required Name of the Secret.
namespace string — Namespace of the Secret; absent = same namespace as the referrer. A ClusterRepository is cluster-scoped and has no namespace of its own, so when IT reads the Secret (to connect, to bootstrap, or to run its repository server) an absent namespace means the operator’s namespace (KOPIUR_NAMESPACE). A workload mover (Snapshot/Restore/Maintenance) still needs the Secret in its OWN namespace — envFrom is namespace-local — so put it there, or use credentialProjection, which needs this namespace set EXPLICITLY to know what to copy. Set it whenever anything other than the operator itself reads the Secret.
Field Type Default Description
url string required WebDAV collection URL holding the kopia repository.
auth object — HTTP basic-auth credentials sourced from a Secret; Secret-only.
ClusterRepository spec.backend.webDav.auth
Section titled “ClusterRepository spec.backend.webDav.auth”
Field Type Default Description
secretRef object — Secret holding the backend’s access credentials, read by well-known keys.
ClusterRepository spec.backend.webDav.auth.secretRef
Section titled “ClusterRepository spec.backend.webDav.auth.secretRef”
Field Type Default Description
name string required Name of the Secret.
namespace string — Namespace of the Secret; absent = same namespace as the referrer. A ClusterRepository is cluster-scoped and has no namespace of its own, so when IT reads the Secret (to connect, to bootstrap, or to run its repository server) an absent namespace means the operator’s namespace (KOPIUR_NAMESPACE). A workload mover (Snapshot/Restore/Maintenance) still needs the Secret in its OWN namespace — envFrom is namespace-local — so put it there, or use credentialProjection, which needs this namespace set EXPLICITLY to know what to copy. Set it whenever anything other than the operator itself reads the Secret.
Field Type Default Description
passwordSecretRef object required Repository password, always a Secret reference (never inline).
ClusterRepository spec.encryption.passwordSecretRef
Section titled “ClusterRepository spec.encryption.passwordSecretRef”
Field Type Default Description
name string required Name of the Secret.
key string — Which key inside the Secret to read.
namespace string — Namespace of the Secret; absent = same namespace as the referrer. A ClusterRepository is cluster-scoped and has no namespace of its own, so when IT reads the Secret (to connect, to bootstrap, or to run its repository server) an absent namespace means the operator’s namespace (KOPIUR_NAMESPACE). A workload mover (Snapshot/Restore/Maintenance) still needs the Secret in its OWN namespace — envFrom is namespace-local — so put it there, or use credentialProjection, which needs this namespace set EXPLICITLY to know what to copy. Set it whenever anything other than the operator itself reads the Secret.
Field Type Default Description
failurePolicy object — Failure policy for the bootstrap Job. activeDeadlineSeconds caps how long a connect may run before the Job is marked failed (default 120s); raise it for a slow backend — e.g. an rclone remote whose repository metadata and indexes load through kopia’s embedded rclone serve/WebDAV bridge, or a large repository whose cold-cache connect outgrows the default. The value is a BASE, not a ceiling: after consecutive deadline-killed attempts the operator escalates the effective deadline itself (doubling per attempt, up to 30 minutes or the configured value, whichever is larger — never below it), so a slow-but-alive backend self-heals without a spec edit. backoffLimit bounds retries. podStartupDeadlineSeconds is accepted for shape parity but is not honored by the bootstrap Job.
ClusterRepository spec.bootstrap.failurePolicy
Section titled “ClusterRepository spec.bootstrap.failurePolicy”
Field Type Default Description
activeDeadlineSeconds integer — Mover Job.spec.activeDeadlineSeconds — wall-clock cap after which a running run is killed.
backoffLimit integer — Mover Job.spec.backoffLimit — retries before a failed run is marked failed.
podStartupDeadlineSeconds integer — Seconds a non-starting (wedged) mover pod may sit before the run is failed; default 300s.
Field Type Default Description
adoption enum: Adopt | Ignore — Whether a discovered snapshot whose resolved identity matches a live SnapshotPolicy is automatically adopted — re-attached (stamped with that policy’s config label, status.origin flipped to Adopted) so GFS retention governs it and eventually prunes it, instead of it sitting in the catalog forever as an immortal discovered row.
fallbackNamespace string — Where to materialize discovered Snapshots with no allowed-namespace mapping (ClusterRepository only).
foreignSnapshots enum: Ignore | Fallback — How catalog discovery treats snapshots written by ANOTHER cluster. status.catalog.foreignSnapshotCount counts an identity hostname carrying a different .<cluster> suffix ALWAYS, under either value below, plus — under Ignore only — a bare hostname naming no allowed namespace here. Under Fallback, that same disallowed bare host is NOT counted foreign: it materializes into catalog.fallbackNamespace exactly like a disallowed OwnCluster host would, so it is placed rather than dropped-and-counted (see classify_hostname/decide_cluster_placement). Meaningful only when identityDefaults.cluster is set: without a cluster identity there is no notion of “foreign” and the legacy hostname-names-a-namespace placement applies (validators enforce this).
periodicRefresh boolean — Opt-in: periodically re-scan the repository to keep discovered Snapshot CRs current (re-list snapshots; for object-store / volume-backed repos this recycles the <name>-discovery mover Job every refreshInterval). Off by default — the repository still bootstraps once, re-bootstraps on a spec change, and re-probes on a backup failure, but does not re-run on a timer. Enable it if you rely on discovered snapshots reflecting changes made outside this operator.
refreshInterval string 1h How often to re-scan when periodicRefresh: true (Go-style duration; minimum 30s, default 1h). Inert unless periodicRefresh is enabled.
retain object — How many discovered Snapshot CRs to keep materialized (bounds etcd footprint).
Field Type Default Description
maxAgeDays integer — Expire discovered Snapshot CRs older than this many days (minimum 1); kopia snapshots untouched.
perIdentity integer — Keep the most-recent N discovered Snapshot CRs per identity; 0 disables materialization.
Field Type Default Description
maxConcurrentDeleteJobs integer —
min 1
Ceiling on how many snapshot-delete batch Jobs may run against this repository at once. Absent means 1: one batch at a time, and the next batch starts when the current one finishes.
A batch Job deletes hundreds of snapshots in a single kopia call. kopia serializes manifest deletes on the repository’s index anyway, so running several batches in parallel adds no throughput. Each extra Job only loads the full index again against the same backend (issue #477). Raise it only for a fast local backend with a very large deletion backlog.
Must be at least 1. There is no “unlimited” value. Omit the field for the default. The controller-wide maxConcurrentDeleteJobs Helm value still caps delete Jobs across ALL repositories on top of this.
No schema default: is emitted (api-conventions §4a); the controller resolves absent to 1, so stored repositories carry no diff noise.
maxConcurrentJobs integer —
min 0
Ceiling on how many of this repository’s mover Jobs may be in flight at once. Backup snapshots, restores, and replication runs that READ FROM this repository all draw from ONE pool — a repository’s backend (and the bandwidth to it) is the shared resource, so splitting the budget per work kind would let three “safe” limits still saturate it.
Restores are always admitted and never parked: a restore is a recovery in progress, and holding one behind a queue of routine backups is exactly backwards. An in-flight restore still COUNTS toward the pool, so it displaces backups rather than adding to them.
Excluded from the pool entirely: maintenance (already single-flight per repository), verification, pin, and snapshot-delete batch Jobs. These are operator-driven housekeeping that must not be starved by a saturated backup pool. Delete batches have their own cap, maxConcurrentDeleteJobs.
Absent or 0 means unlimited — the default, and today’s behavior.
No schema default: is emitted for this field (api-conventions §4a): absent and 0 are the SAME state (unlimited), so a materialized default would stamp {maxConcurrentJobs: 0} onto every stored repository — GitOps diff noise for a value that changes nothing.
Field Type Default Description
ecc object — Reed-Solomon ECC parity for a freshly-created repository (creation-time only, immutable after).
enabled boolean true Create the repository if it does not exist yet — on by default. Repository create/connect is idempotent: pointing create at an already-initialized repository just connects to it (it never re-creates or clobbers), so the only effect of the default is that a genuinely-absent repository is bootstrapped instead of erroring. Set false for a strictly read-only or externally-managed repository the operator must never create.
encryption string — kopia encryption algorithm for a freshly-created repository (creation-time only).
hash string — kopia content hash algorithm for a freshly-created repository (creation-time only).
splitter string — kopia object splitter for a freshly-created repository (creation-time only).
Field Type Default Description
algorithm string — ECC algorithm, e.g. REED-SOLOMON-CRC32 (--ecc).
overheadPercent integer — Parity overhead as a percentage (--ecc-overhead-percent).

ClusterRepository spec.credentialProjection

Section titled “ClusterRepository spec.credentialProjection”
Field Type Default Description
allowed boolean false When true, the owner permits projecting this repository’s credential Secret(s) into a consumer namespace.
Field Type Default Description
threshold integer 10
min 0
Pending EXTERNAL destructive Snapshot deletions (deletionTimestamp set, effective deletionPolicy Delete, not operator-pruned) that trip the breaker for this repository: at or above this, those deletions are HELD (finalizers wait) until acknowledged via the kopiur.home-operations.com/allow-mass-deletion annotation. 0 disables the breaker. Default 10.
Field Type Default Description
indexBlobWarnThreshold integer 1000 Index-blob count above which the reconciler raises the IndexBlobHealth warning (0 disables).
probe object — Periodic backend health probe (on by default): re-connect the repository on a timer to confirm the kopia repository still exists at the backend. With the default onFailure: Degrade it doubles as the repository circuit breaker — see probe.onFailure. Disable with probe.enabled: false.
Field Type Default Description
enabled boolean true Whether the probe runs (default true). false disables probing — and with it the circuit breaker, since the probe is its only sensor: a wiped or unreachable backend then goes unnoticed until the next backup fails.
failureThreshold integer 3 How many consecutive failing probes to require before the failure is acted on (default 3): the loud BackendReachable=False condition + event fire, and — under onFailure: Degrade — the repository moves to Degraded. Debounces a single transient blip from alarming, tripping the breaker, or nudging a destructive manual recreate. Any success resets it.
interval string 30m How often to re-probe the backend (Go-style duration like 30m or 1h; minimum 30s, default 30m). Inert when enabled: false.
onFailure enum: Degrade | Alert Degrade What sustained backend-probe failure (past failureThreshold) does to the repository (default Degrade). Degrade moves it to Degraded, pausing backups and replication until a re-connect succeeds — recovery is automatic (maintenance also pauses for a confirmed-unreachable/vanished backend, but keeps running for a probe deadline kill, where index compaction is often the cure). Alert keeps the repository Ready and only raises the BackendReachable condition + Warning event + metric; backups keep running against the failing backend. Neither ever auto-recreates.
Field Type Default Description
cluster string — This cluster’s identity suffix for repositories shared across clusters (an RFC 1123 label, at most 32 characters; dots are rejected — the first . in a hostname is the namespace/cluster delimiter). When set, the default kopia identity hostname becomes <namespace>.<cluster> instead of <namespace>, so two clusters backing up same-named namespaces write distinct identities (and one cluster’s retention prune can no longer touch the other’s snapshots). Also exposed to hostnameExpr/ usernameExpr as the CEL variable cluster.
hostnameExpr string — CEL expression for the kopia identity hostname (e.g. "namespace").
usernameExpr string — CEL expression for the kopia identity username (e.g. "namespace + '-' + policyName").
Field Type Default Description
enabled boolean true Whether the operator manages a Maintenance CR for this repository (default true).
failurePolicy object — Failure handling (backoff/deadline) for the managed Maintenance run.
mover object — Mover overrides for the managed Maintenance.
namespace string — ClusterRepository only: namespace the managed Maintenance CR is created in (default the operator’s namespace).
schedule object — Schedule override; absent uses the default quick-6h / full-daily schedule.
takeoverPolicy enum: Never | PromptCondition | Force — What to do when another owner already holds the lease. Defaults to Never (the safest: never seize a lease another owner holds).
ClusterRepository spec.maintenance.failurePolicy
Section titled “ClusterRepository spec.maintenance.failurePolicy”
Field Type Default Description
activeDeadlineSeconds integer — Mover Job.spec.activeDeadlineSeconds — wall-clock cap after which a running run is killed.
backoffLimit integer — Mover Job.spec.backoffLimit — retries before a failed run is marked failed.
podStartupDeadlineSeconds integer — Seconds a non-starting (wedged) mover pod may sit before the run is failed; default 300s.
Field Type Default Description
cache object — Override the repository’s CacheDefaults for this recipe’s movers.
inheritSecurityContextFrom union — Copy the UID/GID security context from a live workload rather than hard-coding it.
Requires the workload to pin runAsUser (container or pod level): a UID that comes from the container image’s USER line is invisible in the pod spec and cannot be inherited — the mover would silently run as its own image’s UID instead.
May be combined with securityContext/podSecurityContext, which override it field-wise and act as the fallback when no workload pod can be resolved.
podSecurityContext core/v1 PodSecurityContext — Pod security context for the mover (notably fsGroup for group-writable restore volumes). Same layering as securityContext: highest layer, merged field-wise, and combinable with inheritSecurityContextFrom.
privilegedMode boolean — Opt-in, namespace-gated privileged mode. Never changes the UID. When the mover runs as root (runAsUser: 0), adds the capabilities the operation needs on top of drop: ALL: DAC_OVERRIDE for a backup (read files owned by any uid/gid); CHOWN, DAC_OVERRIDE, FOWNER, FSETID for a restore (reproduce original ownership). Grants nothing for maintenance, or when the mover does not run as root (capabilities are inert for non-root); set runAsUser: 0 yourself.
resources core/v1 ResourceRequirements — Resource requests/limits for the mover container.
securityContext core/v1 SecurityContext — Container security context for the mover; merged field-wise over the hardened base, moverDefaults, and any inherited context — this is the highest layer, so every field set here wins. Combines with inheritSecurityContextFrom: fields you set override the workload’s, fields you omit are inherited, and this context stands in alone when inheritance cannot resolve a pod.
ttlSecondsAfterFinished integer — Per-recipe override of Job.spec.ttlSecondsAfterFinished so finished Jobs self-GC.
ClusterRepository spec.maintenance.mover.cache
Section titled “ClusterRepository spec.maintenance.mover.cache”
Field Type Default Description
capacity string — Size of the PVC backing the mover’s kopia cache (e.g. 10Gi).
contentCacheSizeMb integer — kopia content cache budget in MiB (--content-cache-size-mb).
metadataCacheSizeMb integer — kopia metadata cache budget in MiB (--metadata-cache-size-mb).
mode enum: Ephemeral | Persistent — How a mover’s kopia cache volume is provisioned.
storageClassName string — StorageClass for the cache PVC; absent uses the cluster default.
ClusterRepository spec.maintenance.mover.inheritSecurityContextFrom
Section titled “ClusterRepository spec.maintenance.mover.inheritSecurityContextFrom”

Externally tagged — set exactly one of: pvcConsumer · snapshot · workloadSelector.

Field Type Default Description
pvcConsumer object — Backup sources only: auto-derive the workload from the PVC this snapshot backs up.
snapshot object — Restores only: inherit the identity RECORDED on the backup itself (Snapshot.status.recorded, decoded from the kopiur-meta kopia tag) — uid/gid/fsGroup the backup mover actually ran as. Needs no live workload pod, so it works on a rebuilt cluster and with target.populator. Rejected at admission on SnapshotPolicy/Maintenance (backups read the live workload; maintenance has no snapshot). Write it as snapshot: {} (an empty sub-object) — a bare snapshot: is null and rejected.
workloadSelector object — Inherit from workload pod(s) matched by an explicit label selector (backup or restore).
ClusterRepository spec.maintenance.mover.inheritSecurityContextFrom.pvcConsumer
Section titled “ClusterRepository spec.maintenance.mover.inheritSecurityContextFrom.pvcConsumer”
Field Type Default Description
container string — Which container within the matched consumer pod to inherit from; absent uses the first/only.
ClusterRepository spec.maintenance.mover.inheritSecurityContextFrom.workloadSelector
Section titled “ClusterRepository spec.maintenance.mover.inheritSecurityContextFrom.workloadSelector”
Field Type Default Description
podSelector core/v1 LabelSelector required Label selector matching the workload pod(s) to read context/hooks from.
container string — Which container within the matched pod; absent uses the first/only container.
ClusterRepository spec.maintenance.schedule
Section titled “ClusterRepository spec.maintenance.schedule”
Field Type Default Description
full object required Cron and jitter for kopia maintenance run --full (content reclamation).
quick object required Cron and jitter for kopia maintenance run (quick, cheap index/log work).
timezone string — IANA timezone both crons are evaluated in; absent means the controller default.
ClusterRepository spec.maintenance.schedule.full
Section titled “ClusterRepository spec.maintenance.schedule.full”
Field Type Default Description
cron string required The cron expression, parsed by croner; may contain an H placeholder for deterministic jitter.
jitter string — Optional deterministic jitter window as a Go-style duration string (e.g. 30m).
timezone string — IANA timezone the cron is evaluated in (e.g. America/Chicago); absent uses the enclosing schedule’s timezone, else the controller default (UTC).
ClusterRepository spec.maintenance.schedule.quick
Section titled “ClusterRepository spec.maintenance.schedule.quick”
Field Type Default Description
cron string required The cron expression, parsed by croner; may contain an H placeholder for deterministic jitter.
jitter string — Optional deterministic jitter window as a Go-style duration string (e.g. 30m).
timezone string — IANA timezone the cron is evaluated in (e.g. America/Chicago); absent uses the enclosing schedule’s timezone, else the controller default (UTC).
Field Type Default Description
affinity core/v1 Affinity — Pod affinity for every mover.
cache object — kopia cache defaults for every mover.
nodeSelector map[string]string — Pod nodeSelector for every mover.
podAnnotations map[string]string — Extra annotations for every mover pod. Unlike podLabels these are pod-template-only — they are not mirrored onto the Job object, because the common case is a sidecar-injection opt-out (sidecar.istio.io/inject: "false", linkerd.io/inject: disabled, vault.hashicorp.com/agent-inject: "false") that only means anything on the pod a mesh webhook actually sees. A mover is a short-lived batch pod; an injected sidecar that never exits keeps its Job running forever.
Same reserved keys as podLabels, rejected at admission.
podLabels map[string]string — Extra labels for every mover POD (and the Job that owns it), merged UNDER kopiur’s own labels — a key kopiur sets always wins, so a user-supplied value can never break the selectors the controller counts and reaps by.
This is the hook for cluster machinery that keys off pod labels and that kopiur has no field of its own for: a Kueue kueue.x-k8s.io/queue-name to put movers under a cluster queue, a monitoring/NetworkPolicy selector, a service-mesh exclusion label.
Keys under kopiur.home-operations.com/ and the exact key app.kubernetes.io/managed-by are reserved and rejected at admission.
podSecurityContext core/v1 PodSecurityContext — Pod security-context base (notably fsGroup) for every mover.
resources core/v1 ResourceRequirements — Resource requests/limits base for the mover container.
scratch object — Defaults for the deep-verification scratch (restore-test) volume.
securityContext core/v1 SecurityContext — Container security-context base for every mover.
sourceColocation object — How a mover co-locates with its RWO PVC’s node; defaults to SourceColocationMode::Auto.
throttle object — Repository throttle limits applied by every mover after it connects.
tolerations []core/v1 Toleration — Pod tolerations for every mover.
ttlSecondsAfterFinished integer — Job.spec.ttlSecondsAfterFinished for every mover Job so finished Jobs self-GC.
ClusterRepository spec.moverDefaults.cache
Section titled “ClusterRepository spec.moverDefaults.cache”
Field Type Default Description
capacity string — Size of the PVC backing the mover’s kopia cache (e.g. 10Gi).
contentCacheSizeMb integer — kopia content cache budget in MiB (--content-cache-size-mb).
metadataCacheSizeMb integer — kopia metadata cache budget in MiB (--metadata-cache-size-mb).
mode enum: Ephemeral | Persistent — How a mover’s kopia cache volume is provisioned.
storageClassName string — StorageClass for the cache PVC; absent uses the cluster default.
ClusterRepository spec.moverDefaults.scratch
Section titled “ClusterRepository spec.moverDefaults.scratch”
Field Type Default Description
capacity string — Size of the ephemeral scratch PVC (e.g. 100Gi); absent falls back to an emptyDir.
storageClassName string — StorageClass for the ephemeral scratch PVC; only applies when capacity is set.
ClusterRepository spec.moverDefaults.sourceColocation
Section titled “ClusterRepository spec.moverDefaults.sourceColocation”
Field Type Default Description
mode enum: Auto | Required | Disabled — How the mover co-locates with the node an RWO source/destination PVC is attached to.
ClusterRepository spec.moverDefaults.throttle
Section titled “ClusterRepository spec.moverDefaults.throttle”
Field Type Default Description
downloadBytesPerSecond integer — Cap download throughput in bytes/sec (--download-bytes-per-second).
readOpsPerSecond integer — Cap read/list ops/sec (--read-requests-per-second).
uploadBytesPerSecond integer — Cap upload throughput in bytes/sec (--upload-bytes-per-second).
writeOpsPerSecond integer — Cap write ops/sec (--write-requests-per-second).
Field Type Default Description
blobRetention union — Object-lock blob retention (S3/Azure/GCS) — ransomware protection. Absent means “don’t touch it”; use disabled: true to actively turn it off.
epoch object — Epoch-manager tuning — how fast kopia closes epochs and therefore how fast index blobs get compacted.
ClusterRepository spec.parameters.blobRetention
Section titled “ClusterRepository spec.parameters.blobRetention”

Externally tagged — set exactly one of: compliance · disabled · governance.

Field Type Default Description
compliance object — COMPLIANCE — nobody can shorten or remove the lock before it expires, including the account root. An oversized period is an unfixable storage-cost commitment; there is no recovery path short of deleting the bucket after expiry.
disabled boolean — Actively disable retention (--retention-mode=none). Must be true.
A bool rather than a unit variant because an externally-tagged unit variant serializes as the bare string "Disabled", mixing string and object forms in one oneOf and breaking the structural schema. Same shape, and same reason, as AllowedNamespaces::All.
This is distinct from omitting blobRetention entirely: absent means “leave the repository alone”, so deleting the block from a manifest can never silently strip ransomware protection someone configured deliberately.
governance object — GOVERNANCE — locked against ordinary deletes, but a sufficiently privileged identity can still shorten or remove the lock. The safe default for most clusters.
ClusterRepository spec.parameters.blobRetention.compliance
Section titled “ClusterRepository spec.parameters.blobRetention.compliance”
Field Type Default Description
period string required Go-style duration; kopia’s minimum is 24h and there is no maximum.
Accepts h/m/s (or a bare number of seconds) — not d. Note that kopia’s own CLI does take 30d, so a period copied from kopia’s documentation is rejected here; write 30 days as 720h. Kopiur deliberately keeps one duration grammar across every CRD field rather than matching kopia’s per-flag variations.
ClusterRepository spec.parameters.blobRetention.governance
Section titled “ClusterRepository spec.parameters.blobRetention.governance”
Field Type Default Description
period string required Go-style duration; kopia’s minimum is 24h and there is no maximum.
Accepts h/m/s (or a bare number of seconds) — not d. Note that kopia’s own CLI does take 30d, so a period copied from kopia’s documentation is rejected here; write 30 days as 720h. Kopiur deliberately keeps one duration grammar across every CRD field rather than matching kopia’s per-flag variations.
Field Type Default Description
advanceOnCount integer — Index blobs in an epoch that trigger an advance, once older than minDuration (kopia default 20).
At least 10 — kopia refuses anything lower with “epoch advance on count too low”.
advanceOnSizeMiB integer — Total index size in an epoch that triggers an advance, once older than minDuration (kopia default 10 MiB).
At least 1 — kopia refuses anything lower with “epoch advance on size too low”, and 1 MiB is the smallest threshold the flag can express.
Named MiB, not MB, with an explicit rename rather than the derived camelCase (advanceOnSizeMb, which reads as megabit). The unit is genuinely mebibytes — kopia’s --epoch-advance-on-size-mb multiplies by 1048576, so 10 is 10485760 bytes — even though kopia’s own log renders the result as “MB”. That ambiguity is this field’s main hazard; the API surface should not reproduce it.
checkpointFrequency integer — Epochs between full index checkpoints (kopia default 7).
At least 1 — kopia refuses anything lower with “invalid epoch range compaction period”.
deleteParallelism integer — Parallelism for epoch cleanup deletions (kopia default 4).
At least 1. This floor is kopiur’s own: kopia does not validate the field, so a non-positive value would ask it to run epoch cleanup with no workers.
minDuration string — Minimum epoch age before it may advance (kopia default 24h). A Go-style duration (6h, 90m). The advance gate — no blob count closes an epoch younger than this.
Must be at least 10m (kopia’s absolute floor) AND at least 3x refreshFrequency. When refreshFrequency is not declared, that second bound is measured against kopia’s untouched 20m default, so 10m on its own is rejected: use 60m, or declare a refreshFrequency of a third of it or less alongside it.
refreshFrequency string — How often clients re-read epoch state (kopia default 20m). Go-style duration.
At most 80m: kopia requires cleanupSafetyMargin >= 3x this value, and cleanupSafetyMargin is observable-but-not-settable here, so it stays at kopia’s 4h default and 4h / 3 is a hard ceiling.
Field Type Default Description
jitter string — Deterministic jitter window (Go-style duration, e.g. 10m) applied to every consuming cron that doesn’t set its own jitter — SnapshotSchedule, Maintenance (quick and full), SnapshotPolicy verification (quick and deep), and both replication kinds. Set once here instead of repeating it on every cron, so a whole repository’s schedules spread their load off the top-of-the-hour thundering herd.
The spread is deterministic per (scheduleUID, slot), not random: the same slot always lands on the same instant, so a restart never re-rolls it. Capped at 24h by validation — jitter is a spread WITHIN a cron period, not a schedule offset.
timezone string — IANA timezone name applied to every consuming cron that doesn’t set its own timezone (e.g. America/New_York). Set once here instead of repeating it on every SnapshotPolicy.verification, RepositoryReplication.schedule, and Maintenance.schedule cron.
Field Type Default Description
from union required Where the seed data comes from: exactly one of a bare storage backend (blob mode) or another repository CR (migrate mode).
allowEmptySource boolean — Accept a source that holds zero snapshots (default false).
A mirror that answers but is empty is almost always a mis-pointed bucket/prefix, and silently seeding nothing would hand you a Ready repository with no history — the failure mode #380 is about. By default the bootstrap fails loudly and retries; set this when an empty source is genuinely expected (e.g. re-homing a repository whose history was deliberately pruned to nothing).
credentialProjection object — Opt-in projection of the SOURCE repository’s credential Secrets into the seeding mover Job’s namespace. Migrate mode only in practice — a blob-mode source’s credentials must already be in the namespace the bootstrap Job runs in (this CR’s own namespace for a Repository; for a ClusterRepository the operator’s namespace, unless encryption.passwordSecretRef.namespace pins another, in which case the Job runs there). Requires the operator’s features.credentialProjection install flag.
failurePolicy object — Deadline/backoff for the seeding bootstrap Job. An absent activeDeadlineSeconds means 24h here, rather than the 120s a routine connect gets — a seed copies a whole repository, once. Only applied while the seed is armed; later connects to the now-initialized repository use spec.bootstrap.failurePolicy as before.
migrate object — Tuning for the kopia snapshot migrate copy. Migrate mode only (from.repository); rejected at admission alongside from.backend.
sync object — Tuning for the kopia repository sync-to blob copy. Blob mode only (from.backend); rejected at admission alongside from.repository.

Externally tagged — set exactly one of: backend · repository.

Field Type Default Description
backend union — A bare storage backend holding a byte-for-byte mirror of a kopia repository (blob mode, kopia repository sync-to). The mirror’s format and encryption password are inherited verbatim, so this repository’s encryption.passwordSecretRef must already hold the MIRROR’s password and spec.create’s format knobs are refused as inert.
repository object — Another Repository/ClusterRepository, opened read-only (migrate mode, kopia snapshot migrate). Snapshot identities and times are preserved, so seeded history is restorable by identity/fromPolicy.
A kind: Repository reference with no namespace resolves in the referrer’s own namespace — and, on a cluster-scoped ClusterRepository (which has none), in the operator’s namespace, the same rule its credential secretRefs follow. Set namespace explicitly whenever the source lives anywhere else.

Externally tagged — set exactly one of: azure · b2 · filesystem · gcs · gdrive · rclone · s3 · sftp · webDav.

Field Type Default Description
azure object — Azure Blob Storage.
b2 object — Backblaze B2.
filesystem object — A local filesystem path, backed by a PVC the operator mounts into the mover.
gcs object — Google Cloud Storage.
gdrive object — Google Drive via kopia’s native gdrive provider (service-account JSON). kopia marks this provider experimental / not maintained, and a native gdrive repository is not interchangeable with an rclone-backed Drive remote.
rclone object — Any rclone remote (kopia shells out to rclone), broadening reach to providers without a native kopia backend.
s3 object — Amazon S3 or any S3-compatible object store (MinIO, RustFS, Ceph RGW, …).
sftp object — SFTP server.
webDav object — WebDAV endpoint.
ClusterRepository spec.seed.from.backend.azure
Section titled “ClusterRepository spec.seed.from.backend.azure”
Field Type Default Description
container string required Blob container holding the kopia repository.
auth object — Access credentials (Secret ref / workload identity).
prefix string — Blob-name prefix within the container; empty/absent means the container root.
storageAccount string — Storage-account name (when not inferred from credentials).
ClusterRepository spec.seed.from.backend.azure.auth
Section titled “ClusterRepository spec.seed.from.backend.azure.auth”
Field Type Default Description
secretRef object — Secret holding the backend’s static access credentials (mutually exclusive with workloadIdentity).
workloadIdentity object — Use a cloud-federated ServiceAccount instead of static keys (mutually exclusive with secretRef).
ClusterRepository spec.seed.from.backend.azure.auth.secretRef
Section titled “ClusterRepository spec.seed.from.backend.azure.auth.secretRef”
Field Type Default Description
name string required Name of the Secret.
namespace string — Namespace of the Secret; absent = same namespace as the referrer. A ClusterRepository is cluster-scoped and has no namespace of its own, so when IT reads the Secret (to connect, to bootstrap, or to run its repository server) an absent namespace means the operator’s namespace (KOPIUR_NAMESPACE). A workload mover (Snapshot/Restore/Maintenance) still needs the Secret in its OWN namespace — envFrom is namespace-local — so put it there, or use credentialProjection, which needs this namespace set EXPLICITLY to know what to copy. Set it whenever anything other than the operator itself reads the Secret.
ClusterRepository spec.seed.from.backend.azure.auth.workloadIdentity
Section titled “ClusterRepository spec.seed.from.backend.azure.auth.workloadIdentity”
Field Type Default Description
serviceAccountName string required Name of the ServiceAccount the mover pod runs as, resolved in the Job’s own namespace.
ClusterRepository spec.seed.from.backend.b2
Section titled “ClusterRepository spec.seed.from.backend.b2”
Field Type Default Description
bucket string required B2 bucket holding the kopia repository.
auth object — Access credentials (application key ID/key Secret); Secret-only.
prefix string — Object-name prefix within the bucket; empty/absent means the bucket root.
ClusterRepository spec.seed.from.backend.b2.auth
Section titled “ClusterRepository spec.seed.from.backend.b2.auth”
Field Type Default Description
secretRef object — Secret holding the backend’s access credentials, read by well-known keys.
ClusterRepository spec.seed.from.backend.b2.auth.secretRef
Section titled “ClusterRepository spec.seed.from.backend.b2.auth.secretRef”
Field Type Default Description
name string required Name of the Secret.
namespace string — Namespace of the Secret; absent = same namespace as the referrer. A ClusterRepository is cluster-scoped and has no namespace of its own, so when IT reads the Secret (to connect, to bootstrap, or to run its repository server) an absent namespace means the operator’s namespace (KOPIUR_NAMESPACE). A workload mover (Snapshot/Restore/Maintenance) still needs the Secret in its OWN namespace — envFrom is namespace-local — so put it there, or use credentialProjection, which needs this namespace set EXPLICITLY to know what to copy. Set it whenever anything other than the operator itself reads the Secret.
ClusterRepository spec.seed.from.backend.filesystem
Section titled “ClusterRepository spec.seed.from.backend.filesystem”
Field Type Default Description
path string required Mount path inside the mover pod where kopia writes the repository (e.g. /repo).
volume union — What backs path: a PVC or an inline NFS export; absent for a path already on the node/image.
ClusterRepository spec.seed.from.backend.filesystem.volume
Section titled “ClusterRepository spec.seed.from.backend.filesystem.volume”

Externally tagged — set exactly one of: nfs · pvc.

Field Type Default Description
nfs object — An inline NFS export mounted directly (no PVC).
pvc object — A PersistentVolumeClaim mounted read-write at the repo path.
ClusterRepository spec.seed.from.backend.filesystem.volume.nfs
Section titled “ClusterRepository spec.seed.from.backend.filesystem.volume.nfs”
Field Type Default Description
path string required Exported path on the NFS server (e.g. /export/kopia or /mnt/eros/Media).
server string required NFS server hostname or IP (e.g. nas.lan or expanse.internal).
ClusterRepository spec.seed.from.backend.filesystem.volume.pvc
Section titled “ClusterRepository spec.seed.from.backend.filesystem.volume.pvc”
Field Type Default Description
name string required Name of the PersistentVolumeClaim to mount (in the mover’s namespace).
ClusterRepository spec.seed.from.backend.gcs
Section titled “ClusterRepository spec.seed.from.backend.gcs”
Field Type Default Description
bucket string required GCS bucket holding the kopia repository.
auth object — Access credentials (service-account key Secret / workload identity).
prefix string — Object-name prefix within the bucket; empty/absent means the bucket root.
ClusterRepository spec.seed.from.backend.gcs.auth
Section titled “ClusterRepository spec.seed.from.backend.gcs.auth”
Field Type Default Description
secretRef object — Secret holding the backend’s static access credentials (mutually exclusive with workloadIdentity).
workloadIdentity object — Use a cloud-federated ServiceAccount instead of static keys (mutually exclusive with secretRef).
ClusterRepository spec.seed.from.backend.gcs.auth.secretRef
Section titled “ClusterRepository spec.seed.from.backend.gcs.auth.secretRef”
Field Type Default Description
name string required Name of the Secret.
namespace string — Namespace of the Secret; absent = same namespace as the referrer. A ClusterRepository is cluster-scoped and has no namespace of its own, so when IT reads the Secret (to connect, to bootstrap, or to run its repository server) an absent namespace means the operator’s namespace (KOPIUR_NAMESPACE). A workload mover (Snapshot/Restore/Maintenance) still needs the Secret in its OWN namespace — envFrom is namespace-local — so put it there, or use credentialProjection, which needs this namespace set EXPLICITLY to know what to copy. Set it whenever anything other than the operator itself reads the Secret.
ClusterRepository spec.seed.from.backend.gcs.auth.workloadIdentity
Section titled “ClusterRepository spec.seed.from.backend.gcs.auth.workloadIdentity”
Field Type Default Description
serviceAccountName string required Name of the ServiceAccount the mover pod runs as, resolved in the Job’s own namespace.
ClusterRepository spec.seed.from.backend.gdrive
Section titled “ClusterRepository spec.seed.from.backend.gdrive”
Field Type Default Description
folderId string required Google Drive folder ID that holds the kopia repository.
credentialsSecretRef object — Secret holding the Google service-account JSON used to reach the folder, read by the well-known key KOPIA_GDRIVE_CREDENTIALS. Absent means kopia falls back to ambient credentials (GOOGLE_APPLICATION_CREDENTIALS or instance metadata).
ClusterRepository spec.seed.from.backend.gdrive.credentialsSecretRef
Section titled “ClusterRepository spec.seed.from.backend.gdrive.credentialsSecretRef”
Field Type Default Description
name string required Name of the Secret.
namespace string — Namespace of the Secret; absent = same namespace as the referrer. A ClusterRepository is cluster-scoped and has no namespace of its own, so when IT reads the Secret (to connect, to bootstrap, or to run its repository server) an absent namespace means the operator’s namespace (KOPIUR_NAMESPACE). A workload mover (Snapshot/Restore/Maintenance) still needs the Secret in its OWN namespace — envFrom is namespace-local — so put it there, or use credentialProjection, which needs this namespace set EXPLICITLY to know what to copy. Set it whenever anything other than the operator itself reads the Secret.
ClusterRepository spec.seed.from.backend.rclone
Section titled “ClusterRepository spec.seed.from.backend.rclone”
Field Type Default Description
remotePath string required rclone path in remote:path form (the remote name must exist in the supplied rclone config).
configSecretRef object — Secret holding the rclone.conf that defines the remote referenced by remote_path.
startupTimeout string — How long kopia waits for its embedded rclone serve to come up before failing the connect, as a Go duration (e.g. 2m). kopia’s default is 15s; raise it for slow remotes whose repository metadata/indexes load through the rclone/WebDAV bridge and take longer than the default budget.
ClusterRepository spec.seed.from.backend.rclone.configSecretRef
Section titled “ClusterRepository spec.seed.from.backend.rclone.configSecretRef”
Field Type Default Description
name string required Name of the Secret.
namespace string — Namespace of the Secret; absent = same namespace as the referrer. A ClusterRepository is cluster-scoped and has no namespace of its own, so when IT reads the Secret (to connect, to bootstrap, or to run its repository server) an absent namespace means the operator’s namespace (KOPIUR_NAMESPACE). A workload mover (Snapshot/Restore/Maintenance) still needs the Secret in its OWN namespace — envFrom is namespace-local — so put it there, or use credentialProjection, which needs this namespace set EXPLICITLY to know what to copy. Set it whenever anything other than the operator itself reads the Secret.
ClusterRepository spec.seed.from.backend.s3
Section titled “ClusterRepository spec.seed.from.backend.s3”
Field Type Default Description
bucket string required Bucket holding the kopia repository.
auth object — Access credentials (Secret ref / workload identity).
endpoint string — S3 endpoint host. Omit for AWS; set it for MinIO/RustFS/other S3-compatible stores.
prefix string — Key prefix under the bucket, letting several repositories share one bucket (e.g. clusters/prod/). Empty/absent means the bucket root.
region string — S3 region. Required by AWS and some compatible providers.
tls object — TLS overrides for self-signed CAs or HTTP-only endpoints.
ClusterRepository spec.seed.from.backend.s3.auth
Section titled “ClusterRepository spec.seed.from.backend.s3.auth”
Field Type Default Description
secretRef object — Secret holding the backend’s static access credentials (mutually exclusive with workloadIdentity).
workloadIdentity object — Use a cloud-federated ServiceAccount instead of static keys (mutually exclusive with secretRef).
ClusterRepository spec.seed.from.backend.s3.auth.secretRef
Section titled “ClusterRepository spec.seed.from.backend.s3.auth.secretRef”
Field Type Default Description
name string required Name of the Secret.
namespace string — Namespace of the Secret; absent = same namespace as the referrer. A ClusterRepository is cluster-scoped and has no namespace of its own, so when IT reads the Secret (to connect, to bootstrap, or to run its repository server) an absent namespace means the operator’s namespace (KOPIUR_NAMESPACE). A workload mover (Snapshot/Restore/Maintenance) still needs the Secret in its OWN namespace — envFrom is namespace-local — so put it there, or use credentialProjection, which needs this namespace set EXPLICITLY to know what to copy. Set it whenever anything other than the operator itself reads the Secret.
ClusterRepository spec.seed.from.backend.s3.auth.workloadIdentity
Section titled “ClusterRepository spec.seed.from.backend.s3.auth.workloadIdentity”
Field Type Default Description
serviceAccountName string required Name of the ServiceAccount the mover pod runs as, resolved in the Job’s own namespace.
ClusterRepository spec.seed.from.backend.s3.tls
Section titled “ClusterRepository spec.seed.from.backend.s3.tls”
Field Type Default Description
caBundleRef object — CA bundle (PEM) used to verify the endpoint’s certificate, sourced from a ConfigMap.
disableTls boolean — Disable TLS entirely and talk plain HTTP; maps to kopia’s --disable-tls.
insecureSkipVerify boolean — Skip TLS certificate verification (still uses TLS); maps to kopia’s --disable-tls-verification.
ClusterRepository spec.seed.from.backend.s3.tls.caBundleRef
Section titled “ClusterRepository spec.seed.from.backend.s3.tls.caBundleRef”
Field Type Default Description
configMapName string — Name of the ConfigMap holding the value (e.g. a CA bundle). Resolved in the referrer’s namespace for a namespaced Repository, and in the operator’s namespace (KOPIUR_NAMESPACE) for a ClusterRepository (cluster-scoped, no namespace of its own).
key string — Which key inside the ConfigMap to read; defaults to ca.crt when unset.
ClusterRepository spec.seed.from.backend.sftp
Section titled “ClusterRepository spec.seed.from.backend.sftp”
Field Type Default Description
host string required SFTP server hostname or IP.
path string required Remote path on the server that holds the kopia repository.
auth object — Credentials (SSH private key / known-hosts) sourced from a Secret; Secret-only.
port integer —
min 0; max 65535
TCP port; defaults to 22 when absent.
username string — SSH username to connect as.
ClusterRepository spec.seed.from.backend.sftp.auth
Section titled “ClusterRepository spec.seed.from.backend.sftp.auth”
Field Type Default Description
secretRef object — Secret holding the backend’s access credentials, read by well-known keys.
ClusterRepository spec.seed.from.backend.sftp.auth.secretRef
Section titled “ClusterRepository spec.seed.from.backend.sftp.auth.secretRef”
Field Type Default Description
name string required Name of the Secret.
namespace string — Namespace of the Secret; absent = same namespace as the referrer. A ClusterRepository is cluster-scoped and has no namespace of its own, so when IT reads the Secret (to connect, to bootstrap, or to run its repository server) an absent namespace means the operator’s namespace (KOPIUR_NAMESPACE). A workload mover (Snapshot/Restore/Maintenance) still needs the Secret in its OWN namespace — envFrom is namespace-local — so put it there, or use credentialProjection, which needs this namespace set EXPLICITLY to know what to copy. Set it whenever anything other than the operator itself reads the Secret.
ClusterRepository spec.seed.from.backend.webDav
Section titled “ClusterRepository spec.seed.from.backend.webDav”
Field Type Default Description
url string required WebDAV collection URL holding the kopia repository.
auth object — HTTP basic-auth credentials sourced from a Secret; Secret-only.
ClusterRepository spec.seed.from.backend.webDav.auth
Section titled “ClusterRepository spec.seed.from.backend.webDav.auth”
Field Type Default Description
secretRef object — Secret holding the backend’s access credentials, read by well-known keys.
ClusterRepository spec.seed.from.backend.webDav.auth.secretRef
Section titled “ClusterRepository spec.seed.from.backend.webDav.auth.secretRef”
Field Type Default Description
name string required Name of the Secret.
namespace string — Namespace of the Secret; absent = same namespace as the referrer. A ClusterRepository is cluster-scoped and has no namespace of its own, so when IT reads the Secret (to connect, to bootstrap, or to run its repository server) an absent namespace means the operator’s namespace (KOPIUR_NAMESPACE). A workload mover (Snapshot/Restore/Maintenance) still needs the Secret in its OWN namespace — envFrom is namespace-local — so put it there, or use credentialProjection, which needs this namespace set EXPLICITLY to know what to copy. Set it whenever anything other than the operator itself reads the Secret.
ClusterRepository spec.seed.from.repository
Section titled “ClusterRepository spec.seed.from.repository”
Field Type Default Description
name string required Name of the referenced Repository/ClusterRepository.
kind enum: Repository | ClusterRepository Repository Which repository CRD this points at; defaults to RepositoryKind::Repository.
namespace string — Cross-namespace Repository reference; ignored/forbidden for ClusterRepository.
ClusterRepository spec.seed.credentialProjection
Section titled “ClusterRepository spec.seed.credentialProjection”
Field Type Default Description
enabled boolean false Copy the repository’s credential Secret(s) into the namespace of each mover Job; off by default.
Field Type Default Description
activeDeadlineSeconds integer — Mover Job.spec.activeDeadlineSeconds — wall-clock cap after which a running run is killed.
backoffLimit integer — Mover Job.spec.backoffLimit — retries before a failed run is marked failed.
podStartupDeadlineSeconds integer — Seconds a non-starting (wedged) mover pod may sit before the run is failed; default 300s.
Field Type Default Description
latestOnly boolean — Copy only each source identity’s most recent snapshot instead of its full history (kopia snapshot migrate --latest). Default false — a seed exists to recover history, so the full copy is the sane default; set this when you only need the latest restore point back quickly.
parallel integer —
min 0
--parallel: snapshots migrated concurrently (kopia default 1 — sequential). Must be >= 1 when set.
policies enum: none | copy | copyOverwrite none Whether the source’s kopia policies are copied along with the snapshots. Defaults to PolicyCopyMode::None (an explicit --no-policies), not kopia’s own copy-by-default: retention in a kopiur-managed repository is driven by Snapshot CRs, and importing the source’s kopia-side policies could delete manifests behind the operator’s back.
throttle object — Bandwidth/ops caps for THIS seed’s copy, per side. A migrate seed opens two repositories under two kopia connections and snapshot migrate has no speed flags of its own, so each side is applied as kopia repository throttle set on that side’s connection:
* source caps the REPLICA — the repository named by spec.seed.from.repository, opened read-only — overriding its moverDefaults.throttle; * destination caps THIS repository, the one being seeded, overriding its own moverDefaults.throttle.
Each side overrides field by field: a knob set here wins, a knob left unset keeps that repository’s default. Absent: both sides use their repository’s defaults. Applies only while the seed is armed — an ordinary connect to the now-initialized repository is capped by moverDefaults.throttle alone.
ClusterRepository spec.seed.migrate.throttle
Section titled “ClusterRepository spec.seed.migrate.throttle”
Field Type Default Description
destination object — Caps for the DESTINATION (write) side, overriding the destination repository’s moverDefaults.throttle field by field. Applied with repository throttle set on the destination connection the migrate writes through.
source object — Caps for the SOURCE (read) side, overriding the source repository’s moverDefaults.throttle field by field. Applied with repository throttle set on the migrate’s read-only source connection — accepted there, so a read-only source is throttled like any other.
ClusterRepository spec.seed.migrate.throttle.destination
Section titled “ClusterRepository spec.seed.migrate.throttle.destination”
Field Type Default Description
downloadBytesPerSecond integer — Cap download throughput in bytes/sec (--download-bytes-per-second).
readOpsPerSecond integer — Cap read/list ops/sec (--read-requests-per-second).
uploadBytesPerSecond integer — Cap upload throughput in bytes/sec (--upload-bytes-per-second).
writeOpsPerSecond integer — Cap write ops/sec (--write-requests-per-second).
ClusterRepository spec.seed.migrate.throttle.source
Section titled “ClusterRepository spec.seed.migrate.throttle.source”
Field Type Default Description
downloadBytesPerSecond integer — Cap download throughput in bytes/sec (--download-bytes-per-second).
readOpsPerSecond integer — Cap read/list ops/sec (--read-requests-per-second).
uploadBytesPerSecond integer — Cap upload throughput in bytes/sec (--upload-bytes-per-second).
writeOpsPerSecond integer — Cap write ops/sec (--write-requests-per-second).
Field Type Default Description
maxDownloadSpeedBytesPerSecond integer — --max-download-speed: cap read throughput from the seed source, in bytes/sec (kopia default: unlimited).
maxUploadSpeedBytesPerSecond integer — --max-upload-speed: cap write throughput into this repository, in bytes/sec (kopia default: unlimited).
parallel integer —
min 0
--parallel: concurrent blob-copy workers (kopia default 1 — sequential). Raise it: a first-time seed of a large repository over a WAN is exactly the workload sequential copying is worst at.
Field Type Default Description
namespace string required Target namespace for the server Deployment/Service (and generated Secret).
auth union — UI authentication mode; omitted ⇒ ServerAuth::Generate (never no-auth).
podSecurityContext core/v1 PodSecurityContext — Pod-level security context for the server pod (notably supplementalGroups for NFS exports).
readOnly boolean — Connect the server’s repository read-only so the UI cannot mutate backups (browse + restore only).
resources core/v1 ResourceRequirements — Resource requests/limits for the server pod.
securityContext core/v1 SecurityContext — Override the hardened default container security context.
service object — How the server is exposed as a Kubernetes Service.

Externally tagged — set exactly one of: generate · insecure · secretRef.

Field Type Default Description
generate object — The operator mints random UI credentials into an owned Secret; the safe default.
insecure object — No UI authentication; requires an explicit acknowledgeInsecure: true.
secretRef object — The user supplies UI credentials via a Secret (name + the two keys).
ClusterRepository spec.server.auth.generate
Section titled “ClusterRepository spec.server.auth.generate”
Field Type Default Description
username string — UI username to provision (default kopia).
ClusterRepository spec.server.auth.insecure
Section titled “ClusterRepository spec.server.auth.insecure”
Field Type Default Description
acknowledgeInsecure boolean false Must be true; the webhook rejects insecure mode otherwise.
ClusterRepository spec.server.auth.secretRef
Section titled “ClusterRepository spec.server.auth.secretRef”
Field Type Default Description
name string required Name of the Secret holding the UI credentials.
passwordKey string required Key within the secret holding the password.
usernameKey string required Key within the secret holding the username.
Field Type Default Description
annotations map[string]string — Annotations applied to the Service — the seam users wire their own Ingress/LoadBalancer controller onto.
port integer 51515
min 0; max 65535
Listen/Service port. Defaults to DEFAULT_SERVER_PORT when omitted.
type enum: ClusterIP | NodePort | LoadBalancer ClusterIP Service type. Defaults to ClusterIP (routing is the user’s responsibility).
Field Type Default Description
allowedNamespaceCount integer — Number of namespaces currently resolved by spec.allowedNamespaces.
backend string — Mirror of spec.backend discriminant for the print column.
catalog object — Catalog-materialization status (discovered-backup count, last refresh).
conditions []object — Standard Kubernetes conditions (e.g. Connected, MaintenanceOwned).
health object — Backend health-probe state (spec.health.probe), when enabled.
lastReverifyAt string — Last reverify-request token honored from a Snapshot’s re-probe nudge (RFC3339); the loop guard that keeps each request a one-shot.
observedGeneration integer — metadata.generation of the spec last reconciled; drives staleness detection.
parameters object — The kopia repository parameters actually observed at the last bootstrap. Compare against spec.parameters to see whether a declared value landed.
phase enum: Pending | Initializing | Ready | Degraded | Failed — Lifecycle phase of a repository. A freshly admitted CR starts in Pending.
resolvedCredentialVersion string — resourceVersion of the password Secret observed at the last connect attempt.
seed object — What the last seed attempt did (spec.seed); absent on a repository that was never seeded.
server object — Resolved kopia server endpoint/auth, pinned by the reconciler.
storageStats object — Repository size and snapshot counts from the last catalog scan.
uniqueId string — Kopia repository unique ID, pinned on the first successful bootstrap.
Its presence is the “this repository has been Ready” flag that makes auto-create one-way in time: spec.create.enabled governs the FIRST bootstrap only, and once this is set kopiur will never create a fresh empty repository over the backend, however empty the backend goes. A wiped backend therefore parks at Failed with reason RepositoryReinitializeBlocked instead of being silently re-created.
To deliberately re-initialize a wiped repository, annotate it with kopiur.home-operations.com/allow-reinitialize set to THIS value; the ack is honored only while it matches, so the new ID minted by a successful re-initialize makes it inert. This discards the history the old repository held.
Field Type Default Description
coverage enum: Complete | Capped | Partial — How much of the repository a catalog scan could see.
discoveredBackupCount integer — How many Snapshot CRs were materialized from the catalog scan.
foreignSnapshotCount integer — Snapshots in the last complete listing classified as another cluster’s (see catalog.foreignSnapshots); never materialized under Ignore. As of catalog.lastRefreshAt — enable periodicRefresh to keep it current.
lastRefreshAt string — RFC 3339 timestamp of the last catalog refresh.
scanRequestAttemptAt string — RFC 3339 timestamp of the last bootstrap/scan attempt initiated BECAUSE OF a pending catalog-scan-requested-at token (i.e. the token arm was the reason the attempt fired). Used only to rate-limit token-driven attempts on a Ready-but-unreachable repository — it is never compared against the token for retirement (that’s scanRequestHonored, by equality).
scanRequestHonored string — The RFC3339 token VALUE of the kopiur.home-operations.com/catalog-scan-requested-at annotation last honored by a completed catalog scan. Compared by equality against the live annotation to decide whether a requested on-demand scan is still pending — deliberately NOT a timestamp comparison against lastRefreshAt (a periodic refresh completing after the request was made would otherwise look like it honored the request even though it started before the annotation was set).
Field Type Default Description
lastTransitionTime string required lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable.
message string required message is a human readable message indicating details about the transition. This may be an empty string.
reason string required reason contains a programmatic identifier indicating the reason for the condition’s last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty.
status string required status of the condition, one of True, False, Unknown.
type string required type of condition in CamelCase or in foo.example.com/CamelCase.
observedGeneration integer — observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditionsx.observedGeneration is 9, the condition is out of date with respect to the current state of the instance.
Field Type Default Description
consecutiveProbeFailures integer — Consecutive failing probes accrued; reset to zero on any success. The loud condition is raised only once this reaches the failure threshold.
firstFailureAt string — RFC 3339 timestamp of the first failure in the current failing streak.
lastHealthyAt string — RFC 3339 timestamp of the last successful probe (backend reachable, repo present).
lastProbeAt string — RFC 3339 timestamp of the last completed probe (success or failure); drives the health_probe_due timer so the probe re-fires on cadence.
probeAttemptAt string — RFC 3339 timestamp at which the last backend health probe was launched (the bootstrap Job created for it), cleared when its result is finalized.
This is the launch-side rate limit, and it is what makes the probe terminate. lastProbeAt is written only at finalize, so gating the launch on that alone recycles the bootstrap Job forever: the gate destroys every Job whose completion would have cleared it (#273). Never compared against lastProbeAt — see kopiur_controller::health::probe_action.
Field Type Default Description
blobRetention object — The blob retention the repository reports.
epoch object — The epoch parameters the repository reports.
ClusterRepository status.parameters.blobRetention
Section titled “ClusterRepository status.parameters.blobRetention”
Field Type Default Description
enabled boolean required Whether the repository currently has blob retention in force (kopia’s IsRetentionEnabled(): a non-empty mode AND a non-zero period).
mode string required Observed retention mode exactly as kopia reports it (GOVERNANCE, COMPLIANCE, or empty when off).
period string required Observed retention period, as a Go-style duration (720h). Empty-equivalent (0s) when retention is off.
Field Type Default Description
advanceOnCount integer required Observed index-blob count that triggers an epoch advance.
advanceOnSizeMiB integer required Observed total index size (MiB) that triggers an epoch advance, rounded up.
kopia reports this threshold in BYTES and it need not be a whole number of MiB, so the mirror rounds up to keep a sub-MiB remainder visible rather than reporting a value the repository does not actually hold. Drift against spec is computed on the exact byte count, never on this rounded mirror.
checkpointFrequency integer required Observed epochs between full index checkpoints.
cleanupSafetyMargin string required Observed cleanup safety margin, as a Go-style duration. Reported for diagnosis; not settable through spec.parameters.
deleteParallelism integer required Observed epoch-cleanup delete parallelism.
enabled boolean required Whether kopia’s epoch manager is enabled on this repository at all.
minDuration string required Observed minimum epoch age, as a Go-style duration.
refreshFrequency string required Observed epoch-state refresh frequency, as a Go-style duration.
Field Type Default Description
mode enum: blob | migrate — Which copy mechanism a seed ran. Mirrors the SeedSource variant, named after the operation rather than the input so status, metrics (kopiur_repository_seed_total{mode}) and docs share one vocabulary.
seededAt string — RFC 3339 timestamp the seed completed. Set once: a repository is seeded exactly once, at its first bootstrap.
snapshotCount integer — Snapshots observed at the SOURCE when the seed ran. Zero is only ever recorded when allowEmptySource permitted it.
snapshotsCopied integer — Snapshots actually copied into this repository. Migrate mode only — a blob copy moves storage, not manifests, so there is no per-snapshot copy count to report and it leaves this unset; its snapshotCount is the listing taken at the SOURCE before the copy, which for a byte-for-byte mirror is also what this repository ends up holding.
source string — The source the data came from, rendered by SeedSource::describe — the backend discriminant (S3, Filesystem, …) for blob mode, Kind/name for migrate mode. Never a credential or a bucket path.
startedAt string — RFC 3339 timestamp the operator LAUNCHED a seeding bootstrap Job for this repository — the durable seed-attempt marker.
Stamped before the Job is created, and never cleared. Its whole job is to distinguish “a seed this operator started did not finish” from “this backend was initialized by somebody else”: the first must resume the copy, the second must keep the no-clobber AlreadyInitialized path. See seed_resume — the marker is the ONLY input the resume decision is allowed to take, because a resuming migrate writes into whatever repository is at the backend and then re-stamps its maintenance owner.
Field Type Default Description
authMode string — Resolved auth mode discriminant (Generate/SecretRef/Insecure).
endpoint string — In-cluster endpoint, <service>.<namespace>.svc:<port>.
generatedSecretRef object — For Generate mode: the operator-owned Secret holding the UI credentials.
namespace string — Namespace the server objects were last applied to.
readOnly boolean — Effective read-only state of the served connection.
ClusterRepository status.server.generatedSecretRef
Section titled “ClusterRepository status.server.generatedSecretRef”
Field Type Default Description
name string required Name of the Secret.
namespace string — Namespace of the Secret; absent = same namespace as the referrer. A ClusterRepository is cluster-scoped and has no namespace of its own, so when IT reads the Secret (to connect, to bootstrap, or to run its repository server) an absent namespace means the operator’s namespace (KOPIUR_NAMESPACE). A workload mover (Snapshot/Restore/Maintenance) still needs the Secret in its OWN namespace — envFrom is namespace-local — so put it there, or use credentialProjection, which needs this namespace set EXPLICITLY to know what to copy. Set it whenever anything other than the operator itself reads the Secret.
Field Type Default Description
indexBlobCount integer — Number of content-index blobs (kopia index list): the freshest count available, from either the last bootstrap or the recount a maintenance run takes right after compacting. indexBlobCountAt says when.
indexBlobCountAt string — RFC3339 instant indexBlobCount was observed.
Distinct from lastObservedAt (the catalog scan’s timestamp) and from status.health.lastProbeAt (the backend probe’s): the index-blob count has its own writers, and this is what lets the reconciler decide whether a post-maintenance recount is fresher than the bootstrap’s own count. Without it the two observations were incomparable, so the IndexBlobHealth warning could only ever quote the bootstrap figure — which is pre-compaction, and stayed pre-compaction until the next bootstrap ran (#458).
The two writers mean subtly different things, deliberately. A bootstrap stamps “when this count was FIRST seen at this value”, reusing the previous stamp while the number is unchanged — that arm re-observes on every reconcile, and a stamp that always moved would make the status always-changed and the reconcile a hot loop. A post-maintenance recount always carries its own instant, because it is a distinct observation taken at a known time and its whole purpose is to be comparable.
lastObservedAt string — RFC 3339 timestamp these stats were last observed.
snapshotCount integer — Total COMPLETE snapshots present in the repository (across all identities). Incomplete checkpoints an interrupted kopia snapshot create left behind are not snapshots and are not counted.
totalSize string — Human-readable total on-disk size (e.g. 412Gi).
totalSizeBytes integer — Logical bytes under management (the integer form of total_size): the sum, over each distinct snapshot source, of the most-recent snapshot’s logical size. Exposed to backup preflight as repository.sizeBytes. This is repository total size, not backend free space (object stores don’t report remaining capacity).

Scope: Namespaced · Short names: kopiasp · Print columns: Repository, Repositories, Last-Snapshot, Last-Verified, Suspended, Age

Externally tagged — set exactly one of: repositories · repository.

Field Type Default Description
adoption enum: Adopt | Ignore — Whether a discovered snapshot whose resolved identity matches a live SnapshotPolicy is automatically adopted — re-attached (stamped with that policy’s config label, status.origin flipped to Adopted) so GFS retention governs it and eventually prunes it, instead of it sitting in the catalog forever as an immortal discovered row.
compression object — Compression algorithm + per-extension opt-outs.
copyMethod enum: Snapshot | Clone | Direct Snapshot How the source volume is captured before kopia reads it: Snapshot (default), Direct, or Clone.
credentialProjection object — Opt-in credential-Secret projection into each backup mover’s namespace (default off).
defaultDeletionPolicy enum: Delete | Retain | Orphan Delete Lifecycle of the underlying kopia snapshot when its Snapshot CR is deleted. Produced backups default to Delete; discovered snapshots are forced to Retain.
deletion object — Deletion semantics for the Snapshot CRs carrying this recipe’s config label.
errorHandling object — Backup-side error handling: let a snapshot complete-with-errors instead of failing outright.
extraArgs []string — Escape hatch for kopia flags not yet modeled.
files object — Paths/patterns kopia should skip while snapshotting.
groupBy enum: VolumeGroupSnapshot | None VolumeGroupSnapshot Multi-PVC grouping strategy. Defaults to a consistent group snapshot across all PVCs; set None explicitly to accept independent per-PVC snapshots, because a silent per-PVC fallback would produce inconsistent backups.
hooks object — Pre/post snapshot hooks that run in the workload, not the mover.
identity object — Identity overrides — what kopia records as username@hostname:path.
mover object — Per-recipe mover overrides (resources, cache, security context).
preflight object — Named CEL preconditions evaluated before each backup run; opt-in (absent ⇒ no preflight). A failing check holds the Snapshot in Pending (PreflightFailed) and, after timeout, fails it.
repositories []object —
minItems 1; maxItems 8
Multi-repository fan-out: every listed Repository/ClusterRepository receives its own independent backup of each source — one Snapshot CR + one mover Job per (source, repository) pair, so the captures are separate kopia snapshots, not copies of one another. Identity resolves per-repo under that repository’s identityDefaults. Mutually exclusive with repository (exactly one of the two is set) AND with hooks: with N concurrent children the first finisher would run the thaw hook while the other N-1 movers still read — use a single-repo policy plus a SnapshotReplication when hooks are needed for a second target.
repository object — Discriminated reference to a Repository or ClusterRepository. Mutually exclusive with repositories (exactly one of the two is set).
retention object — GFS retention, enforced by the operator pruning Snapshot CRs.
sources []object —
maxItems 100
What to back up (at least one source; webhook-enforced).
staging object — Staging knobs for copyMethod: Snapshot/Clone (e.g. how long to wait for the CSI capture to become ready before failing the backup).
suspend boolean — Pause this recipe declaratively (schedules and reconcile skip a suspended policy).
upload object — Upload parallelism (kopia’s --max-parallel-snapshots / --max-parallel-file-reads).
verification object — First-class backup verification; opt-in (absent ⇒ no verification runs).
volumeSnapshotClassName string — VolumeSnapshotClass used when copyMethod snapshots/clones the source. Absent or empty both mean auto-select the default class for the source PVC’s CSI driver, so a GitOps-templated value (Flux/Kustomize ${VAR}) is safe when the variable is unset.
Field Type Default Description
compressor string — kopia compressor name (e.g. zstd); absent leaves kopia’s default.
neverCompress []string — Filename globs to leave uncompressed (e.g. already-compressed media).
Field Type Default Description
enabled boolean false Copy the repository’s credential Secret(s) into the namespace of each mover Job; off by default.
Field Type Default Description
onPolicyDelete enum: Retain | Delete Retain Consulted by the Snapshot finalizer when the deletion is external and the owning SnapshotPolicy is gone. Absent resolves to Retain.
Field Type Default Description
failFast boolean — Abort the snapshot at the first error instead of collecting and continuing (snapshot create --fail-fast; kopia default: false). This is a snapshot create argv flag, not a policy set knob, but lives beside its semantic opposites (ignore*Errors) for discoverability.
ignoreDirErrors boolean — Continue the snapshot when a directory cannot be read (--ignore-dir-errors).
ignoreFileErrors boolean — Continue the snapshot when a file cannot be read (--ignore-file-errors).
ignoreUnknownTypes boolean — Continue past entries of unknown type (--ignore-unknown-types).
Field Type Default Description
ignoreCacheDirs boolean — Honor CACHEDIR.TAG.
ignoreIdenticalSnapshots boolean — Skip taking a new snapshot when the source is identical to the previous one.
ignoreRules []string ["/lost+found","System Volume Information","$RECYCLE.BIN","@eaDir",".snapshot"] Filename/path globs to exclude from the snapshot (e.g. *.tmp, */cache/*). Absent ⇒ default_ignore_rules (OS-artifact junk: /lost+found, System Volume Information, $RECYCLE.BIN, @eaDir, .snapshot). An explicit list REPLACES the default wholesale (re-add any entries you still want); explicit ignoreRules: [] opts fully out. NOT skip_serializing_if — an explicit empty list must round-trip as [], not vanish back to “absent” (which would silently resurrect the default on the next parse).
Field Type Default Description
afterSnapshot []object — Hooks run (in order) after the snapshot completes — e.g. resuming the workload.
beforeSnapshot []object — Hooks run (in order) before the snapshot is taken — e.g. quiescing a database.

Externally tagged — set exactly one of: httpRequest · runJob · workloadExec.

Field Type Default Description
httpRequest object — Typed POST to a URL for cross-system orchestration.
runJob object — Full JobSpec run as a one-shot Job (k8up PreBackupPod analog).
workloadExec object — kubectl exec-style into a matched workload pod/container (the default form).
SnapshotPolicy spec.hooks.afterSnapshot[].httpRequest
Section titled “SnapshotPolicy spec.hooks.afterSnapshot[].httpRequest”
Field Type Default Description
url string required Target URL to call.
body string — Optional request body.
continueOnFailure boolean — If true, a failed request does not abort the backup (default: abort).
headers []object — Additional request headers (e.g. Content-Type: application/json).
method string — HTTP method (default POST).
timeout string — Max time to wait for the response (Go duration string).
SnapshotPolicy spec.hooks.afterSnapshot[].httpRequest.headers[]
Section titled “SnapshotPolicy spec.hooks.afterSnapshot[].httpRequest.headers[]”
Field Type Default Description
name string required Header name (case-insensitive; RFC 7230 token, e.g. Content-Type).
value string required Header value.
SnapshotPolicy spec.hooks.afterSnapshot[].runJob
Section titled “SnapshotPolicy spec.hooks.afterSnapshot[].runJob”
Field Type Default Description
jobSpec object (free-form) required The full Kubernetes JobSpec to run.
continueOnFailure boolean — If true, a failed Job does not abort the backup (default: abort).
timeout string — Max time to wait for the Job to complete (Go duration string).
SnapshotPolicy spec.hooks.afterSnapshot[].workloadExec
Section titled “SnapshotPolicy spec.hooks.afterSnapshot[].workloadExec”
Field Type Default Description
podSelector core/v1 LabelSelector required Label selector matching the workload pod(s) to read context/hooks from.
command []string — Command + args to run inside the selected container.
container string — Which container within the matched pod; absent uses the first/only container.
continueOnFailure boolean — If true, a failed hook does not abort the backup (default: abort).
timeout string — Max time to wait for the command (Go duration string, e.g. 2m).
SnapshotPolicy spec.hooks.beforeSnapshot[]
Section titled “SnapshotPolicy spec.hooks.beforeSnapshot[]”

Externally tagged — set exactly one of: httpRequest · runJob · workloadExec.

Field Type Default Description
httpRequest object — Typed POST to a URL for cross-system orchestration.
runJob object — Full JobSpec run as a one-shot Job (k8up PreBackupPod analog).
workloadExec object — kubectl exec-style into a matched workload pod/container (the default form).
SnapshotPolicy spec.hooks.beforeSnapshot[].httpRequest
Section titled “SnapshotPolicy spec.hooks.beforeSnapshot[].httpRequest”
Field Type Default Description
url string required Target URL to call.
body string — Optional request body.
continueOnFailure boolean — If true, a failed request does not abort the backup (default: abort).
headers []object — Additional request headers (e.g. Content-Type: application/json).
method string — HTTP method (default POST).
timeout string — Max time to wait for the response (Go duration string).
SnapshotPolicy spec.hooks.beforeSnapshot[].httpRequest.headers[]
Section titled “SnapshotPolicy spec.hooks.beforeSnapshot[].httpRequest.headers[]”
Field Type Default Description
name string required Header name (case-insensitive; RFC 7230 token, e.g. Content-Type).
value string required Header value.
SnapshotPolicy spec.hooks.beforeSnapshot[].runJob
Section titled “SnapshotPolicy spec.hooks.beforeSnapshot[].runJob”
Field Type Default Description
jobSpec object (free-form) required The full Kubernetes JobSpec to run.
continueOnFailure boolean — If true, a failed Job does not abort the backup (default: abort).
timeout string — Max time to wait for the Job to complete (Go duration string).
SnapshotPolicy spec.hooks.beforeSnapshot[].workloadExec
Section titled “SnapshotPolicy spec.hooks.beforeSnapshot[].workloadExec”
Field Type Default Description
podSelector core/v1 LabelSelector required Label selector matching the workload pod(s) to read context/hooks from.
command []string — Command + args to run inside the selected container.
container string — Which container within the matched pod; absent uses the first/only container.
continueOnFailure boolean — If true, a failed hook does not abort the backup (default: abort).
timeout string — Max time to wait for the command (Go duration string, e.g. 2m).
Field Type Default Description
hostname string — Override the hostname portion of username@hostname:path; absent uses the resolved default.
username string — Override the username portion of username@hostname:path; absent uses the resolved default.
Field Type Default Description
cache object — Override the repository’s CacheDefaults for this recipe’s movers.
inheritSecurityContextFrom union — Copy the UID/GID security context from a live workload rather than hard-coding it.
Requires the workload to pin runAsUser (container or pod level): a UID that comes from the container image’s USER line is invisible in the pod spec and cannot be inherited — the mover would silently run as its own image’s UID instead.
May be combined with securityContext/podSecurityContext, which override it field-wise and act as the fallback when no workload pod can be resolved.
podSecurityContext core/v1 PodSecurityContext — Pod security context for the mover (notably fsGroup for group-writable restore volumes). Same layering as securityContext: highest layer, merged field-wise, and combinable with inheritSecurityContextFrom.
privilegedMode boolean — Opt-in, namespace-gated privileged mode. Never changes the UID. When the mover runs as root (runAsUser: 0), adds the capabilities the operation needs on top of drop: ALL: DAC_OVERRIDE for a backup (read files owned by any uid/gid); CHOWN, DAC_OVERRIDE, FOWNER, FSETID for a restore (reproduce original ownership). Grants nothing for maintenance, or when the mover does not run as root (capabilities are inert for non-root); set runAsUser: 0 yourself.
resources core/v1 ResourceRequirements — Resource requests/limits for the mover container.
securityContext core/v1 SecurityContext — Container security context for the mover; merged field-wise over the hardened base, moverDefaults, and any inherited context — this is the highest layer, so every field set here wins. Combines with inheritSecurityContextFrom: fields you set override the workload’s, fields you omit are inherited, and this context stands in alone when inheritance cannot resolve a pod.
ttlSecondsAfterFinished integer — Per-recipe override of Job.spec.ttlSecondsAfterFinished so finished Jobs self-GC.
Field Type Default Description
capacity string — Size of the PVC backing the mover’s kopia cache (e.g. 10Gi).
contentCacheSizeMb integer — kopia content cache budget in MiB (--content-cache-size-mb).
metadataCacheSizeMb integer — kopia metadata cache budget in MiB (--metadata-cache-size-mb).
mode enum: Ephemeral | Persistent — How a mover’s kopia cache volume is provisioned.
storageClassName string — StorageClass for the cache PVC; absent uses the cluster default.
SnapshotPolicy spec.mover.inheritSecurityContextFrom
Section titled “SnapshotPolicy spec.mover.inheritSecurityContextFrom”

Externally tagged — set exactly one of: pvcConsumer · snapshot · workloadSelector.

Field Type Default Description
pvcConsumer object — Backup sources only: auto-derive the workload from the PVC this snapshot backs up.
snapshot object — Restores only: inherit the identity RECORDED on the backup itself (Snapshot.status.recorded, decoded from the kopiur-meta kopia tag) — uid/gid/fsGroup the backup mover actually ran as. Needs no live workload pod, so it works on a rebuilt cluster and with target.populator. Rejected at admission on SnapshotPolicy/Maintenance (backups read the live workload; maintenance has no snapshot). Write it as snapshot: {} (an empty sub-object) — a bare snapshot: is null and rejected.
workloadSelector object — Inherit from workload pod(s) matched by an explicit label selector (backup or restore).
SnapshotPolicy spec.mover.inheritSecurityContextFrom.pvcConsumer
Section titled “SnapshotPolicy spec.mover.inheritSecurityContextFrom.pvcConsumer”
Field Type Default Description
container string — Which container within the matched consumer pod to inherit from; absent uses the first/only.
SnapshotPolicy spec.mover.inheritSecurityContextFrom.workloadSelector
Section titled “SnapshotPolicy spec.mover.inheritSecurityContextFrom.workloadSelector”
Field Type Default Description
podSelector core/v1 LabelSelector required Label selector matching the workload pod(s) to read context/hooks from.
container string — Which container within the matched pod; absent uses the first/only container.
Field Type Default Description
checks []object —
maxItems 50
Checks that must all pass (AND) before the backup launches. An empty list is an inert no-op (symmetric with verification absent).
timeout string — How long to hold a Snapshot in Pending while a check is unsatisfied before failing it (Go-style duration like 10m or 1h; default 10m). A zero duration (0/0s) holds indefinitely (never fail on preflight).
Field Type Default Description
expr string required CEL bool predicate; the backup proceeds only when this evaluates true.
name string required
minLength 1; maxLength 63
Stable identifier surfaced in the Snapshot’s status when this check blocks (e.g. maintenance-fresh). Unique within the policy.
message string — Optional human message surfaced alongside the check name when it blocks.
Field Type Default Description
name string required Name of the referenced Repository/ClusterRepository.
kind enum: Repository | ClusterRepository Repository Which repository CRD this points at; defaults to RepositoryKind::Repository.
namespace string — Cross-namespace Repository reference; ignored/forbidden for ClusterRepository.
Field Type Default Description
name string required Name of the referenced Repository/ClusterRepository.
kind enum: Repository | ClusterRepository Repository Which repository CRD this points at; defaults to RepositoryKind::Repository.
namespace string — Cross-namespace Repository reference; ignored/forbidden for ClusterRepository.
Field Type Default Description
keepAnnual integer —
min 0
Keep one snapshot per year for the most-recent N years.
keepDaily integer —
min 0
Keep one snapshot per day for the most-recent N days.
keepHourly integer —
min 0
Keep one snapshot per hour for the most-recent N hours.
keepLatest integer —
min 0
Keep the N most-recent snapshots regardless of age.
keepMonthly integer —
min 0
Keep one snapshot per month for the most-recent N months.
keepWeekly integer —
min 0
Keep one snapshot per week for the most-recent N weeks.

Externally tagged — set exactly one of: nfs · pvc · pvcSelector · stream.

Field Type Default Description
acknowledgeLiveMutation boolean — Acknowledges that copyMethod: Direct + readOnly: false lets the kubelet recursively chgrp the live volume to the mover’s fsGroup and make it group-writable — permanently, while the workload is running. Required for that combination alone.
Ignored (not rejected) otherwise: it is an acknowledgement, never harmful to carry, and rejecting a stale one would make switching copyMethod between Direct and Snapshot/Clone a two-step edit in both directions.
nfs object — An inline NFS export to back up directly. Mutually exclusive with pvc/pvcSelector/stream.
pvc object — Single PVC by name. Mutually exclusive with pvcSelector/nfs.
pvcSelector object — Label/namespace selector matching many PVCs. Mutually exclusive with pvc/nfs.
readOnly boolean true Mount the source read-only (default true; kopia only ever reads it).
Set false only to make fsGroup work on the source. The kubelet applies fsGroup by recursively chgrp-ing the volume and adding group-write — and it skips that walk entirely on a read-only mount, which is why a mover fsGroup/fsGroupChangePolicy otherwise has no effect here. Under copyMethod: Snapshot/Clone the walk rewrites the throwaway staged PVC and never touches your data. Under copyMethod: Direct it rewrites the LIVE volume, which requires acknowledgeLiveMutation.
Not supported on an nfs source: the kubelet does not apply fsGroup to in-tree NFS volumes at all, so a read-write mount would grant nothing.
sourcePathOverride string —
maxLength 4096
What kopia records as the source path (default /pvc/<name>, or the NFS export path).
On a pvcSelector source this is a footgun. It is ONE literal path, so it works only while the selector matches exactly one PVC; the moment a second PVC matches, both would land on that same kopia source, merging their histories into one stream where they also prune each other, so the BACKUP is refused at run time and no further snapshots are minted for that source.
Watch the failed schedule fire, not verification: the earlier snapshots remain at that path, so verification keeps passing while backups have stopped. (Verification only fails on a path that never received a backup.) Prefer sourcePathStrategy, which derives a distinct path per PVC, or put the override on its own pvc: source.
sourcePathStrategy enum: PvcName | PvcNamespacedName PvcName How a selector-matched PVC’s source path is derived. Only relevant for pvcSelector sources, where one recipe expands to many PVCs and each needs a distinct kopia source path. Defaults to PvcName.
stream object — Capture a command’s standard output as one virtual file — a logical backup (pg_dumpall, mysqldump, …) rather than a volume copy. Mutually exclusive with pvc/pvcSelector/nfs. No volume is mounted; the mover execs the command in a running workload Pod and streams its stdout straight into kopia.
Field Type Default Description
path string required Exported path on the NFS server (e.g. /export/kopia or /mnt/eros/Media).
server string required NFS server hostname or IP (e.g. nas.lan or expanse.internal).
Field Type Default Description
name string required Name of the PersistentVolumeClaim to back up (in the SnapshotPolicy’s namespace).
Field Type Default Description
labelSelector core/v1 LabelSelector — Standard Kubernetes label selector matching the PVCs to include.
namespaceSelector object — Restricts the search to specific namespaces; absent means the policy’s own namespace.
SnapshotPolicy spec.sources[].pvcSelector.namespaceSelector
Section titled “SnapshotPolicy spec.sources[].pvcSelector.namespaceSelector”
Field Type Default Description
matchNames []string — Exact namespace names to search; empty means the policy’s own namespace.
Field Type Default Description
fileName string required
minLength 1; maxLength 255
Name of the single virtual file stored in the snapshot (e.g. postgres.sql).
Must be ONE file name: no /, and not . or ... kopia stores this string verbatim as the entry name and does not sanitize it, so a path-shaped value would make a later kopia restore write OUTSIDE its destination directory.
workloadExec object required The producer: what to run, and where. Its stdout IS the backup data.
SnapshotPolicy spec.sources[].stream.workloadExec
Section titled “SnapshotPolicy spec.sources[].stream.workloadExec”
Field Type Default Description
command []string required
minItems 1
The argv to execute. NOT a shell line: element 0 is the program, so use ["sh", "-ec", "..."] explicitly if you want shell semantics.
Reference credentials through the container’s existing environment or mounted Secrets — never inline them here. This argv is copied into the mover Pod’s spec, so anyone with pods:get in the namespace can read it.
podSelector core/v1 LabelSelector required Standard label selector identifying the workload Pod, resolved in the SnapshotPolicy’s (or Restore’s) own namespace. Must not be empty — an empty selector matches every Pod in the namespace.
container string — Container to exec in; absent uses the Pod’s default container.
timeout string 1h Go duration bounding the command (e.g. 2h; default 1h). On expiry the command is abandoned and the run fails, leaving no snapshot behind.
The same bound applies whether this exec is a backup’s producer or a streamExec restore’s consumer.
Field Type Default Description
accessModes []enum: ReadWriteOnce | ReadOnlyMany | ReadWriteMany | ReadWriteOncePod — Access modes for the staged PVC. Empty ⇒ copy the source PVC’s modes. ReadOnlyMany pairs with snapshot-backed read-only classes (e.g. CephFS backingSnapshot); the mover mounts the staged PVC read-only to match, and rejects it at admission if a source sets readOnly: false (a read-only stage cannot be mounted read-write).
storageClassName string — StorageClass for the staged PVC — the temporary PVC restored from the CSI VolumeSnapshot (copyMethod: Snapshot) or cloned from the source (copyMethod: Clone). Absent ⇒ the staged PVC copies the source PVC’s class. Must belong to the same CSI driver as the source (staging fails fast on a mismatch). Flagship use: a rook-ceph CephFS class with backingSnapshot: "true", which mounts the snapshot shallowly (metadata-only, near-instant, read-only) instead of running a full subvolume clone that can take many minutes on small-file-heavy volumes.
timeout string — How long each staging phase may take before the backup is failed (Go-style duration like 10m or 1h; default 10m): first the staged VolumeSnapshot becoming readyToUse (measured from its creation), then — on an Immediate-binding StorageClass — the staged PVC binding (a fresh budget measured from the PVC’s creation, covering the CSI restore/clone). A transient CSI/snapshot-controller error during either wait is retried, never fatal on its own — only this deadline fails staging. A zero duration (0/0s) waits indefinitely. Raise this for backends whose snapshots or clones take long (e.g. cloud snapshots of large volumes, CephFS full clones of small-file-heavy volumes).
Field Type Default Description
limitMb integer — snapshot create --upload-limit-mb: abort the snapshot once this many MB have been uploaded (kopia default: 0 — unlimited). Named limitMb rather than uploadLimitMb to avoid the upload.uploadLimitMb stutter; like failFast, this is a snapshot create argv flag, not a policy set knob, but lives here beside its parallelism siblings.
maxParallelFileReads integer — --max-parallel-file-reads: file-read concurrency within a snapshot.
maxParallelSnapshots integer — --max-parallel-snapshots: how many sources snapshot concurrently.
Field Type Default Description
deep object — Schedule + knobs for the rarer scratch-restore test; absent ⇒ no deep verification.
quick object — Quick (blob-level) verification tier; absent ⇒ no quick verification. Its cron lives under quick.schedule (matching deep.schedule), see QuickVerification.
successExpr string — CEL pass/fail predicate over the verify result; applies to both tiers.
verifyFilesPercent integer —
min 0; max 255
How many files quick verifies fully (--verify-files-percent); absent leaves kopia’s default.
Field Type Default Description
schedule object required Cron + jitter for the deep restore-test (e.g. weekly).
capacity string — Size of the ephemeral scratch PVC (e.g. 10Gi); absent falls back to a node-ephemeral emptyDir.
parallel integer —
min 0
restore --parallel: restore parallelism for the scratch-restore (deep verify IS a restore under the hood); absent leaves kopia’s default.
storageClassName string — StorageClass for the ephemeral scratch PVC; absent uses the cluster default (only with capacity).
SnapshotPolicy spec.verification.deep.schedule
Section titled “SnapshotPolicy spec.verification.deep.schedule”
Field Type Default Description
cron string required The cron expression, parsed by croner; may contain an H placeholder for deterministic jitter.
jitter string — Optional deterministic jitter window as a Go-style duration string (e.g. 30m).
timezone string — IANA timezone the cron is evaluated in (e.g. America/Chicago); absent uses the enclosing schedule’s timezone, else the controller default (UTC).
Field Type Default Description
fileParallelism integer —
min 0
--file-parallelism: parallelism for file verification (kopia default: unset).
fileQueueLength integer —
min 0
--file-queue-length: queue length for file verification (kopia default: 20000).
maxErrors integer —
min 0
--max-errors: stop after this many errors (kopia default: 0, meaning stop at the first error).
parallel integer —
min 0
--parallel: verification parallelism (kopia default: 8).
schedule object — Cron + jitter + timezone for the frequent blob-level verify; absent ⇒ quick tier disabled.
SnapshotPolicy spec.verification.quick.schedule
Section titled “SnapshotPolicy spec.verification.quick.schedule”
Field Type Default Description
cron string required The cron expression, parsed by croner; may contain an H placeholder for deterministic jitter.
jitter string — Optional deterministic jitter window as a Go-style duration string (e.g. 30m).
timezone string — IANA timezone the cron is evaluated in (e.g. America/Chicago); absent uses the enclosing schedule’s timezone, else the controller default (UTC).
Field Type Default Description
adoption object — Summary of automatic adoption of discovered snapshots into this recipe.
conditions []object — Standard Kubernetes conditions (e.g. RepositoryReachable, GroupSnapshotSupported).
lastSuccessfulSnapshot string — RFC3339 timestamp of the most recent successful child Snapshot from this recipe.
lastVerified string — RFC3339 timestamp of the most recent successful verification (any tier).
Verification runs once per (repository x source) cell: a spec.repositories fan-out adds the repository dimension, and a pvcSelector source adds one cell per matched PVC (each has its own kopia source path, so each needs its own verification).
* one repository AND a non-selector source (pvc/nfs): stamped directly by the verify mover, exactly as before; * otherwise — a spec.repositories fan-out, or ANY pvcSelector source (including one currently matching a single PVC): computed by the controller as the MINIMUM across the CURRENT cells (“everything is verified as of T”), and absent until EVERY current cell has verified at least once — a partially verified policy must not display a reassuring timestamp.
observedGeneration integer — metadata.generation last reconciled, for staleness detection.
repositorySummary string — Human-readable summary of the policy’s repository target(s) for the Repositories print column: the comma-joined repository names (the one name for the single-repo shape), capped near a kubectl column width with a +N overflow marker. Written by the controller.
resolved object — What would be passed to kopia — pinned at admission.
retention object — Summary of GFS retention pruning against this config’s Snapshot CRs.
verification []object — Per-repository verification records for a multi-repository policy (#368): one entry per CURRENT spec.repositories member, maintained by the controller (single writer — entries for repositories no longer in the spec are pruned). Empty (elided) for the single-repo shape, whose wire stays byte-identical.
verificationStamps map[string]string — Internal write channel for per-cell verification: RFC3339 markers keyed by the (repository x source) cell a verify run covered.
Key shapes, where the repository segment is the normalized repository key (repo_key) and the member segment is a stable 12-hex tag over the matched PVC’s derived kopia source path:
* <repository> — a spec.repositories fan-out with a single source; * <repository>#<member> — a fan-out over both dimensions; * #<member> — one repository, a pvcSelector source (the repository segment is empty).
# is the separator because a repository key cannot contain one.
Each verify mover merge-patches ONLY its own key — a JSON merge patch merges map keys, so concurrent cells can never clobber one another (a Vec would be replaced wholesale). The controller folds these into verification and lastVerified on its next pass and prunes keys whose repository or matched PVC is gone. Not written when the policy targets one repository with a non-selector source, whose wire stays byte-identical; a pvcSelector source always uses this map, even while it matches a single PVC.
Field Type Default Description
lastAdoptedCount integer —
min 0
Number of discovered Snapshot CRs adopted by the last adoption pass.
lastAdoptionAt string — RFC3339 timestamp of the last adoption pass that adopted at least one snapshot.
lastScanMatched integer —
min 0
Discovered snapshots whose kopia identity matched this policy at the most recent adoption pass, counted BEFORE the own-id and retention filters — so it reads “history relevant to me exists in the catalog”, independent of whether that pass adopted anything. A multi-repository policy SUMS this across the ready repositories of the pass. 0 together with lastScanUnmatched: 0 means the catalog was empty at that pass; absent means no adoption pass has run yet. Neutral inventory, not a verdict: 0 matched beside a non-zero lastScanUnmatched is the ordinary shape of a new policy on a shared repository, and is also what a post-disaster-recovery identity mismatch looks like — compare status.resolved.identity with the pre-disaster configuration to tell them apart.
lastScanUnmatched integer —
min 0
Discovered snapshots the most recent adoption pass saw that did NOT match this policy’s identity (other policies’ or other clusters’ history in a shared repository). Same counting rules as lastScanMatched: pre-filter, summed across a multi-repository policy’s ready repositories, 0/0 for an empty catalog, absent when no pass has run.
scanRequestedAt string — RFC3339 token echoing an in-flight on-demand adoption scan request for this policy’s identity; cleared once honored.
scanRequestedIdentity string — The resolved kopia identity the requested scan was scoped to, pinned at request time so a later identity-changing edit can’t retarget an in-flight scan.
skippedByRetention integer —
min 0
Identity-matching discovered snapshots the last adoption pass left discovered because spec.retention would prune them immediately under the effective deletionPolicy (Retain/Orphan — a CR-only prune that would re-discover and re-adopt forever). 0/absent when nothing was withheld. See the AdoptionSkippedByRetention event for the levers.
totalAdopted integer —
min 0
Running total of Snapshot CRs ever adopted into this recipe.
Field Type Default Description
lastTransitionTime string required lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable.
message string required message is a human readable message indicating details about the transition. This may be an empty string.
reason string required reason contains a programmatic identifier indicating the reason for the condition’s last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty.
status string required status of the condition, one of True, False, Unknown.
type string required type of condition in CamelCase or in foo.example.com/CamelCase.
observedGeneration integer — observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditionsx.observedGeneration is 9, the condition is out of date with respect to the current state of the instance.
Field Type Default Description
identity object — The resolved username@hostname identity.
repositories []object — Per-repository resolution for a MULTI-repository policy (spec.repositories): one entry per member, each carrying the identity resolved under THAT repository’s identityDefaults (the unit of identity is the (repository, identity) pair — N members means N independent kopia lineages). Empty — and elided from the wire — for the classic single-repo shape, whose resolution stays in the top-level identity/sources fields exactly as before this field existed.
sources []object — The concrete PVCs + source paths after selector expansion.
Field Type Default Description
hostname string required The final hostname kopia records, fixed at admission.
username string required The final username kopia records, fixed at admission.
sourcePath string — The resolved snapshot source path, when applicable (username@hostname:path).
SnapshotPolicy status.resolved.repositories[]
Section titled “SnapshotPolicy status.resolved.repositories[]”
Field Type Default Description
repository object required The member repository this entry resolves for (by value, as listed in spec.repositories).
identity object — The username@hostname identity resolved under this repository’s identityDefaults; absent when it could not be resolved (the guard treats an absent baseline as “no baseline” and degrades to allow for that member only).
SnapshotPolicy status.resolved.repositories[].repository
Section titled “SnapshotPolicy status.resolved.repositories[].repository”
Field Type Default Description
name string required Name of the referenced Repository/ClusterRepository.
kind enum: Repository | ClusterRepository Repository Which repository CRD this points at; defaults to RepositoryKind::Repository.
namespace string — Cross-namespace Repository reference; ignored/forbidden for ClusterRepository.
SnapshotPolicy status.resolved.repositories[].identity
Section titled “SnapshotPolicy status.resolved.repositories[].identity”
Field Type Default Description
hostname string required The final hostname kopia records, fixed at admission.
username string required The final username kopia records, fixed at admission.
sourcePath string — The resolved snapshot source path, when applicable (username@hostname:path).
Field Type Default Description
pvc string — namespace/name of the PVC, as kopia sees it.
sourcePath string — The source path kopia records for this PVC.
Field Type Default Description
activeSnapshotCount integer — CRs currently inside the GFS window.
lastPruneAt string — RFC3339 timestamp of the last prune pass.
lastPruneDeleted integer — Number of Snapshot CRs deleted by the last prune pass.
Field Type Default Description
repository object required The repository this record covers, normalized (normalized_repository_ref) so it re-resolves from anywhere.
lastVerified string — RFC3339 timestamp of the most recent successful verification (any tier) against THIS repository; absent until its first successful verify.
When the policy’s source is a pvcSelector, this is the MINIMUM across that repository’s matched PVCs, and absent until every one of them has verified — a repository whose volumes are only partly verified must not look fully verified.
SnapshotPolicy status.verification[].repository
Section titled “SnapshotPolicy status.verification[].repository”
Field Type Default Description
name string required Name of the referenced Repository/ClusterRepository.
kind enum: Repository | ClusterRepository Repository Which repository CRD this points at; defaults to RepositoryKind::Repository.
namespace string — Cross-namespace Repository reference; ignored/forbidden for ClusterRepository.

Scope: Namespaced · Short names: kopiasnap · Print columns: Phase, Origin, Snapshot, Source, Age

Field Type Default Description
deletionPolicy enum: Delete | Retain | Orphan — Lifecycle of the underlying kopia snapshot when its Snapshot CR is deleted. Produced backups default to Delete; discovered snapshots are forced to Retain.
description string —
maxLength 1024
Free-form text recorded on the kopia snapshot manifest (snapshot create --description). Per-invocation by nature — scheduled/discovered Snapshots never set this (no templated descriptions).
failurePolicy object — Mover Job retry and deadline limits for this run.
mover object — Per-run mover overrides for THIS snapshot’s Job (resources, cache budgets, securityContext, privilegedMode, ttlSecondsAfterFinished).
Layered field-wise as repository.moverDefaults < policyRef's mover < this mover — the highest layer that sets a field wins, and a field you omit falls through, so a partial override here can only adjust what it names. This exists so an ad-hoc one-shot (kubectl create before a risky change, a debug run that needs more memory or a different UID) does not require editing the shared, GitOps-managed SnapshotPolicy that every scheduled run also uses.
Two deliberate exclusions:
* mover.cache here is run-scoped only. It sets this run’s kopia cache budgets (--content-cache-size-mb/--metadata-cache-size-mb) and, when the cache is Ephemeral, that Job’s cache-volume capacity and storageClassName — a generic ephemeral volume bound to this pod and GC’d with it. What it cannot touch is anything shared: cache.mode is policy-owned (a per-run mode: Persistent never mints the shared PVC), and under mode: Persistent the PVC’s own capacity/ storageClassName come from the policy alone, because that claim is named per-POLICY and every sibling Snapshot depends on it.
* inheritSecurityContextFrom.snapshot is restore-only and rejected here, exactly as on SnapshotPolicy: a backup’s identity comes from the live workload; it is the run that records an identity.
An elevated mover assembled here is gated by the namespace’s privileged-movers opt-in just like a policy-level one — the gate runs on the merged result.
onScheduleDelete enum: Retain | Delete — What the deletion of a SnapshotSchedule does to the Snapshot CRs it produced (which Kubernetes GC cascade-deletes via their ownerReference). Default Retain: the CRs are removed but their kopia snapshots survive and the catalog rediscovers them as origin: discovered. Delete opts into the cascade: each Snapshot’s own deletionPolicy applies.
Deliberately 2-variant (not reusing DeletionPolicy): an Orphan in cascade position would differ from Retain only in per-CR event/metric bookkeeping — an invalid state made unrepresentable. The guard’s Retain is exactly DeletionPolicy::Retain’s semantics (CR removed, kopia snapshot stays, catalog rediscovers it), deliberately NOT the Orphan event storm (no per-CR “orphaned” event/metric for every produced Snapshot).
pin boolean — Exempt this snapshot from GFS retention.
policyRef object — The SnapshotPolicy recipe to run; absent for discovered backups.
repository object — The ONE repository this Snapshot targets, pinned by value at mint time. Stamped by a multi-repository SnapshotPolicy fan-out (each child covers exactly one member of the policy’s repository set) and by SnapshotReplication copy CRs (the destination repository). Absent for the legacy single-repository case, where the policy’s own spec.repository (or, for catalog rows, the owning repository CR) is the answer — an absent pin resolves exactly as before this field existed, so pre-feature Snapshots are untouched.
source object — The ONE concrete source this Snapshot covers, when policyRef names a recipe whose sources[] expands to many — i.e. a pvcSelector.
Stamped by whoever minted the CR: a SnapshotSchedule fire, or kubectl kopiur snapshot now. Absent for the ordinary single-source case, where the policy’s own sources0 is the target.
Absent against a selector policy is refused rather than guessed. The operator must never pick a PVC on the user’s behalf: silently backing up one arbitrary volume out of N looks exactly like success.
tags map[string]string — Free-form tags attached to the kopia snapshot manifest itself (snapshot create --tags), e.g. reason: pre-upgrade — durable in the repository, independent of this CR. Keys must be non-empty, colon-free (kopia splits on the first colon), and must not start with the reserved kopiur prefix; at most 10 tags, keys ≤ 63 bytes, values ≤ 256 bytes (webhook-enforced).
Field Type Default Description
activeDeadlineSeconds integer — Mover Job.spec.activeDeadlineSeconds — wall-clock cap after which a running run is killed.
backoffLimit integer — Mover Job.spec.backoffLimit — retries before a failed run is marked failed.
podStartupDeadlineSeconds integer — Seconds a non-starting (wedged) mover pod may sit before the run is failed; default 300s.
Field Type Default Description
cache object — Override the repository’s CacheDefaults for this recipe’s movers.
inheritSecurityContextFrom union — Copy the UID/GID security context from a live workload rather than hard-coding it.
Requires the workload to pin runAsUser (container or pod level): a UID that comes from the container image’s USER line is invisible in the pod spec and cannot be inherited — the mover would silently run as its own image’s UID instead.
May be combined with securityContext/podSecurityContext, which override it field-wise and act as the fallback when no workload pod can be resolved.
podSecurityContext core/v1 PodSecurityContext — Pod security context for the mover (notably fsGroup for group-writable restore volumes). Same layering as securityContext: highest layer, merged field-wise, and combinable with inheritSecurityContextFrom.
privilegedMode boolean — Opt-in, namespace-gated privileged mode. Never changes the UID. When the mover runs as root (runAsUser: 0), adds the capabilities the operation needs on top of drop: ALL: DAC_OVERRIDE for a backup (read files owned by any uid/gid); CHOWN, DAC_OVERRIDE, FOWNER, FSETID for a restore (reproduce original ownership). Grants nothing for maintenance, or when the mover does not run as root (capabilities are inert for non-root); set runAsUser: 0 yourself.
resources core/v1 ResourceRequirements — Resource requests/limits for the mover container.
securityContext core/v1 SecurityContext — Container security context for the mover; merged field-wise over the hardened base, moverDefaults, and any inherited context — this is the highest layer, so every field set here wins. Combines with inheritSecurityContextFrom: fields you set override the workload’s, fields you omit are inherited, and this context stands in alone when inheritance cannot resolve a pod.
ttlSecondsAfterFinished integer — Per-recipe override of Job.spec.ttlSecondsAfterFinished so finished Jobs self-GC.
Field Type Default Description
capacity string — Size of the PVC backing the mover’s kopia cache (e.g. 10Gi).
contentCacheSizeMb integer — kopia content cache budget in MiB (--content-cache-size-mb).
metadataCacheSizeMb integer — kopia metadata cache budget in MiB (--metadata-cache-size-mb).
mode enum: Ephemeral | Persistent — How a mover’s kopia cache volume is provisioned.
storageClassName string — StorageClass for the cache PVC; absent uses the cluster default.
Snapshot spec.mover.inheritSecurityContextFrom
Section titled “Snapshot spec.mover.inheritSecurityContextFrom”

Externally tagged — set exactly one of: pvcConsumer · snapshot · workloadSelector.

Field Type Default Description
pvcConsumer object — Backup sources only: auto-derive the workload from the PVC this snapshot backs up.
snapshot object — Restores only: inherit the identity RECORDED on the backup itself (Snapshot.status.recorded, decoded from the kopiur-meta kopia tag) — uid/gid/fsGroup the backup mover actually ran as. Needs no live workload pod, so it works on a rebuilt cluster and with target.populator. Rejected at admission on SnapshotPolicy/Maintenance (backups read the live workload; maintenance has no snapshot). Write it as snapshot: {} (an empty sub-object) — a bare snapshot: is null and rejected.
workloadSelector object — Inherit from workload pod(s) matched by an explicit label selector (backup or restore).
Snapshot spec.mover.inheritSecurityContextFrom.pvcConsumer
Section titled “Snapshot spec.mover.inheritSecurityContextFrom.pvcConsumer”
Field Type Default Description
container string — Which container within the matched consumer pod to inherit from; absent uses the first/only.
Snapshot spec.mover.inheritSecurityContextFrom.workloadSelector
Section titled “Snapshot spec.mover.inheritSecurityContextFrom.workloadSelector”
Field Type Default Description
podSelector core/v1 LabelSelector required Label selector matching the workload pod(s) to read context/hooks from.
container string — Which container within the matched pod; absent uses the first/only container.
Field Type Default Description
name string required Name of the referenced SnapshotPolicy.
namespace string — Namespace of the SnapshotPolicy; absent = same namespace as the referrer.
Field Type Default Description
name string required Name of the referenced Repository/ClusterRepository.
kind enum: Repository | ClusterRepository Repository Which repository CRD this points at; defaults to RepositoryKind::Repository.
namespace string — Cross-namespace Repository reference; ignored/forbidden for ClusterRepository.
Field Type Default Description
sourceIndex integer required
min 0
Zero-based index into policyRef’s spec.sources this child expanded from.
Pins WHICH source’s knobs (readOnly, sourcePathOverride, sourcePathStrategy, acknowledgeLiveMutation) govern this run, so a policy carrying several sources stays unambiguous. An index that is out of range at reconcile time — the policy shrank mid-run — is a named terminal failure, never a silent fallback to sources0.
target union required What the expansion resolved to.
group object — The consistency group this child belongs to, present only when the policy asked for one (groupBy: VolumeGroupSnapshot) AND the expansion produced more than one member in this namespace.

Externally tagged — set exactly one of: pvc.

Field Type Default Description
pvc object — One PersistentVolumeClaim, fully qualified.
Field Type Default Description
name string required Name of the matched PersistentVolumeClaim.
namespace string required Namespace of the matched PersistentVolumeClaim.
Explicit rather than inferred from the Snapshot’s own namespace: a pvcSelector under a ClusterRepository may match across namespaces.
Field Type Default Description
namespace string required Namespace the VolumeGroupSnapshot lives in.
A VolumeGroupSnapshot is namespaced and its source.selector is namespace-local, so a selector spanning namespaces yields ONE GROUP PER NAMESPACE, not one group. The consistency guarantee is per-namespace and this field is where that shows.
volumeGroupSnapshotName string required Name of the shared VolumeGroupSnapshot.
Field Type Default Description
cleanup object — Post-run cleanup bookkeeping, so each cleanup runs at most once per Snapshot.
conditions []object — Standard Kubernetes conditions (e.g. SourcesQuiesced, SnapshotCreated).
copiedFrom object — Lineage for origin: replicated rows: the source repository, source manifest id, and startTime the copy was migrated from. Written by the SnapshotReplication mover in the same atomic PATCH as status.snapshot; absent on every other origin. See CopiedFrom for why this lives on the CR rather than as kopia tags.
failure object — Structured terminal-failure detail (kopia error class, stderr tail, retry hint).
hooks object — Hook-execution bookkeeping so each hook list runs exactly once per Snapshot.
job object — The mover Job backing this run; absent for discovered.
logTail string — The last lines of the run’s output, written by the mover at the terminal transition.
observedGeneration integer — metadata.generation last reconciled, for staleness detection.
origin enum: scheduled | manual | discovered | adopted | replicated — How a Snapshot came to exist. Canonical value mirrored from the kopiur.home-operations.com/origin label. Origin drives the deletion-policy default: discovered backups are forced to Retain because the operator did not create those snapshots.
phase enum: Pending | Running | Succeeded | Failed | Deleting | Discovered | Unchanged — Lifecycle phase of a Snapshot.
pinned boolean — The observed kopia-side pin state: Some(true) if pinned, Some(false) if unpinned, None before any pin reconcile.
preflightSince string — RFC 3339 timestamp of the first reconcile where the repository was Ready but a spec.preflight check was failing. The one-shot anchor for the preflight timeout deadline (so the budget covers preflight only, not the earlier repository-not-Ready wait). Cleared once every preflight check passes, so a later failing episode gets a fresh budget rather than a stale anchor.
recorded object — The mover identity recorded on the kopia snapshot itself (the kopiur-meta tag): the resolved effective uid/gid/fsGroup the backup ran as, plus its provenance. Produced runs stamp this at launch (from the same value written into the tag); discovered rows decode it from the tag during the catalog scan. Absent for pre-feature snapshots, foreign backups without the tag, or a tag this operator version cannot decode.
resolved object — Frozen recipe values at run time (scheduled/manual).
snapshot object — The kopia artifact this CR represents.
staged object — The CSI staging objects the run created for copyMethod: Snapshot/Clone.
stats object — Byte/file counts parsed from kopia’s JSON output.
timing object — Start/end/duration of the snapshot run.
Field Type Default Description
credsReapedAt string — When the run’s projected credential Secrets were reclaimed (RFC 3339); absent until the reap has run. A projected copy is only needed while a mover Job can still load it via envFrom, but it is owner-ref’d to this CR, which long outlives that Job — so without an explicit reap it would sit in the workload namespace holding live repository credentials until the CR is pruned (#240).
Field Type Default Description
lastTransitionTime string required lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable.
message string required message is a human readable message indicating details about the transition. This may be an empty string.
reason string required reason contains a programmatic identifier indicating the reason for the condition’s last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty.
status string required status of the condition, one of True, False, Unknown.
type string required type of condition in CamelCase or in foo.example.com/CamelCase.
observedGeneration integer — observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditionsx.observedGeneration is 9, the condition is out of date with respect to the current state of the instance.
Field Type Default Description
repository object required The SOURCE repository the snapshot was migrated from (the SnapshotReplication’s sourceRef, resolved at run time).
sourceManifestId string required The kopia manifest id the snapshot had in the SOURCE repository. Migrate assigns a NEW manifest id on the destination (status.snapshot.kopiaSnapshotID); this is the old one, kept for cross-repository correlation.
startTime string required The snapshot’s RFC3339 startTime — preserved verbatim by migrate and the key (together with the identity triple) both idempotent re-migration and pruning: mirrorSource correlate source and destination rows on.
Field Type Default Description
name string required Name of the referenced Repository/ClusterRepository.
kind enum: Repository | ClusterRepository Repository Which repository CRD this points at; defaults to RepositoryKind::Repository.
namespace string — Cross-namespace Repository reference; ignored/forbidden for ClusterRepository.
Field Type Default Description
kopiaErrorClass string required kopia error class (e.g. RepositoryUnavailable, AuthFailure).
message string required A short human-readable message: what failed, why, and how to fix it.
retryRecommended boolean required Whether retrying the same operation unchanged could succeed.
exitCode integer — The process exit code, if one was reported.
op string — The mover operation that failed, as a stable label (e.g. repository connect, snapshot create) — the values of the mover’s KopiaOp::as_str(). Distinguishes a repository-level connect failure from a source-level failure (a broken PVC), which share kopiaErrorClass values (e.g. NotFound). Absent on failures that occurred outside a kopia invocation.
stderrTail string — The last lines of kopia’s stderr, if any were captured (bounded by MAX_LOG_TAIL_BYTES).
Field Type Default Description
postCompletedAt string — When the afterSnapshot list completed (RFC3339); absent until it has.
preCompletedAt string — When the beforeSnapshot list completed (RFC3339); absent until it has.
Field Type Default Description
attempts integer — Number of attempts so far (bounded by failurePolicy.backoffLimit).
name string — Name of the mover Job.
Field Type Default Description
schema integer required The kopiur-meta schema version this value was written under. Writers emit the lowest schema that represents the data (currently KOPIUR_META_SCHEMA_V1); readers reject only a schema NEWER than they understand (degrading to recorded-absent, never an error).
src enum: inherited | explicit | defaults | unknown required Which layer pinned the recorded identity. Only inherited means the identity tracked the workload.
fsGroup integer — The resolved pod-level fsGroup the mover ran with (the hardened default is 65532). Absent = no layer set one.
gid integer — The resolved effective runAsGroup the mover ran as at backup time (container runAsGroup, else pod). Absent = image-determined.
uid integer — The resolved effective runAsUser the mover ran as at backup time (container runAsUser, else pod). Absent = no layer pinned a UID, so the mover’s UID was image-determined.
Field Type Default Description
credentialProjection object — The recipe’s spec.credentialProjection as it stood for this run.
The deletion path re-projects the mover’s credentials, but the opt-in lives on the SnapshotPolicy — which a user may delete first. Pinning it here lets the finalizer honor the opt-in that was actually in force, instead of reading an absent recipe as “projection off” and blocking on a Secret that was never meant to be namespace-local (#255). Absent only on a Snapshot that predates the pin or never ran; a run always writes it, including enabled: false, so absent stays distinguishable from off.
repository object — The repository this run targeted, frozen at run time.
sources []object — The concrete PVCs + source paths backed up this run.
Snapshot status.resolved.credentialProjection
Section titled “Snapshot status.resolved.credentialProjection”
Field Type Default Description
enabled boolean false Copy the repository’s credential Secret(s) into the namespace of each mover Job; off by default.
Field Type Default Description
name string required Name of the referenced Repository/ClusterRepository.
kind enum: Repository | ClusterRepository Repository Which repository CRD this points at; defaults to RepositoryKind::Repository.
namespace string — Cross-namespace Repository reference; ignored/forbidden for ClusterRepository.
Field Type Default Description
pvc string — namespace/name of the PVC, as kopia sees it.
sourcePath string — The source path kopia recorded for this PVC.
Field Type Default Description
identity object required The username@hostname:path identity recorded for this snapshot.
kopiaSnapshotID string required kopia’s snapshot ID — the handle the finalizer uses to delete content.
description string — The kopia snapshot description (snapshot create --description), when one is recorded and non-empty. For discovered rows this is copied from the repository listing TRUNCATED to 1024 bytes (char-boundary-safe) — the value is foreign-writer-controlled and must never fail the CR write.
Field Type Default Description
hostname string required The final hostname kopia records, fixed at admission.
username string required The final username kopia records, fixed at admission.
sourcePath string — The resolved snapshot source path, when applicable (username@hostname:path).
Field Type Default Description
copyMethod string — The resolved capture method (Snapshot or Clone) that produced this stage.
pvcName string — Name of the staged PersistentVolumeClaim the mover mounts in place of the live source PVC.
ready boolean — true once the stage is ready for the mover.
stagingTimeoutSeconds integer — The resolved spec.staging.timeout (seconds) pinned when the stage was stamped, so the running-Job staged-PVC bind watchdog never re-resolves a policy that may have been edited or deleted mid-run. 0 = wait indefinitely.
storageClassName string — StorageClass of the staged PVC — spec.staging.storageClassName when set, else the source PVC’s class. Pinned for observability (e.g. confirming a CephFS shallow-clone class actually took effect).
volumeGroupSnapshotName string — Name of the shared CSI VolumeGroupSnapshot this member staged from, when the recipe asked for a consistency group (groupBy: VolumeGroupSnapshot).
Recorded because the group is otherwise invisible: it deliberately carries no ownerReferences (see io::group_staging), so this is how an operator tells which capture a backup came from — and how kubectl kopiur doctor finds one that outlived its members.
volumeSnapshotName string — Name of the VolumeSnapshot created from the source PVC (copyMethod: Snapshot only).
Field Type Default Description
bytesNew integer — Bytes newly uploaded this run (after dedup/compression).
filesFailed integer — Count of source entries kopia could not read and excluded, making the snapshot incomplete.
filesModified integer — Count of files changed since the previous snapshot.
filesNew integer — Count of files new since the previous snapshot.
filesUnchanged integer — Count of files unchanged since the previous snapshot.
sizeBytes integer — Total logical size of the snapshot in bytes.
Field Type Default Description
durationSeconds integer — Wall-clock duration in seconds.
endTime string — RFC3339 end time of the run.
startTime string — RFC3339 start time of the run.

Scope: Namespaced · Short names: kopiasched · Print columns: Config, Schedule, Suspended, Age

Field Type Default Description
schedule object required Cron, jitter, timezone, and concurrency for the firing cadence.
deletion object — Deletion semantics for the Snapshots this schedule produced.
failedJobsHistoryLimit integer 10
min 0
Maximum number of failed Snapshot CRs from this schedule to retain (default 10; 0 keeps none).
policyRef object — The single SnapshotPolicy this schedule invokes; mutually exclusive with policySelector.
policySelector core/v1 LabelSelector — Label selector fanning out over SnapshotPolicy objects; mutually exclusive with policyRef.

Validation rules (enforced at admission):

  • exactly one of policyRef or policySelector
Field Type Default Description
cron string required Cron expression with Jenkins-style H substitution.
concurrencyPolicy enum: Forbid | Allow | Replace Forbid How to handle a firing while a prior run is still in flight (default Forbid).
jitter string — Deterministic jitter (Go-style duration), derived from (scheduleUID, slot).
runOnCreate boolean false Whether to fire immediately on create (default false).
startingDeadlineSeconds integer — If a slot is missed by more than this many seconds, skip it instead of firing late.
suspend boolean — Skip future firings while true.
timezone string — IANA timezone the cron is evaluated in; absent uses the controller’s default.
Field Type Default Description
onScheduleDelete enum: Retain | Delete Retain Stamped onto every produced Snapshot at creation (spec.onScheduleDelete) and consulted by the Snapshot finalizer when the owning schedule is gone or replaced. Absent resolves to Retain.
Field Type Default Description
name string required Name of the referenced SnapshotPolicy.
namespace string — Namespace of the SnapshotPolicy; absent = same namespace as the referrer.
Field Type Default Description
conditions []object — Standard Kubernetes conditions surfacing schedule health.
consecutiveFailures integer — Count of back-to-back failed runs; resets on success.
lastSchedule object — Most recent firing (cron + jitter, pinned).
lastSuccessfulSchedule object — The most recent firing whose Snapshot succeeded.
nextSchedule object — The next firing slot the controller has computed (cron + jitter, pinned).
observedGeneration integer — The metadata.generation this status reflects, for staleness detection.
Field Type Default Description
lastTransitionTime string required lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable.
message string required message is a human readable message indicating details about the transition. This may be an empty string.
reason string required reason contains a programmatic identifier indicating the reason for the condition’s last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty.
status string required status of the condition, one of True, False, Unknown.
type string required type of condition in CamelCase or in foo.example.com/CamelCase.
observedGeneration integer — observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditionsx.observedGeneration is 9, the condition is out of date with respect to the current state of the instance.
Field Type Default Description
at string — The RFC3339 instant this slot fired (or is scheduled to); also accepts the scheduledAt alias.
cron string — The spec.schedule.cron expression this slot was computed from, as written when it was pinned. Like timezone and jitter, only ever WRITTEN on nextSchedule. Recorded so a cron edit invalidates the pinned slot at once instead of letting the OLD expression fire one more time. Compared with whitespace normalized, so re-spacing the expression is not a change. Absent on pins written before this field existed, which is treated as “unchanged” (the slot is recomputed with the new expression at its next natural re-pin).
jitter string — The deterministic jitter window (Go-style duration, e.g. 10m) the cron was spread by when this slot was pinned. This struct is shared by nextSchedule, lastSchedule and lastSuccessfulSchedule, so the field appears on all three, but the controller only ever WRITES it on nextSchedule — it is a property of a pin the controller may still have to invalidate, not a record of a slot that already fired. Recorded for the same reason as the pinned timezone: the window may be INHERITED from the target repository’s scheduleDefaults.jitter, so a change to that default (or to spec.schedule.jitter) must invalidate the pinned wall-clock slot and recompute it in the new window — otherwise the edit would only take effect an arbitrary slot later. Absent both when no jitter applies and on legacy pins written before this field existed; an absent recorded window is treated as “unchanged” so an upgrade never churns an established pin.
snapshotRef object — The Snapshot CR this slot produced, when one was created.
timezone string — The IANA timezone the cron was evaluated in when this slot was pinned. This struct is shared by nextSchedule, lastSchedule and lastSuccessfulSchedule, so the field appears on all three, but the controller only ever WRITES it on nextSchedule — it is a property of a pin the controller may still have to invalidate, not a record of a slot that already fired. Recorded so the controller can detect an effective-timezone change — a spec.schedule.timezone edit or a change to the target repository’s scheduleDefaults.timezone — and invalidate the pinned wall-clock slot, recomputing it in the new zone. Absent on legacy pins written before this field existed (treated as “unchanged”).
SnapshotSchedule status.lastSchedule.snapshotRef
Section titled “SnapshotSchedule status.lastSchedule.snapshotRef”
Field Type Default Description
name string required The Snapshot’s metadata.name (same namespace as the schedule).

SnapshotSchedule status.lastSuccessfulSchedule

Section titled “SnapshotSchedule status.lastSuccessfulSchedule”
Field Type Default Description
at string — The RFC3339 instant this slot fired (or is scheduled to); also accepts the scheduledAt alias.
cron string — The spec.schedule.cron expression this slot was computed from, as written when it was pinned. Like timezone and jitter, only ever WRITTEN on nextSchedule. Recorded so a cron edit invalidates the pinned slot at once instead of letting the OLD expression fire one more time. Compared with whitespace normalized, so re-spacing the expression is not a change. Absent on pins written before this field existed, which is treated as “unchanged” (the slot is recomputed with the new expression at its next natural re-pin).
jitter string — The deterministic jitter window (Go-style duration, e.g. 10m) the cron was spread by when this slot was pinned. This struct is shared by nextSchedule, lastSchedule and lastSuccessfulSchedule, so the field appears on all three, but the controller only ever WRITES it on nextSchedule — it is a property of a pin the controller may still have to invalidate, not a record of a slot that already fired. Recorded for the same reason as the pinned timezone: the window may be INHERITED from the target repository’s scheduleDefaults.jitter, so a change to that default (or to spec.schedule.jitter) must invalidate the pinned wall-clock slot and recompute it in the new window — otherwise the edit would only take effect an arbitrary slot later. Absent both when no jitter applies and on legacy pins written before this field existed; an absent recorded window is treated as “unchanged” so an upgrade never churns an established pin.
snapshotRef object — The Snapshot CR this slot produced, when one was created.
timezone string — The IANA timezone the cron was evaluated in when this slot was pinned. This struct is shared by nextSchedule, lastSchedule and lastSuccessfulSchedule, so the field appears on all three, but the controller only ever WRITES it on nextSchedule — it is a property of a pin the controller may still have to invalidate, not a record of a slot that already fired. Recorded so the controller can detect an effective-timezone change — a spec.schedule.timezone edit or a change to the target repository’s scheduleDefaults.timezone — and invalidate the pinned wall-clock slot, recomputing it in the new zone. Absent on legacy pins written before this field existed (treated as “unchanged”).
SnapshotSchedule status.lastSuccessfulSchedule.snapshotRef
Section titled “SnapshotSchedule status.lastSuccessfulSchedule.snapshotRef”
Field Type Default Description
name string required The Snapshot’s metadata.name (same namespace as the schedule).
Field Type Default Description
at string — The RFC3339 instant this slot fired (or is scheduled to); also accepts the scheduledAt alias.
cron string — The spec.schedule.cron expression this slot was computed from, as written when it was pinned. Like timezone and jitter, only ever WRITTEN on nextSchedule. Recorded so a cron edit invalidates the pinned slot at once instead of letting the OLD expression fire one more time. Compared with whitespace normalized, so re-spacing the expression is not a change. Absent on pins written before this field existed, which is treated as “unchanged” (the slot is recomputed with the new expression at its next natural re-pin).
jitter string — The deterministic jitter window (Go-style duration, e.g. 10m) the cron was spread by when this slot was pinned. This struct is shared by nextSchedule, lastSchedule and lastSuccessfulSchedule, so the field appears on all three, but the controller only ever WRITES it on nextSchedule — it is a property of a pin the controller may still have to invalidate, not a record of a slot that already fired. Recorded for the same reason as the pinned timezone: the window may be INHERITED from the target repository’s scheduleDefaults.jitter, so a change to that default (or to spec.schedule.jitter) must invalidate the pinned wall-clock slot and recompute it in the new window — otherwise the edit would only take effect an arbitrary slot later. Absent both when no jitter applies and on legacy pins written before this field existed; an absent recorded window is treated as “unchanged” so an upgrade never churns an established pin.
snapshotRef object — The Snapshot CR this slot produced, when one was created.
timezone string — The IANA timezone the cron was evaluated in when this slot was pinned. This struct is shared by nextSchedule, lastSchedule and lastSuccessfulSchedule, so the field appears on all three, but the controller only ever WRITES it on nextSchedule — it is a property of a pin the controller may still have to invalidate, not a record of a slot that already fired. Recorded so the controller can detect an effective-timezone change — a spec.schedule.timezone edit or a change to the target repository’s scheduleDefaults.timezone — and invalidate the pinned wall-clock slot, recomputing it in the new zone. Absent on legacy pins written before this field existed (treated as “unchanged”).
SnapshotSchedule status.nextSchedule.snapshotRef
Section titled “SnapshotSchedule status.nextSchedule.snapshotRef”
Field Type Default Description
name string required The Snapshot’s metadata.name (same namespace as the schedule).

Scope: Namespaced · Short names: kopiarestore · Print columns: Phase, Source, Age

Field Type Default Description
source union required Where to read data from (snapshotRef, fromPolicy, or identity).
target union required Where to write the restored data (pvc, pvcRef, or populator).
credentialProjection object — Opt-in copying of the repository’s credential Secret(s) into the mover’s namespace (default off).
failurePolicy object — Mover Job retry/deadline limits (backoffLimit, activeDeadlineSeconds).
mover object — Per-run mover overrides for this restore’s Job (resources, cache, securityContext).
options object — kopia restore behavior (file deletion, permission/atomicity handling).
policy object — What to do when the referenced snapshot doesn’t exist yet, and how long to wait.
repository object — The repository to read from; derived from source when omitted, required only with source.identity.

Validation rules (enforced at admission):

  • exactly one of target.pvc, target.pvcRef, target.populator, target.streamExec

Externally tagged — set exactly one of: fromPolicy · identity · snapshotRef.

Field Type Default Description
fromPolicy object — A SnapshotPolicy CR, resolved via identity even with no Snapshot CR present (deploy-or-restore).
identity object — A raw kopia identity (foreign writers / aged-out catalog); requires spec.repository.
snapshotRef object — A Snapshot CR (scheduled, manual, or discovered).
Field Type Default Description
name string required Name of the SnapshotPolicy whose identity selects the snapshot.
asOf string — Restore the newest snapshot at or before this RFC3339 timestamp (point-in-time).
namespace string — Namespace of the SnapshotPolicy; absent = the Restore’s own namespace.
offset integer 0 Which snapshot to pick: 0 = latest, 1 = previous, and so on.
sourcePath string —
maxLength 4096
The kopia source path to restore FROM, overriding the path kopiur derives from the policy.
Normally the path is derived: a policy with one plain pvc:/nfs source contributes its own path, and a pvcSelector policy contributes the path its sourcePathStrategy would have produced for the PVC being restored (/pvc/<name> or /pvc/<namespace>/<name>) — the same rule the backup side used when it wrote the snapshot, so a fan-out restore fills each PVC from ITS OWN snapshot instead of the newest snapshot of any member.
Set this when the derivation is ambiguous or wrong: selector sources that disagree on sourcePathStrategy/sourcePathOverride (kopiur fails closed rather than guess), a policy whose selector sources share one sourcePathOverride, or a cross-namespace target.pvcRef whose derived /pvc/<namespace>/<name> names a namespace the repository never saw.
Mirrors IdentitySource::source_path: it selects which kopia source to READ, it does not change where the data is written.
Field Type Default Description
hostname string required The kopia hostname to match.
username string required The kopia username to match.
asOf string — Restore the newest snapshot at or before this RFC3339 timestamp (point-in-time).
offset integer — Which snapshot to pick: 0 = latest, 1 = previous, and so on.
snapshotID string — Pin an exact kopia snapshot by ID.
sourcePath string — The kopia source path to match; absent matches any path for the identity.
Field Type Default Description
name string required Name of the referenced object.
namespace string — Namespace of the referenced object; absent = same namespace as the referrer.

Externally tagged — set exactly one of: populator · pvc · pvcRef · streamExec.

Field Type Default Description
populator object — Passive populator mode: the restore is claimed by a PVC’s spec.dataSourceRef.
pvc object — Operator creates the PVC.
pvcRef object — Write into an existing PVC.
streamExec object — Stream one virtual file out of the snapshot into a command’s stdin in a running Pod — the companion of a stream backup source (e.g. feeding a pg_dumpall artifact back through psql). Writes no PVC.
Field Type Default Description
name string required Name of the PVC to create.
accessModes []enum: ReadWriteOnce | ReadOnlyMany | ReadWriteMany | ReadWriteOncePod — Access modes for the new PVC; empty defaults to ReadWriteOnce. Closed enum in the schema; a non-canonical value persisted before enforcement decodes as PvcAccessMode::Unknown and is rejected per-CR with the value quoted (webhook + reconciler, via validate_access_modes) instead of poisoning the typed watcher.
capacity string — Requested size of the new PVC (e.g. 100Gi).
storageClassName string — StorageClass for the new PVC; absent uses the cluster default.
Field Type Default Description
name string required Name of the referenced object.
namespace string — Namespace of the referenced object; absent = same namespace as the referrer.
Field Type Default Description
fileName string required
minLength 1; maxLength 255
Which virtual file inside the snapshot to read back — the fileName the backup’s stream source used (e.g. postgres.sql).
workloadExec object required Where to send it: the command receives the file’s bytes on stdin.
Restore spec.target.streamExec.workloadExec
Section titled “Restore spec.target.streamExec.workloadExec”
Field Type Default Description
command []string required
minItems 1
The argv to execute. NOT a shell line: element 0 is the program, so use ["sh", "-ec", "..."] explicitly if you want shell semantics.
Reference credentials through the container’s existing environment or mounted Secrets — never inline them here. This argv is copied into the mover Pod’s spec, so anyone with pods:get in the namespace can read it.
podSelector core/v1 LabelSelector required Standard label selector identifying the workload Pod, resolved in the SnapshotPolicy’s (or Restore’s) own namespace. Must not be empty — an empty selector matches every Pod in the namespace.
container string — Container to exec in; absent uses the Pod’s default container.
timeout string 1h Go duration bounding the command (e.g. 2h; default 1h). On expiry the command is abandoned and the run fails, leaving no snapshot behind.
The same bound applies whether this exec is a backup’s producer or a streamExec restore’s consumer.
Field Type Default Description
enabled boolean false Copy the repository’s credential Secret(s) into the namespace of each mover Job; off by default.
Field Type Default Description
activeDeadlineSeconds integer — Mover Job.spec.activeDeadlineSeconds — wall-clock cap after which a running run is killed.
backoffLimit integer — Mover Job.spec.backoffLimit — retries before a failed run is marked failed.
podStartupDeadlineSeconds integer — Seconds a non-starting (wedged) mover pod may sit before the run is failed; default 300s.
Field Type Default Description
cache object — Override the repository’s CacheDefaults for this recipe’s movers.
inheritSecurityContextFrom union — Copy the UID/GID security context from a live workload rather than hard-coding it.
Requires the workload to pin runAsUser (container or pod level): a UID that comes from the container image’s USER line is invisible in the pod spec and cannot be inherited — the mover would silently run as its own image’s UID instead.
May be combined with securityContext/podSecurityContext, which override it field-wise and act as the fallback when no workload pod can be resolved.
podSecurityContext core/v1 PodSecurityContext — Pod security context for the mover (notably fsGroup for group-writable restore volumes). Same layering as securityContext: highest layer, merged field-wise, and combinable with inheritSecurityContextFrom.
privilegedMode boolean — Opt-in, namespace-gated privileged mode. Never changes the UID. When the mover runs as root (runAsUser: 0), adds the capabilities the operation needs on top of drop: ALL: DAC_OVERRIDE for a backup (read files owned by any uid/gid); CHOWN, DAC_OVERRIDE, FOWNER, FSETID for a restore (reproduce original ownership). Grants nothing for maintenance, or when the mover does not run as root (capabilities are inert for non-root); set runAsUser: 0 yourself.
resources core/v1 ResourceRequirements — Resource requests/limits for the mover container.
securityContext core/v1 SecurityContext — Container security context for the mover; merged field-wise over the hardened base, moverDefaults, and any inherited context — this is the highest layer, so every field set here wins. Combines with inheritSecurityContextFrom: fields you set override the workload’s, fields you omit are inherited, and this context stands in alone when inheritance cannot resolve a pod.
ttlSecondsAfterFinished integer — Per-recipe override of Job.spec.ttlSecondsAfterFinished so finished Jobs self-GC.
Field Type Default Description
capacity string — Size of the PVC backing the mover’s kopia cache (e.g. 10Gi).
contentCacheSizeMb integer — kopia content cache budget in MiB (--content-cache-size-mb).
metadataCacheSizeMb integer — kopia metadata cache budget in MiB (--metadata-cache-size-mb).
mode enum: Ephemeral | Persistent — How a mover’s kopia cache volume is provisioned.
storageClassName string — StorageClass for the cache PVC; absent uses the cluster default.
Restore spec.mover.inheritSecurityContextFrom
Section titled “Restore spec.mover.inheritSecurityContextFrom”

Externally tagged — set exactly one of: pvcConsumer · snapshot · workloadSelector.

Field Type Default Description
pvcConsumer object — Backup sources only: auto-derive the workload from the PVC this snapshot backs up.
snapshot object — Restores only: inherit the identity RECORDED on the backup itself (Snapshot.status.recorded, decoded from the kopiur-meta kopia tag) — uid/gid/fsGroup the backup mover actually ran as. Needs no live workload pod, so it works on a rebuilt cluster and with target.populator. Rejected at admission on SnapshotPolicy/Maintenance (backups read the live workload; maintenance has no snapshot). Write it as snapshot: {} (an empty sub-object) — a bare snapshot: is null and rejected.
workloadSelector object — Inherit from workload pod(s) matched by an explicit label selector (backup or restore).
Restore spec.mover.inheritSecurityContextFrom.pvcConsumer
Section titled “Restore spec.mover.inheritSecurityContextFrom.pvcConsumer”
Field Type Default Description
container string — Which container within the matched consumer pod to inherit from; absent uses the first/only.
Restore spec.mover.inheritSecurityContextFrom.workloadSelector
Section titled “Restore spec.mover.inheritSecurityContextFrom.workloadSelector”
Field Type Default Description
podSelector core/v1 LabelSelector required Label selector matching the workload pod(s) to read context/hooks from.
container string — Which container within the matched pod; absent uses the first/only container.
Field Type Default Description
enableFileDeletion boolean — Delete files in the target that are not present in the snapshot (exact mirror); off by default. Wired to kopia’s --[no-]delete-extra (previously a silent no-op — see issue #216 gap sweep).
ignoreErrors boolean — --[no-]ignore-errors: ignore all restore errors and continue (kopia default false).
ignorePermissionErrors boolean — Continue past permission errors during restore (default true).
overwriteDirectories boolean — --[no-]overwrite-directories: overwrite existing directories in the target (kopia default true).
overwriteFiles boolean — --[no-]overwrite-files: overwrite existing files in the target (kopia default true).
overwriteSymlinks boolean — --[no-]overwrite-symlinks: overwrite existing symlinks in the target (kopia default true).
parallel integer —
min 0
--parallel: restore parallelism (kopia default 8; 1 disables parallelism).
skipExisting boolean — --[no-]skip-existing: skip files/symlinks that already exist in the target (kopia default false).
skipOwners boolean — --[no-]skip-owners: skip restoring file owners (kopia default false).
skipPermissions boolean — --[no-]skip-permissions: skip restoring file permissions (kopia default false).
skipTimes boolean — --[no-]skip-times: skip restoring file modification times (kopia default false).
writeFilesAtomically boolean — Write files atomically via a temp file + rename (default true).
writeSparseFiles boolean — --[no-]write-sparse-files: attempt to write files sparsely, allocating the minimum disk space needed (kopia default false).
Field Type Default Description
onMissingSnapshot enum: Fail | Continue — What to do when the resolved source matches no snapshot. Defaults to Fail (fail-closed) so an explicit restore can never silently no-op; choose Continue to provision an empty volume instead (deploy-or-restore).
waitTimeout string — How long to wait for the source snapshot to appear before giving up (e.g. 5m).
Field Type Default Description
name string required Name of the referenced Repository/ClusterRepository.
kind enum: Repository | ClusterRepository Repository Which repository CRD this points at; defaults to RepositoryKind::Repository.
namespace string — Cross-namespace Repository reference; ignored/forbidden for ClusterRepository.
Field Type Default Description
claims map[string]object — Per-claimant state for a target.populator restore, keyed by the claiming PVC’s name (#443).
A populator Restore is claimed by EVERY PVC whose spec.dataSourceRef names it, not just the first, and each claimant gets its own prime PVC, its own mover Job and its own kopia source path — so each needs its own state. A map, not a list, because an RFC-7386 merge patch merges map keys but REPLACES arrays: N concurrent populate movers each patch only their own key and can never clobber a sibling (the same reason as SnapshotPolicyStatus.verificationStamps).
Absent for a direct target.pvc/target.pvcRef restore, which keeps using the top-level resolved/target/waitStartedAt/logTail/failure.
The schema renders as an object with additionalProperties, which PRUNES unknown keys — so every field any writer (controller or mover) puts under claims.<pvc> must exist on RestoreClaimStatus.
conditions []object — Standard Kubernetes conditions carrying the human-readable status/reason.
failure object — Structured terminal-failure detail (kopia error class, stderr tail, retry hint).
logTail string — The last lines of the run’s output, written by the mover at the terminal transition.
observedGeneration integer — metadata.generation last reconciled, so stale status is detectable.
phase enum: Pending | Resolving | Restoring | Completed | Failed — Lifecycle phase of a restore.
progress object — Bytes/files restored so far, patched periodically by the mover.
resolved object — The source resolved and pinned at admission; never re-resolved.
sourceKind string — The pinned source kind (SnapshotRef/FromPolicy/Identity); backs the SOURCE printer column.
target object — Resolved target details (the PVC written to / populator handshake).
timing object — Start/end timestamps for the restore run.
waitStartedAt string — When the policy.waitTimeout window OPENED (RFC3339) — the first reconcile on which the restore could actually proceed (its repository reached Ready, and for a target.populator a PVC already claims it), NOT when the Restore was created. The window does NOT open while the referenced Repository object or fromPolicy SnapshotPolicy doesn’t exist: the restore parks in Pending (ReferentAvailable=False, reason RestoreReferentMissing) and stays unstamped. It DOES still open for a snapshotRef whose Snapshot row doesn’t exist yet (so onMissingSnapshot can fire for a ref that never appears) and for a restore whose mover Job already launched. Stamped once and then honored verbatim, so the window survives controller restarts and Job pod retries; cleared when a populator re-opens resolution for a re-created claim, so that claim gets the full window again. Absent means the window has not opened yet (or no policy.waitTimeout is configured, in which case there is no window to anchor).
Field Type Default Description
lastTransitionTime string required lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable.
message string required message is a human readable message indicating details about the transition. This may be an empty string.
reason string required reason contains a programmatic identifier indicating the reason for the condition’s last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty.
status string required status of the condition, one of True, False, Unknown.
type string required type of condition in CamelCase or in foo.example.com/CamelCase.
observedGeneration integer — observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditionsx.observedGeneration is 9, the condition is out of date with respect to the current state of the instance.
Field Type Default Description
kopiaErrorClass string required kopia error class (e.g. RepositoryUnavailable, AuthFailure).
message string required A short human-readable message: what failed, why, and how to fix it.
retryRecommended boolean required Whether retrying the same operation unchanged could succeed.
exitCode integer — The process exit code, if one was reported.
op string — The mover operation that failed, as a stable label (e.g. repository connect, snapshot create) — the values of the mover’s KopiaOp::as_str(). Distinguishes a repository-level connect failure from a source-level failure (a broken PVC), which share kopiaErrorClass values (e.g. NotFound). Absent on failures that occurred outside a kopia invocation.
stderrTail string — The last lines of kopia’s stderr, if any were captured (bounded by MAX_LOG_TAIL_BYTES).
Field Type Default Description
bytesRestored integer — Total bytes restored so far.
filesRestored integer — Total files restored so far.
Field Type Default Description
identity object — The resolved kopia identity (username@hostname:path) of the snapshot.
kopiaSnapshotID string — The exact kopia snapshot manifest id the source resolved to; pinned once.
pinnedAt string — Timestamp at which the source was pinned (RFC3339).
repository object — The repository the snapshot lives in, resolved from the source.
resolution enum: Snapshot | NoSnapshot — Which outcome the source resolution pinned, once and never re-resolved.
snapshotRef object — The concrete Snapshot CR the source resolved to, when applicable.
Field Type Default Description
hostname string required The final hostname kopia records, fixed at admission.
username string required The final username kopia records, fixed at admission.
sourcePath string — The resolved snapshot source path, when applicable (username@hostname:path).
Field Type Default Description
name string required Name of the referenced Repository/ClusterRepository.
kind enum: Repository | ClusterRepository Repository Which repository CRD this points at; defaults to RepositoryKind::Repository.
namespace string — Cross-namespace Repository reference; ignored/forbidden for ClusterRepository.
Field Type Default Description
name string required Name of the referenced object.
namespace string — Namespace of the referenced object; absent = same namespace as the referrer.
Field Type Default Description
pvcPrime string — Populator handshake (passive / pvc-create modes).
pvcRef object — The PVC actually written to (created or pre-existing).
Field Type Default Description
name string required Name of the referenced object.
namespace string — Namespace of the referenced object; absent = same namespace as the referrer.
Field Type Default Description
endTime string — When the restore reached a terminal phase (RFC3339).
startTime string — When the mover began restoring (RFC3339).

Scope: Namespaced · Short names: kopiamaint · Print columns: Repository, Owner, Age

Field Type Default Description
ownership object required Maintenance ownership lease holder and takeover policy.
repository object required Reference to the Repository or ClusterRepository to maintain.
schedule object required quick (cheap) and full (--full, reclamation) maintenance crons.
credentialProjection object — Opt-in projection of the repository’s credential Secret(s) into this run’s namespace (default off).
failurePolicy object — How a failed maintenance run is retried and bounded (backoff, deadline).
mover object — Mover (Job pod) overrides for the maintenance run.
Field Type Default Description
owner string required Stable lease holder identity (e.g. kopia-operator/nas-primary).
ownerAliases []string — Previous lease strings still recognized as SELF (a migration path): when kopia’s currently-recorded maintenance owner matches the owner derived from one of these aliases, a run treats the lease as its own — it claims it and re-stamps owner, upgrading the recorded owner to the current format. The operator populates this when a repository’s managed Maintenance moves to a cluster-qualified lease (identityDefaults.cluster), so the transition never yields the lease to what merely looks like a foreign owner.
takeoverPolicy enum: Never | PromptCondition | Force Never What to do when the lease is already held by a different owner.
Field Type Default Description
name string required Name of the referenced Repository/ClusterRepository.
kind enum: Repository | ClusterRepository Repository Which repository CRD this points at; defaults to RepositoryKind::Repository.
namespace string — Cross-namespace Repository reference; ignored/forbidden for ClusterRepository.
Field Type Default Description
full object required Cron and jitter for kopia maintenance run --full (content reclamation).
quick object required Cron and jitter for kopia maintenance run (quick, cheap index/log work).
timezone string — IANA timezone both crons are evaluated in; absent means the controller default.
Field Type Default Description
cron string required The cron expression, parsed by croner; may contain an H placeholder for deterministic jitter.
jitter string — Optional deterministic jitter window as a Go-style duration string (e.g. 30m).
timezone string — IANA timezone the cron is evaluated in (e.g. America/Chicago); absent uses the enclosing schedule’s timezone, else the controller default (UTC).
Field Type Default Description
cron string required The cron expression, parsed by croner; may contain an H placeholder for deterministic jitter.
jitter string — Optional deterministic jitter window as a Go-style duration string (e.g. 30m).
timezone string — IANA timezone the cron is evaluated in (e.g. America/Chicago); absent uses the enclosing schedule’s timezone, else the controller default (UTC).
Field Type Default Description
enabled boolean false Copy the repository’s credential Secret(s) into the namespace of each mover Job; off by default.
Field Type Default Description
activeDeadlineSeconds integer — Mover Job.spec.activeDeadlineSeconds — wall-clock cap after which a running run is killed.
backoffLimit integer — Mover Job.spec.backoffLimit — retries before a failed run is marked failed.
podStartupDeadlineSeconds integer — Seconds a non-starting (wedged) mover pod may sit before the run is failed; default 300s.
Field Type Default Description
cache object — Override the repository’s CacheDefaults for this recipe’s movers.
inheritSecurityContextFrom union — Copy the UID/GID security context from a live workload rather than hard-coding it.
Requires the workload to pin runAsUser (container or pod level): a UID that comes from the container image’s USER line is invisible in the pod spec and cannot be inherited — the mover would silently run as its own image’s UID instead.
May be combined with securityContext/podSecurityContext, which override it field-wise and act as the fallback when no workload pod can be resolved.
podSecurityContext core/v1 PodSecurityContext — Pod security context for the mover (notably fsGroup for group-writable restore volumes). Same layering as securityContext: highest layer, merged field-wise, and combinable with inheritSecurityContextFrom.
privilegedMode boolean — Opt-in, namespace-gated privileged mode. Never changes the UID. When the mover runs as root (runAsUser: 0), adds the capabilities the operation needs on top of drop: ALL: DAC_OVERRIDE for a backup (read files owned by any uid/gid); CHOWN, DAC_OVERRIDE, FOWNER, FSETID for a restore (reproduce original ownership). Grants nothing for maintenance, or when the mover does not run as root (capabilities are inert for non-root); set runAsUser: 0 yourself.
resources core/v1 ResourceRequirements — Resource requests/limits for the mover container.
securityContext core/v1 SecurityContext — Container security context for the mover; merged field-wise over the hardened base, moverDefaults, and any inherited context — this is the highest layer, so every field set here wins. Combines with inheritSecurityContextFrom: fields you set override the workload’s, fields you omit are inherited, and this context stands in alone when inheritance cannot resolve a pod.
ttlSecondsAfterFinished integer — Per-recipe override of Job.spec.ttlSecondsAfterFinished so finished Jobs self-GC.
Field Type Default Description
capacity string — Size of the PVC backing the mover’s kopia cache (e.g. 10Gi).
contentCacheSizeMb integer — kopia content cache budget in MiB (--content-cache-size-mb).
metadataCacheSizeMb integer — kopia metadata cache budget in MiB (--metadata-cache-size-mb).
mode enum: Ephemeral | Persistent — How a mover’s kopia cache volume is provisioned.
storageClassName string — StorageClass for the cache PVC; absent uses the cluster default.
Maintenance spec.mover.inheritSecurityContextFrom
Section titled “Maintenance spec.mover.inheritSecurityContextFrom”

Externally tagged — set exactly one of: pvcConsumer · snapshot · workloadSelector.

Field Type Default Description
pvcConsumer object — Backup sources only: auto-derive the workload from the PVC this snapshot backs up.
snapshot object — Restores only: inherit the identity RECORDED on the backup itself (Snapshot.status.recorded, decoded from the kopiur-meta kopia tag) — uid/gid/fsGroup the backup mover actually ran as. Needs no live workload pod, so it works on a rebuilt cluster and with target.populator. Rejected at admission on SnapshotPolicy/Maintenance (backups read the live workload; maintenance has no snapshot). Write it as snapshot: {} (an empty sub-object) — a bare snapshot: is null and rejected.
workloadSelector object — Inherit from workload pod(s) matched by an explicit label selector (backup or restore).
Maintenance spec.mover.inheritSecurityContextFrom.pvcConsumer
Section titled “Maintenance spec.mover.inheritSecurityContextFrom.pvcConsumer”
Field Type Default Description
container string — Which container within the matched consumer pod to inherit from; absent uses the first/only.
Maintenance spec.mover.inheritSecurityContextFrom.workloadSelector
Section titled “Maintenance spec.mover.inheritSecurityContextFrom.workloadSelector”
Field Type Default Description
podSelector core/v1 LabelSelector required Label selector matching the workload pod(s) to read context/hooks from.
container string — Which container within the matched pod; absent uses the first/only container.
Field Type Default Description
conditions []object — Standard Kubernetes conditions surfacing maintenance health.
full object — Last/next-run state for the full maintenance schedule.
manualRun object — State of the most recent annotation-requested out-of-band run; absent until one is requested.
observedGeneration integer — The metadata.generation this status reflects, for staleness detection.
observedIndexBlobs object — Content-index blob count re-counted right after the most recent successful run.
ownership object — Current lease holder, if the lease has been claimed.
quick object — Last/next-run state for the quick maintenance schedule.
Field Type Default Description
lastTransitionTime string required lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable.
message string required message is a human readable message indicating details about the transition. This may be an empty string.
reason string required reason contains a programmatic identifier indicating the reason for the condition’s last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty.
status string required status of the condition, one of True, False, Unknown.
type string required type of condition in CamelCase or in foo.example.com/CamelCase.
observedGeneration integer — observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditionsx.observedGeneration is 9, the condition is out of date with respect to the current state of the instance.
Field Type Default Description
consecutiveFailures integer — Count of back-to-back failed runs of this kind; resets on success.
lastContentReclaimedBytes integer — Bytes of backend storage the most recent run of this kind actually freed: the blobs kopia deleted (unreferenced packs, superseded epoch indexes and expired logs), summed from the run history kopia maintenance info reports. It deliberately EXCLUDES kopia’s snapshot-GC figure, which only marks contents deleted in the index and frees no storage until a later run removes the blobs. Absent when the run reclaimed nothing measurable — a quick run on an epoch-enabled repository only advances and compacts epochs, so there is no figure to report; 0 always means a measured zero, never “unknown”.
lastHandledAt string — RFC3339 instant the controller last observed this kind’s per-slot Job reach terminal success.
lastRunAt string — RFC3339 instant of the most recent run of this kind.
nextScheduledAt string — RFC3339 instant of the next scheduled run of this kind (cron + jitter, pinned).
Field Type Default Description
completedAt string — RFC3339 instant the run reached a terminal phase.
mode enum: quick | full — Which maintenance kind a manual (annotation-requested) run performs; the wire values are the run-mode annotation values. Defaults to quick.
phase enum: Running | Succeeded | Failed — Lifecycle of a manual run. Closed enum.
requestedAt string — The run-requested annotation value this status reflects (RFC3339).
Field Type Default Description
count integer 0 Number of content-index blobs (kopia index list) after the run.
observedAt string `` RFC3339 instant the recount was taken. What makes this observation comparable against the repository’s own storageStats.indexBlobCountAt, so whichever is newer wins rather than whichever was written last.
Field Type Default Description
claimedAt string — RFC3339 instant the lease was claimed.
owner string — The current lease holder’s identity (matches Ownership.owner).
Field Type Default Description
consecutiveFailures integer — Count of back-to-back failed runs of this kind; resets on success.
lastContentReclaimedBytes integer — Bytes of backend storage the most recent run of this kind actually freed: the blobs kopia deleted (unreferenced packs, superseded epoch indexes and expired logs), summed from the run history kopia maintenance info reports. It deliberately EXCLUDES kopia’s snapshot-GC figure, which only marks contents deleted in the index and frees no storage until a later run removes the blobs. Absent when the run reclaimed nothing measurable — a quick run on an epoch-enabled repository only advances and compacts epochs, so there is no figure to report; 0 always means a measured zero, never “unknown”.
lastHandledAt string — RFC3339 instant the controller last observed this kind’s per-slot Job reach terminal success.
lastRunAt string — RFC3339 instant of the most recent run of this kind.
nextScheduledAt string — RFC3339 instant of the next scheduled run of this kind (cron + jitter, pinned).

Scope: Namespaced · Short names: kopiarepl · Print columns: Source, Destination, Schedule, Last, Age

Field Type Default Description
destination union required The backend to mirror to; must differ from the source’s backend (webhook-enforced).
kopia repository sync-to is a blob-level copy: the destination inherits the source repository’s format and encryption password verbatim, so there is no separate destination password to configure. The destination backend’s own access credentials (e.g. S3 keys) ride its auth.secretRef, which — like the source’s — must live in this CR’s namespace.
schedule object required Cron and deterministic jitter for the replication runs.
sourceRef object required Reference to the Repository or ClusterRepository to mirror from.
mover object — Mover (Job pod) overrides for the replication run.
suspend boolean — Pause this replication; a suspended replication runs no syncs (default false).
sync object — Tuning knobs for the underlying kopia repository sync-to invocation (issue #216). None reproduces today’s behavior: sequential copy (--parallel unset), additive sync (no --delete), kopia’s own --must-exist/--times/--update defaults, and no throughput cap.

Externally tagged — set exactly one of: azure · b2 · filesystem · gcs · gdrive · rclone · s3 · sftp · webDav.

Field Type Default Description
azure object — Azure Blob Storage.
b2 object — Backblaze B2.
filesystem object — A local filesystem path, backed by a PVC the operator mounts into the mover.
gcs object — Google Cloud Storage.
gdrive object — Google Drive via kopia’s native gdrive provider (service-account JSON). kopia marks this provider experimental / not maintained, and a native gdrive repository is not interchangeable with an rclone-backed Drive remote.
rclone object — Any rclone remote (kopia shells out to rclone), broadening reach to providers without a native kopia backend.
s3 object — Amazon S3 or any S3-compatible object store (MinIO, RustFS, Ceph RGW, …).
sftp object — SFTP server.
webDav object — WebDAV endpoint.
RepositoryReplication spec.destination.azure
Section titled “RepositoryReplication spec.destination.azure”
Field Type Default Description
container string required Blob container holding the kopia repository.
auth object — Access credentials (Secret ref / workload identity).
prefix string — Blob-name prefix within the container; empty/absent means the container root.
storageAccount string — Storage-account name (when not inferred from credentials).
RepositoryReplication spec.destination.azure.auth
Section titled “RepositoryReplication spec.destination.azure.auth”
Field Type Default Description
secretRef object — Secret holding the backend’s static access credentials (mutually exclusive with workloadIdentity).
workloadIdentity object — Use a cloud-federated ServiceAccount instead of static keys (mutually exclusive with secretRef).
RepositoryReplication spec.destination.azure.auth.secretRef
Section titled “RepositoryReplication spec.destination.azure.auth.secretRef”
Field Type Default Description
name string required Name of the Secret.
namespace string — Namespace of the Secret; absent = same namespace as the referrer. A ClusterRepository is cluster-scoped and has no namespace of its own, so when IT reads the Secret (to connect, to bootstrap, or to run its repository server) an absent namespace means the operator’s namespace (KOPIUR_NAMESPACE). A workload mover (Snapshot/Restore/Maintenance) still needs the Secret in its OWN namespace — envFrom is namespace-local — so put it there, or use credentialProjection, which needs this namespace set EXPLICITLY to know what to copy. Set it whenever anything other than the operator itself reads the Secret.
RepositoryReplication spec.destination.azure.auth.workloadIdentity
Section titled “RepositoryReplication spec.destination.azure.auth.workloadIdentity”
Field Type Default Description
serviceAccountName string required Name of the ServiceAccount the mover pod runs as, resolved in the Job’s own namespace.
Field Type Default Description
bucket string required B2 bucket holding the kopia repository.
auth object — Access credentials (application key ID/key Secret); Secret-only.
prefix string — Object-name prefix within the bucket; empty/absent means the bucket root.
RepositoryReplication spec.destination.b2.auth
Section titled “RepositoryReplication spec.destination.b2.auth”
Field Type Default Description
secretRef object — Secret holding the backend’s access credentials, read by well-known keys.
RepositoryReplication spec.destination.b2.auth.secretRef
Section titled “RepositoryReplication spec.destination.b2.auth.secretRef”
Field Type Default Description
name string required Name of the Secret.
namespace string — Namespace of the Secret; absent = same namespace as the referrer. A ClusterRepository is cluster-scoped and has no namespace of its own, so when IT reads the Secret (to connect, to bootstrap, or to run its repository server) an absent namespace means the operator’s namespace (KOPIUR_NAMESPACE). A workload mover (Snapshot/Restore/Maintenance) still needs the Secret in its OWN namespace — envFrom is namespace-local — so put it there, or use credentialProjection, which needs this namespace set EXPLICITLY to know what to copy. Set it whenever anything other than the operator itself reads the Secret.
RepositoryReplication spec.destination.filesystem
Section titled “RepositoryReplication spec.destination.filesystem”
Field Type Default Description
path string required Mount path inside the mover pod where kopia writes the repository (e.g. /repo).
volume union — What backs path: a PVC or an inline NFS export; absent for a path already on the node/image.
RepositoryReplication spec.destination.filesystem.volume
Section titled “RepositoryReplication spec.destination.filesystem.volume”

Externally tagged — set exactly one of: nfs · pvc.

Field Type Default Description
nfs object — An inline NFS export mounted directly (no PVC).
pvc object — A PersistentVolumeClaim mounted read-write at the repo path.
RepositoryReplication spec.destination.filesystem.volume.nfs
Section titled “RepositoryReplication spec.destination.filesystem.volume.nfs”
Field Type Default Description
path string required Exported path on the NFS server (e.g. /export/kopia or /mnt/eros/Media).
server string required NFS server hostname or IP (e.g. nas.lan or expanse.internal).
RepositoryReplication spec.destination.filesystem.volume.pvc
Section titled “RepositoryReplication spec.destination.filesystem.volume.pvc”
Field Type Default Description
name string required Name of the PersistentVolumeClaim to mount (in the mover’s namespace).
RepositoryReplication spec.destination.gcs
Section titled “RepositoryReplication spec.destination.gcs”
Field Type Default Description
bucket string required GCS bucket holding the kopia repository.
auth object — Access credentials (service-account key Secret / workload identity).
prefix string — Object-name prefix within the bucket; empty/absent means the bucket root.
RepositoryReplication spec.destination.gcs.auth
Section titled “RepositoryReplication spec.destination.gcs.auth”
Field Type Default Description
secretRef object — Secret holding the backend’s static access credentials (mutually exclusive with workloadIdentity).
workloadIdentity object — Use a cloud-federated ServiceAccount instead of static keys (mutually exclusive with secretRef).
RepositoryReplication spec.destination.gcs.auth.secretRef
Section titled “RepositoryReplication spec.destination.gcs.auth.secretRef”
Field Type Default Description
name string required Name of the Secret.
namespace string — Namespace of the Secret; absent = same namespace as the referrer. A ClusterRepository is cluster-scoped and has no namespace of its own, so when IT reads the Secret (to connect, to bootstrap, or to run its repository server) an absent namespace means the operator’s namespace (KOPIUR_NAMESPACE). A workload mover (Snapshot/Restore/Maintenance) still needs the Secret in its OWN namespace — envFrom is namespace-local — so put it there, or use credentialProjection, which needs this namespace set EXPLICITLY to know what to copy. Set it whenever anything other than the operator itself reads the Secret.
RepositoryReplication spec.destination.gcs.auth.workloadIdentity
Section titled “RepositoryReplication spec.destination.gcs.auth.workloadIdentity”
Field Type Default Description
serviceAccountName string required Name of the ServiceAccount the mover pod runs as, resolved in the Job’s own namespace.
RepositoryReplication spec.destination.gdrive
Section titled “RepositoryReplication spec.destination.gdrive”
Field Type Default Description
folderId string required Google Drive folder ID that holds the kopia repository.
credentialsSecretRef object — Secret holding the Google service-account JSON used to reach the folder, read by the well-known key KOPIA_GDRIVE_CREDENTIALS. Absent means kopia falls back to ambient credentials (GOOGLE_APPLICATION_CREDENTIALS or instance metadata).
RepositoryReplication spec.destination.gdrive.credentialsSecretRef
Section titled “RepositoryReplication spec.destination.gdrive.credentialsSecretRef”
Field Type Default Description
name string required Name of the Secret.
namespace string — Namespace of the Secret; absent = same namespace as the referrer. A ClusterRepository is cluster-scoped and has no namespace of its own, so when IT reads the Secret (to connect, to bootstrap, or to run its repository server) an absent namespace means the operator’s namespace (KOPIUR_NAMESPACE). A workload mover (Snapshot/Restore/Maintenance) still needs the Secret in its OWN namespace — envFrom is namespace-local — so put it there, or use credentialProjection, which needs this namespace set EXPLICITLY to know what to copy. Set it whenever anything other than the operator itself reads the Secret.
RepositoryReplication spec.destination.rclone
Section titled “RepositoryReplication spec.destination.rclone”
Field Type Default Description
remotePath string required rclone path in remote:path form (the remote name must exist in the supplied rclone config).
configSecretRef object — Secret holding the rclone.conf that defines the remote referenced by remote_path.
startupTimeout string — How long kopia waits for its embedded rclone serve to come up before failing the connect, as a Go duration (e.g. 2m). kopia’s default is 15s; raise it for slow remotes whose repository metadata/indexes load through the rclone/WebDAV bridge and take longer than the default budget.
RepositoryReplication spec.destination.rclone.configSecretRef
Section titled “RepositoryReplication spec.destination.rclone.configSecretRef”
Field Type Default Description
name string required Name of the Secret.
namespace string — Namespace of the Secret; absent = same namespace as the referrer. A ClusterRepository is cluster-scoped and has no namespace of its own, so when IT reads the Secret (to connect, to bootstrap, or to run its repository server) an absent namespace means the operator’s namespace (KOPIUR_NAMESPACE). A workload mover (Snapshot/Restore/Maintenance) still needs the Secret in its OWN namespace — envFrom is namespace-local — so put it there, or use credentialProjection, which needs this namespace set EXPLICITLY to know what to copy. Set it whenever anything other than the operator itself reads the Secret.
Field Type Default Description
bucket string required Bucket holding the kopia repository.
auth object — Access credentials (Secret ref / workload identity).
endpoint string — S3 endpoint host. Omit for AWS; set it for MinIO/RustFS/other S3-compatible stores.
prefix string — Key prefix under the bucket, letting several repositories share one bucket (e.g. clusters/prod/). Empty/absent means the bucket root.
region string — S3 region. Required by AWS and some compatible providers.
tls object — TLS overrides for self-signed CAs or HTTP-only endpoints.
RepositoryReplication spec.destination.s3.auth
Section titled “RepositoryReplication spec.destination.s3.auth”
Field Type Default Description
secretRef object — Secret holding the backend’s static access credentials (mutually exclusive with workloadIdentity).
workloadIdentity object — Use a cloud-federated ServiceAccount instead of static keys (mutually exclusive with secretRef).
RepositoryReplication spec.destination.s3.auth.secretRef
Section titled “RepositoryReplication spec.destination.s3.auth.secretRef”
Field Type Default Description
name string required Name of the Secret.
namespace string — Namespace of the Secret; absent = same namespace as the referrer. A ClusterRepository is cluster-scoped and has no namespace of its own, so when IT reads the Secret (to connect, to bootstrap, or to run its repository server) an absent namespace means the operator’s namespace (KOPIUR_NAMESPACE). A workload mover (Snapshot/Restore/Maintenance) still needs the Secret in its OWN namespace — envFrom is namespace-local — so put it there, or use credentialProjection, which needs this namespace set EXPLICITLY to know what to copy. Set it whenever anything other than the operator itself reads the Secret.
RepositoryReplication spec.destination.s3.auth.workloadIdentity
Section titled “RepositoryReplication spec.destination.s3.auth.workloadIdentity”
Field Type Default Description
serviceAccountName string required Name of the ServiceAccount the mover pod runs as, resolved in the Job’s own namespace.
RepositoryReplication spec.destination.s3.tls
Section titled “RepositoryReplication spec.destination.s3.tls”
Field Type Default Description
caBundleRef object — CA bundle (PEM) used to verify the endpoint’s certificate, sourced from a ConfigMap.
disableTls boolean — Disable TLS entirely and talk plain HTTP; maps to kopia’s --disable-tls.
insecureSkipVerify boolean — Skip TLS certificate verification (still uses TLS); maps to kopia’s --disable-tls-verification.
RepositoryReplication spec.destination.s3.tls.caBundleRef
Section titled “RepositoryReplication spec.destination.s3.tls.caBundleRef”
Field Type Default Description
configMapName string — Name of the ConfigMap holding the value (e.g. a CA bundle). Resolved in the referrer’s namespace for a namespaced Repository, and in the operator’s namespace (KOPIUR_NAMESPACE) for a ClusterRepository (cluster-scoped, no namespace of its own).
key string — Which key inside the ConfigMap to read; defaults to ca.crt when unset.
RepositoryReplication spec.destination.sftp
Section titled “RepositoryReplication spec.destination.sftp”
Field Type Default Description
host string required SFTP server hostname or IP.
path string required Remote path on the server that holds the kopia repository.
auth object — Credentials (SSH private key / known-hosts) sourced from a Secret; Secret-only.
port integer —
min 0; max 65535
TCP port; defaults to 22 when absent.
username string — SSH username to connect as.
RepositoryReplication spec.destination.sftp.auth
Section titled “RepositoryReplication spec.destination.sftp.auth”
Field Type Default Description
secretRef object — Secret holding the backend’s access credentials, read by well-known keys.
RepositoryReplication spec.destination.sftp.auth.secretRef
Section titled “RepositoryReplication spec.destination.sftp.auth.secretRef”
Field Type Default Description
name string required Name of the Secret.
namespace string — Namespace of the Secret; absent = same namespace as the referrer. A ClusterRepository is cluster-scoped and has no namespace of its own, so when IT reads the Secret (to connect, to bootstrap, or to run its repository server) an absent namespace means the operator’s namespace (KOPIUR_NAMESPACE). A workload mover (Snapshot/Restore/Maintenance) still needs the Secret in its OWN namespace — envFrom is namespace-local — so put it there, or use credentialProjection, which needs this namespace set EXPLICITLY to know what to copy. Set it whenever anything other than the operator itself reads the Secret.
RepositoryReplication spec.destination.webDav
Section titled “RepositoryReplication spec.destination.webDav”
Field Type Default Description
url string required WebDAV collection URL holding the kopia repository.
auth object — HTTP basic-auth credentials sourced from a Secret; Secret-only.
RepositoryReplication spec.destination.webDav.auth
Section titled “RepositoryReplication spec.destination.webDav.auth”
Field Type Default Description
secretRef object — Secret holding the backend’s access credentials, read by well-known keys.
RepositoryReplication spec.destination.webDav.auth.secretRef
Section titled “RepositoryReplication spec.destination.webDav.auth.secretRef”
Field Type Default Description
name string required Name of the Secret.
namespace string — Namespace of the Secret; absent = same namespace as the referrer. A ClusterRepository is cluster-scoped and has no namespace of its own, so when IT reads the Secret (to connect, to bootstrap, or to run its repository server) an absent namespace means the operator’s namespace (KOPIUR_NAMESPACE). A workload mover (Snapshot/Restore/Maintenance) still needs the Secret in its OWN namespace — envFrom is namespace-local — so put it there, or use credentialProjection, which needs this namespace set EXPLICITLY to know what to copy. Set it whenever anything other than the operator itself reads the Secret.
Field Type Default Description
cron string required The cron expression, parsed by croner; may contain an H placeholder for deterministic jitter.
jitter string — Optional deterministic jitter window as a Go-style duration string (e.g. 30m).
timezone string — IANA timezone the cron is evaluated in (e.g. America/Chicago); absent uses the enclosing schedule’s timezone, else the controller default (UTC).
Field Type Default Description
name string required Name of the referenced Repository/ClusterRepository.
kind enum: Repository | ClusterRepository Repository Which repository CRD this points at; defaults to RepositoryKind::Repository.
namespace string — Cross-namespace Repository reference; ignored/forbidden for ClusterRepository.
Field Type Default Description
cache object — Override the repository’s CacheDefaults for this recipe’s movers.
inheritSecurityContextFrom union — Copy the UID/GID security context from a live workload rather than hard-coding it.
Requires the workload to pin runAsUser (container or pod level): a UID that comes from the container image’s USER line is invisible in the pod spec and cannot be inherited — the mover would silently run as its own image’s UID instead.
May be combined with securityContext/podSecurityContext, which override it field-wise and act as the fallback when no workload pod can be resolved.
podSecurityContext core/v1 PodSecurityContext — Pod security context for the mover (notably fsGroup for group-writable restore volumes). Same layering as securityContext: highest layer, merged field-wise, and combinable with inheritSecurityContextFrom.
privilegedMode boolean — Opt-in, namespace-gated privileged mode. Never changes the UID. When the mover runs as root (runAsUser: 0), adds the capabilities the operation needs on top of drop: ALL: DAC_OVERRIDE for a backup (read files owned by any uid/gid); CHOWN, DAC_OVERRIDE, FOWNER, FSETID for a restore (reproduce original ownership). Grants nothing for maintenance, or when the mover does not run as root (capabilities are inert for non-root); set runAsUser: 0 yourself.
resources core/v1 ResourceRequirements — Resource requests/limits for the mover container.
securityContext core/v1 SecurityContext — Container security context for the mover; merged field-wise over the hardened base, moverDefaults, and any inherited context — this is the highest layer, so every field set here wins. Combines with inheritSecurityContextFrom: fields you set override the workload’s, fields you omit are inherited, and this context stands in alone when inheritance cannot resolve a pod.
ttlSecondsAfterFinished integer — Per-recipe override of Job.spec.ttlSecondsAfterFinished so finished Jobs self-GC.
Field Type Default Description
capacity string — Size of the PVC backing the mover’s kopia cache (e.g. 10Gi).
contentCacheSizeMb integer — kopia content cache budget in MiB (--content-cache-size-mb).
metadataCacheSizeMb integer — kopia metadata cache budget in MiB (--metadata-cache-size-mb).
mode enum: Ephemeral | Persistent — How a mover’s kopia cache volume is provisioned.
storageClassName string — StorageClass for the cache PVC; absent uses the cluster default.
RepositoryReplication spec.mover.inheritSecurityContextFrom
Section titled “RepositoryReplication spec.mover.inheritSecurityContextFrom”

Externally tagged — set exactly one of: pvcConsumer · snapshot · workloadSelector.

Field Type Default Description
pvcConsumer object — Backup sources only: auto-derive the workload from the PVC this snapshot backs up.
snapshot object — Restores only: inherit the identity RECORDED on the backup itself (Snapshot.status.recorded, decoded from the kopiur-meta kopia tag) — uid/gid/fsGroup the backup mover actually ran as. Needs no live workload pod, so it works on a rebuilt cluster and with target.populator. Rejected at admission on SnapshotPolicy/Maintenance (backups read the live workload; maintenance has no snapshot). Write it as snapshot: {} (an empty sub-object) — a bare snapshot: is null and rejected.
workloadSelector object — Inherit from workload pod(s) matched by an explicit label selector (backup or restore).
RepositoryReplication spec.mover.inheritSecurityContextFrom.pvcConsumer
Section titled “RepositoryReplication spec.mover.inheritSecurityContextFrom.pvcConsumer”
Field Type Default Description
container string — Which container within the matched consumer pod to inherit from; absent uses the first/only.
RepositoryReplication spec.mover.inheritSecurityContextFrom.workloadSelector
Section titled “RepositoryReplication spec.mover.inheritSecurityContextFrom.workloadSelector”
Field Type Default Description
podSelector core/v1 LabelSelector required Label selector matching the workload pod(s) to read context/hooks from.
container string — Which container within the matched pod; absent uses the first/only container.
Field Type Default Description
deleteExtra boolean — --delete: prune destination-only blobs so the mirror is an exact copy (kopia default false — additive sync, never removes destination content). Named deleteExtra, not kopia’s bare delete: a delete: true key on backup-adjacent YAML is dangerously ambiguous at a glance.
CAUTION: with this true, blobs present at the destination but absent from the source are deleted on every run.
maxDownloadSpeedBytesPerSecond integer — --max-download-speed: cap read throughput from the source, in bytes/sec (kopia default: unlimited).
maxUploadSpeedBytesPerSecond integer — --max-upload-speed: cap write throughput to the destination, in bytes/sec (kopia default: unlimited).
mustExist boolean — --[no-]must-exist: fail the sync instead of initializing the destination’s repository-format blob (kopia default false — sync-to may create the destination layout on first run).
parallel integer —
min 0
--parallel: number of concurrent blob-copy workers (kopia default 1 — sequential, the root cause of #216’s multi-week seed times to R2).
times boolean — --[no-]times: synchronize blob modification times to the destination, when the destination backend supports it (kopia default true).
update boolean — --[no-]update: update blobs already present at the destination when the source copy is newer (kopia default true).
Field Type Default Description
conditions []object — Standard Kubernetes conditions (Ready, Reconciling, Stalled).
destinationBackend string — The destination backend kind, for the DESTINATION print column.
lastReplicated string — RFC3339 timestamp of the most recent successful replication run.
lastReplicatedBlobs integer — Blobs replicated by the last successful run (best-effort).
lastReplicatedBytes integer — Bytes replicated by the last successful run (best-effort from kopia output).
manualRun object — State of the most recent annotation-requested out-of-band run (kopiur.home-operations.com/run-requested); absent until one is requested.
nextScheduledAt string — RFC3339 timestamp of the next scheduled replication run (cron + jitter, pinned).
observedGeneration integer — metadata.generation last reconciled, for staleness detection / kstatus.
phase enum: Pending | Replicating | Succeeded | Failed | Suspended — Lifecycle phase of a replication.
Field Type Default Description
lastTransitionTime string required lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable.
message string required message is a human readable message indicating details about the transition. This may be an empty string.
reason string required reason contains a programmatic identifier indicating the reason for the condition’s last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty.
status string required status of the condition, one of True, False, Unknown.
type string required type of condition in CamelCase or in foo.example.com/CamelCase.
observedGeneration integer — observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditionsx.observedGeneration is 9, the condition is out of date with respect to the current state of the instance.
Field Type Default Description
completedAt string — RFC3339 instant the run reached a terminal phase.
phase enum: Pending | Running | Succeeded | Failed — Lifecycle of a manual replication run. Closed enum.
requestedAt string — The run-requested annotation value this status reflects (RFC3339), verbatim as the user wrote it — it pins WHICH request is answered.

Scope: Namespaced · Short names: kopiasrepl · Print columns: Source, Destination, Schedule, Phase, Last, Age

Field Type Default Description
destinationRef object required The Repository or ClusterRepository snapshots are copied INTO. A real repository CR with its own password and format (unlike a RepositoryReplication destination, which is a bare backend reusing the source’s password). Must not resolve to the same repository as sourceRef (webhook-enforced structurally; the shared validator catches the literal same-ref case at admission).
schedule object required Cron and deterministic jitter for the replication runs.
sourceRef object required The Repository or ClusterRepository snapshots are copied FROM. Opened read-only by the replication mover — a replication never writes to its source.
credentialProjection object — Opt-in projection of BOTH repositories’ credential Secrets into the mover Job’s namespace (required when the destination is a ClusterRepository whose Secrets live elsewhere).
migrate object — Tuning for the underlying kopia snapshot migrate invocation. Absent: sequential copy, and NO policy copying (see PolicyCopyMode).
mover object — Mover (Job pod) overrides for the replication run.
pruning union — What happens to already-replicated copies at the destination on later runs. Absent = none: copies accumulate forever and — like every mode here — survive deletion of this CR (copy Snapshot CRs carry no ownerReference to it). Pruning only ever considers snapshots this CR replicated (labeled at birth); it never touches the destination’s own directly-written snapshots.
selection object — Which snapshots to copy. Absent: every identity in the source repository, full history (kopia snapshot migrate --all).
suspend boolean — Pause this replication; a suspended replication runs no copies (default false).
Field Type Default Description
name string required Name of the referenced Repository/ClusterRepository.
kind enum: Repository | ClusterRepository Repository Which repository CRD this points at; defaults to RepositoryKind::Repository.
namespace string — Cross-namespace Repository reference; ignored/forbidden for ClusterRepository.
Field Type Default Description
cron string required The cron expression, parsed by croner; may contain an H placeholder for deterministic jitter.
jitter string — Optional deterministic jitter window as a Go-style duration string (e.g. 30m).
timezone string — IANA timezone the cron is evaluated in (e.g. America/Chicago); absent uses the enclosing schedule’s timezone, else the controller default (UTC).
Field Type Default Description
name string required Name of the referenced Repository/ClusterRepository.
kind enum: Repository | ClusterRepository Repository Which repository CRD this points at; defaults to RepositoryKind::Repository.
namespace string — Cross-namespace Repository reference; ignored/forbidden for ClusterRepository.

SnapshotReplication spec.credentialProjection

Section titled “SnapshotReplication spec.credentialProjection”
Field Type Default Description
enabled boolean false Copy the repository’s credential Secret(s) into the namespace of each mover Job; off by default.
Field Type Default Description
parallel integer —
min 0
--parallel: number of snapshots migrated concurrently (kopia default 1 — sequential). Must be >= 1 when set.
policies enum: none | copy | copyOverwrite none Whether kopia policies attached to the copied sources are also copied to the destination. Defaults to PolicyCopyMode::None.
throttle object — Bandwidth/ops caps for THIS replication’s runs, per side. snapshot migrate has no speed flags, so each side is applied as kopia repository throttle set on that side’s connection; source overrides the source repository’s moverDefaults.throttle and destination the destination repository’s, field by field (a field left unset keeps that repository’s default). Absent: both sides use their repository’s defaults.
Field Type Default Description
destination object — Caps for the DESTINATION (write) side, overriding the destination repository’s moverDefaults.throttle field by field. Applied with repository throttle set on the destination connection the migrate writes through.
source object — Caps for the SOURCE (read) side, overriding the source repository’s moverDefaults.throttle field by field. Applied with repository throttle set on the migrate’s read-only source connection — accepted there, so a read-only source is throttled like any other.
SnapshotReplication spec.migrate.throttle.destination
Section titled “SnapshotReplication spec.migrate.throttle.destination”
Field Type Default Description
downloadBytesPerSecond integer — Cap download throughput in bytes/sec (--download-bytes-per-second).
readOpsPerSecond integer — Cap read/list ops/sec (--read-requests-per-second).
uploadBytesPerSecond integer — Cap upload throughput in bytes/sec (--upload-bytes-per-second).
writeOpsPerSecond integer — Cap write ops/sec (--write-requests-per-second).
SnapshotReplication spec.migrate.throttle.source
Section titled “SnapshotReplication spec.migrate.throttle.source”
Field Type Default Description
downloadBytesPerSecond integer — Cap download throughput in bytes/sec (--download-bytes-per-second).
readOpsPerSecond integer — Cap read/list ops/sec (--read-requests-per-second).
uploadBytesPerSecond integer — Cap upload throughput in bytes/sec (--upload-bytes-per-second).
writeOpsPerSecond integer — Cap write ops/sec (--write-requests-per-second).
Field Type Default Description
cache object — Override the repository’s CacheDefaults for this recipe’s movers.
inheritSecurityContextFrom union — Copy the UID/GID security context from a live workload rather than hard-coding it.
Requires the workload to pin runAsUser (container or pod level): a UID that comes from the container image’s USER line is invisible in the pod spec and cannot be inherited — the mover would silently run as its own image’s UID instead.
May be combined with securityContext/podSecurityContext, which override it field-wise and act as the fallback when no workload pod can be resolved.
podSecurityContext core/v1 PodSecurityContext — Pod security context for the mover (notably fsGroup for group-writable restore volumes). Same layering as securityContext: highest layer, merged field-wise, and combinable with inheritSecurityContextFrom.
privilegedMode boolean — Opt-in, namespace-gated privileged mode. Never changes the UID. When the mover runs as root (runAsUser: 0), adds the capabilities the operation needs on top of drop: ALL: DAC_OVERRIDE for a backup (read files owned by any uid/gid); CHOWN, DAC_OVERRIDE, FOWNER, FSETID for a restore (reproduce original ownership). Grants nothing for maintenance, or when the mover does not run as root (capabilities are inert for non-root); set runAsUser: 0 yourself.
resources core/v1 ResourceRequirements — Resource requests/limits for the mover container.
securityContext core/v1 SecurityContext — Container security context for the mover; merged field-wise over the hardened base, moverDefaults, and any inherited context — this is the highest layer, so every field set here wins. Combines with inheritSecurityContextFrom: fields you set override the workload’s, fields you omit are inherited, and this context stands in alone when inheritance cannot resolve a pod.
ttlSecondsAfterFinished integer — Per-recipe override of Job.spec.ttlSecondsAfterFinished so finished Jobs self-GC.
Field Type Default Description
capacity string — Size of the PVC backing the mover’s kopia cache (e.g. 10Gi).
contentCacheSizeMb integer — kopia content cache budget in MiB (--content-cache-size-mb).
metadataCacheSizeMb integer — kopia metadata cache budget in MiB (--metadata-cache-size-mb).
mode enum: Ephemeral | Persistent — How a mover’s kopia cache volume is provisioned.
storageClassName string — StorageClass for the cache PVC; absent uses the cluster default.
SnapshotReplication spec.mover.inheritSecurityContextFrom
Section titled “SnapshotReplication spec.mover.inheritSecurityContextFrom”

Externally tagged — set exactly one of: pvcConsumer · snapshot · workloadSelector.

Field Type Default Description
pvcConsumer object — Backup sources only: auto-derive the workload from the PVC this snapshot backs up.
snapshot object — Restores only: inherit the identity RECORDED on the backup itself (Snapshot.status.recorded, decoded from the kopiur-meta kopia tag) — uid/gid/fsGroup the backup mover actually ran as. Needs no live workload pod, so it works on a rebuilt cluster and with target.populator. Rejected at admission on SnapshotPolicy/Maintenance (backups read the live workload; maintenance has no snapshot). Write it as snapshot: {} (an empty sub-object) — a bare snapshot: is null and rejected.
workloadSelector object — Inherit from workload pod(s) matched by an explicit label selector (backup or restore).
SnapshotReplication spec.mover.inheritSecurityContextFrom.pvcConsumer
Section titled “SnapshotReplication spec.mover.inheritSecurityContextFrom.pvcConsumer”
Field Type Default Description
container string — Which container within the matched consumer pod to inherit from; absent uses the first/only.
SnapshotReplication spec.mover.inheritSecurityContextFrom.workloadSelector
Section titled “SnapshotReplication spec.mover.inheritSecurityContextFrom.workloadSelector”
Field Type Default Description
podSelector core/v1 LabelSelector required Label selector matching the workload pod(s) to read context/hooks from.
container string — Which container within the matched pod; absent uses the first/only container.

Externally tagged — set exactly one of: mirrorSource · none · retention.

Field Type Default Description
mirrorSource object — Mirror the source: delete a copy when its (identity, startTime) has vanished from the source repository.
none object — Never prune: copies accumulate until deleted by hand (the default when spec.pruning is absent).
retention object — Keep copies under an independent GFS retention at the destination, regardless of what the source still holds.
SnapshotReplication spec.pruning.retention
Section titled “SnapshotReplication spec.pruning.retention”
Field Type Default Description
keepAnnual integer —
min 0
Keep one snapshot per year for the most-recent N years.
keepDaily integer —
min 0
Keep one snapshot per day for the most-recent N days.
keepHourly integer —
min 0
Keep one snapshot per hour for the most-recent N hours.
keepLatest integer —
min 0
Keep the N most-recent snapshots regardless of age.
keepMonthly integer —
min 0
Keep one snapshot per month for the most-recent N months.
keepWeekly integer —
min 0
Keep one snapshot per week for the most-recent N weeks.
Field Type Default Description
identities object — Select source identities (username@hostname:path) to copy. Absent: all identities in the source repository.
latestOnly boolean — Copy only each selected identity’s most recent snapshot instead of its full history (kopia snapshot migrate --latest). Default false.
SnapshotReplication spec.selection.identities
Section titled “SnapshotReplication spec.selection.identities”
Field Type Default Description
exclude []object — Identities to skip, applied after include. Exclude wins on overlap.
include []object — Identities to copy. Empty/absent: every identity in the source.
SnapshotReplication spec.selection.identities.exclude[]
Section titled “SnapshotReplication spec.selection.identities.exclude[]”
Field Type Default Description
hostname string — Glob for the hostname component; absent matches any hostname.
sourcePath string — Glob for the sourcePath component; absent matches any path.
username string — Glob for the username component; absent matches any username.
SnapshotReplication spec.selection.identities.include[]
Section titled “SnapshotReplication spec.selection.identities.include[]”
Field Type Default Description
hostname string — Glob for the hostname component; absent matches any hostname.
sourcePath string — Glob for the sourcePath component; absent matches any path.
username string — Glob for the username component; absent matches any username.
Field Type Default Description
conditions []object — Standard Kubernetes conditions (Ready, Reconciling, Stalled).
lastReplicated string — RFC3339 timestamp of the most recent successful replication run (also the scheduling anchor for the next slot).
lastRun object — Counters from the most recent run.
manualRun object — State of the most recent annotation-requested out-of-band run (kopiur.home-operations.com/run-requested); absent until one is requested.
observedGeneration integer — metadata.generation last reconciled, for staleness detection / kstatus.
phase enum: Pending | Replicating | Succeeded | Failed | Suspended — Lifecycle phase of a snapshot replication.
Field Type Default Description
lastTransitionTime string required lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable.
message string required message is a human readable message indicating details about the transition. This may be an empty string.
reason string required reason contains a programmatic identifier indicating the reason for the condition’s last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty.
status string required status of the condition, one of True, False, Unknown.
type string required type of condition in CamelCase or in foo.example.com/CamelCase.
observedGeneration integer — observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditionsx.observedGeneration is 9, the condition is out of date with respect to the current state of the instance.
Field Type Default Description
alreadyPresent integer —
min 0
Selected snapshots that were already present at the destination (skipped).
failed integer —
min 0
Selected snapshots that failed to copy (kopia migrate exits 0 on per-source failures; the mover’s post-verify counts them here).
identitiesSelected integer —
min 0
Source identities the selector matched this run.
incompleteSkipped integer —
min 0
Incomplete source manifests of selected identities — checkpoints an interrupted kopia snapshot create left behind — that this run did not replicate. kopia can never migrate a checkpoint as a complete snapshot, so they are skipped rather than failing the post-verify. Non-zero usually means an abandoned manual backup worth cleaning up with kopia snapshot delete <id> --delete (the mover log names the ids).
pruned integer —
min 0
Copies pruned this run per spec.pruning.
snapshotsCopied integer —
min 0
Snapshots newly copied to the destination this run.
Field Type Default Description
completedAt string — RFC3339 instant the run reached a terminal phase.
phase enum: Pending | Running | Succeeded | Failed — Lifecycle of a manual replication run. Closed enum.
requestedAt string — The run-requested annotation value this status reflects (RFC3339), verbatim as the user wrote it — it pins WHICH request is answered.