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.

Conventions

  • Type uses the CRD/YAML shape. enum: A \| B lists the allowed values; []T is an array, map[string]T a map, object (free-form) an unvalidated object, and core/v1 X an embedded Kubernetes type (see the Kubernetes API reference for its fields).
  • Default is the schema default: the API server materializes when the field is absent. means no schema default — an optional field that is simply unset, or one whose effective default depends on context (the description says which).
  • required marks a field with no default that must be present, or admission fails.
  • Externally-tagged unions select a variant by which key you set, never a kind: field; each is flagged "set exactly one of …".
  • Validation rules enforced by the API server (x-kubernetes-validations, including immutability) are listed under the table they apply to.

Repository

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

spec

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

spec.backend

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.
spec.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).
spec.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).
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.
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.
spec.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.
spec.backend.b2.auth
Field Type Default Description
secretRef object Secret holding the backend's access credentials, read by well-known keys.
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.
spec.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.
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.
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).
spec.backend.filesystem.volume.pvc
Field Type Default Description
name string required Name of the PersistentVolumeClaim to mount (in the mover's namespace).
spec.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.
spec.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).
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.
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.
spec.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).
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.
spec.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.
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.
spec.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.
spec.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).
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.
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.
spec.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.
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.
spec.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.
spec.backend.sftp.auth
Field Type Default Description
secretRef object Secret holding the backend's access credentials, read by well-known keys.
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.
spec.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.
spec.backend.webDav.auth
Field Type Default Description
secretRef object Secret holding the backend's access credentials, read by well-known keys.
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.

spec.encryption

Field Type Default Description
passwordSecretRef object required Repository password, always a Secret reference (never inline).
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.

spec.bootstrap

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.
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.

spec.catalog

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).
spec.catalog.retain
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.

spec.concurrency

Field Type Default Description
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.
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.

spec.create

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).
spec.create.ecc
Field Type Default Description
algorithm string ECC algorithm, e.g. REED-SOLOMON-CRC32 (--ecc).
overheadPercent integer Parity overhead as a percentage (--ecc-overhead-percent).

spec.deletionProtection

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.

spec.health

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.
spec.health.probe
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.

spec.identityDefaults

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").

spec.maintenance

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).
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.
spec.maintenance.mover
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; preserves UID/GID on restore.
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.
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.
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).
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.
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.
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.
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).
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).

spec.moverDefaults

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.
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.
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.
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.
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).

spec.parameters

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.
spec.parameters.blobRetention

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

Field Type Default Description
compliance object COMPLIANCEnobody 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 crate::cluster_repository::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.
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.
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.
spec.parameters.epoch
Field Type Default Description
advanceOnCount integer Index blobs in an epoch that trigger an advance, once older than minDuration (kopia default 20).
advanceOnSizeMiB integer Total index size in an epoch that triggers an advance, once older than minDuration (kopia default 10 MiB).
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).
deleteParallelism integer Parallelism for epoch cleanup deletions (kopia default 4).
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.
refreshFrequency string How often clients re-read epoch state (kopia default 20m). Go-style duration.

spec.scheduleDefaults

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 jitterSnapshotSchedule, 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.

spec.seed

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.
spec.seed.from

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.
spec.seed.from.backend

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.
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).
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).
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.
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.
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.
spec.seed.from.backend.b2.auth
Field Type Default Description
secretRef object Secret holding the backend's access credentials, read by well-known keys.
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.
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.
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.
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).
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).
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.
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).
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.
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.
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).
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.
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.
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.
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.
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).
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.
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.
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.
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.
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.
spec.seed.from.backend.sftp.auth
Field Type Default Description
secretRef object Secret holding the backend's access credentials, read by well-known keys.
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.
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.
spec.seed.from.backend.webDav.auth
Field Type Default Description
secretRef object Secret holding the backend's access credentials, read by well-known keys.
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.
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.
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.
spec.seed.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.
spec.seed.migrate
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.
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.
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).
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).
spec.seed.sync
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.

spec.server

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.
spec.server.auth

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).
spec.server.auth.generate
Field Type Default Description
username string UI username to provision (default kopia).
spec.server.auth.insecure
Field Type Default Description
acknowledgeInsecure boolean false Must be true; the webhook rejects insecure mode otherwise.
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.
spec.server.service
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).

status

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.

status.catalog

Field Type Default Description
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).

status.conditions[]

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.

status.health

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.

status.parameters

Field Type Default Description
blobRetention object The blob retention the repository reports.
epoch object The epoch parameters the repository reports.
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.
status.parameters.epoch
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.
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.

status.seed

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.

status.server

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.
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.

status.storageStats

Field Type Default Description
indexBlobCount integer Number of content-index blobs (kopia index list) observed at the last bootstrap.
lastObservedAt string RFC 3339 timestamp these stats were last observed.
snapshotCount integer Total snapshots present in the repository (across all identities).
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).

ClusterRepository

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

spec

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

spec.allowedNamespaces

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.

spec.backend

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.
spec.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).
spec.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).
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.
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.
spec.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.
spec.backend.b2.auth
Field Type Default Description
secretRef object Secret holding the backend's access credentials, read by well-known keys.
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.
spec.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.
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.
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).
spec.backend.filesystem.volume.pvc
Field Type Default Description
name string required Name of the PersistentVolumeClaim to mount (in the mover's namespace).
spec.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.
spec.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).
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.
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.
spec.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).
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.
spec.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.
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.
spec.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.
spec.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).
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.
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.
spec.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.
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.
spec.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.
spec.backend.sftp.auth
Field Type Default Description
secretRef object Secret holding the backend's access credentials, read by well-known keys.
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.
spec.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.
spec.backend.webDav.auth
Field Type Default Description
secretRef object Secret holding the backend's access credentials, read by well-known keys.
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.

spec.encryption

Field Type Default Description
passwordSecretRef object required Repository password, always a Secret reference (never inline).
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.

spec.bootstrap

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.
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.

spec.catalog

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).
spec.catalog.retain
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.

spec.concurrency

Field Type Default Description
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.
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.

spec.create

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).
spec.create.ecc
Field Type Default Description
algorithm string ECC algorithm, e.g. REED-SOLOMON-CRC32 (--ecc).
overheadPercent integer Parity overhead as a percentage (--ecc-overhead-percent).

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.

spec.deletionProtection

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.

spec.health

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.
spec.health.probe
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.

spec.identityDefaults

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").

spec.maintenance

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).
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.
spec.maintenance.mover
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; preserves UID/GID on restore.
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.
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.
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).
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.
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.
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.
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).
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).

spec.moverDefaults

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.
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.
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.
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.
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).

spec.parameters

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.
spec.parameters.blobRetention

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

Field Type Default Description
compliance object COMPLIANCEnobody 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 crate::cluster_repository::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.
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.
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.
spec.parameters.epoch
Field Type Default Description
advanceOnCount integer Index blobs in an epoch that trigger an advance, once older than minDuration (kopia default 20).
advanceOnSizeMiB integer Total index size in an epoch that triggers an advance, once older than minDuration (kopia default 10 MiB).
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).
deleteParallelism integer Parallelism for epoch cleanup deletions (kopia default 4).
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.
refreshFrequency string How often clients re-read epoch state (kopia default 20m). Go-style duration.

spec.scheduleDefaults

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 jitterSnapshotSchedule, 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.

spec.seed

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.
spec.seed.from

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.
spec.seed.from.backend

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.
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).
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).
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.
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.
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.
spec.seed.from.backend.b2.auth
Field Type Default Description
secretRef object Secret holding the backend's access credentials, read by well-known keys.
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.
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.
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.
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).
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).
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.
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).
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.
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.
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).
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.
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.
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.
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.
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).
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.
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.
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.
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.
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.
spec.seed.from.backend.sftp.auth
Field Type Default Description
secretRef object Secret holding the backend's access credentials, read by well-known keys.
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.
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.
spec.seed.from.backend.webDav.auth
Field Type Default Description
secretRef object Secret holding the backend's access credentials, read by well-known keys.
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.
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.
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.
spec.seed.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.
spec.seed.migrate
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.
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.
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).
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).
spec.seed.sync
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.

spec.server

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.
spec.server.auth

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).
spec.server.auth.generate
Field Type Default Description
username string UI username to provision (default kopia).
spec.server.auth.insecure
Field Type Default Description
acknowledgeInsecure boolean false Must be true; the webhook rejects insecure mode otherwise.
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.
spec.server.service
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).

status

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.

status.catalog

Field Type Default Description
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).

status.conditions[]

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.

status.health

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.

status.parameters

Field Type Default Description
blobRetention object The blob retention the repository reports.
epoch object The epoch parameters the repository reports.
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.
status.parameters.epoch
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.
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.

status.seed

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.

status.server

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.
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.

status.storageStats

Field Type Default Description
indexBlobCount integer Number of content-index blobs (kopia index list) observed at the last bootstrap.
lastObservedAt string RFC 3339 timestamp these stats were last observed.
snapshotCount integer Total snapshots present in the repository (across all identities).
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).

SnapshotPolicy

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

spec

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.

spec.compression

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).

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.

spec.deletion

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.

spec.errorHandling

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).

spec.files

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).

spec.hooks

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.
spec.hooks.afterSnapshot[]

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).
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).
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.
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).
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).
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).
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).
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.
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).
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).

spec.identity

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.

spec.mover

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; preserves UID/GID on restore.
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.
spec.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.
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).
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.
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.

spec.preflight

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).
spec.preflight.checks[]
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.

spec.repositories[]

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.

spec.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.

spec.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.

spec.sources[]

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

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.
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).
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.
spec.sources[].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).
spec.sources[].pvc
Field Type Default Description
name string required Name of the PersistentVolumeClaim to back up (in the SnapshotPolicy's namespace).
spec.sources[].pvcSelector
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.
spec.sources[].pvcSelector.namespaceSelector
Field Type Default Description
matchNames []string Exact namespace names to search; empty means the policy's own namespace.

spec.staging

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).

spec.upload

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.

spec.verification

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.
spec.verification.deep
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).
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).
spec.verification.quick
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.
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).

status

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). Single-repo: stamped directly by the verify mover. Multi-repo: computed by the controller as the MINIMUM lastVerified across the CURRENT repositories ("everything is verified as of T"), absent until every current repository has verified at least once.
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-repository verification (#368): RFC3339 markers keyed by the normalized repository key (repo_key). Each verify mover merge-patches ONLY its own key — a JSON merge patch merges map keys, so two concurrent per-repo verifies can never clobber one another (a Vec would be replaced wholesale). The controller folds these into verification on its next pass and prunes keys for repositories no longer in the spec. Never written for the single-repo shape.

status.adoption

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.

status.conditions[]

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.

status.resolved

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.
status.resolved.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).
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).
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.
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).
status.resolved.sources[]
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.

status.retention

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.

status.verification[]

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.
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.

Snapshot

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

spec

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.
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).

spec.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.

spec.policyRef

Field Type Default Description
name string required Name of the referenced SnapshotPolicy.
namespace string Namespace of the SnapshotPolicy; absent = same namespace as the referrer.

spec.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.

spec.source

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.
spec.source.target

Externally tagged — set exactly one of: pvc.

Field Type Default Description
pvc object One PersistentVolumeClaim, fully qualified.
spec.source.target.pvc
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.
spec.source.group
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.

status

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.

status.cleanup

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).

status.conditions[]

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.

status.copiedFrom

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.
status.copiedFrom.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.

status.failure

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).

status.hooks

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.

status.job

Field Type Default Description
attempts integer Number of attempts so far (bounded by failurePolicy.backoffLimit).
name string Name of the mover Job.

status.recorded

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.

status.resolved

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.
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.
status.resolved.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.
status.resolved.sources[]
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.

status.snapshot

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.
status.snapshot.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).

status.staged

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).

status.stats

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.

status.timing

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.

SnapshotSchedule

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

spec

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

spec.schedule

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.

spec.deletion

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.

spec.policyRef

Field Type Default Description
name string required Name of the referenced SnapshotPolicy.
namespace string Namespace of the SnapshotPolicy; absent = same namespace as the referrer.

status

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.

status.conditions[]

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.

status.lastSchedule

Field Type Default Description
at string The RFC3339 instant this slot fired (or is scheduled to); also accepts the scheduledAt alias.
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").
status.lastSchedule.snapshotRef
Field Type Default Description
name string required The Snapshot's metadata.name (same namespace as the schedule).

status.lastSuccessfulSchedule

Field Type Default Description
at string The RFC3339 instant this slot fired (or is scheduled to); also accepts the scheduledAt alias.
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").
status.lastSuccessfulSchedule.snapshotRef
Field Type Default Description
name string required The Snapshot's metadata.name (same namespace as the schedule).

status.nextSchedule

Field Type Default Description
at string The RFC3339 instant this slot fired (or is scheduled to); also accepts the scheduledAt alias.
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").
status.nextSchedule.snapshotRef
Field Type Default Description
name string required The Snapshot's metadata.name (same namespace as the schedule).

Restore

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

spec

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

spec.source

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).
spec.source.fromPolicy
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.
spec.source.identity
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.
spec.source.snapshotRef
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.

spec.target

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

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.
spec.target.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.
spec.target.pvcRef
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.

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.

spec.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.

spec.mover

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; preserves UID/GID on restore.
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.
spec.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.
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).
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.
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.

spec.options

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).

spec.policy

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).

spec.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.

status

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).

status.conditions[]

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.

status.failure

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).

status.progress

Field Type Default Description
bytesRestored integer Total bytes restored so far.
filesRestored integer Total files restored so far.

status.resolved

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.
status.resolved.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).
status.resolved.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.
status.resolved.snapshotRef
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.

status.target

Field Type Default Description
pvcPrime string Populator handshake (passive / pvc-create modes).
pvcRef object The PVC actually written to (created or pre-existing).
status.target.pvcRef
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.

status.timing

Field Type Default Description
endTime string When the restore reached a terminal phase (RFC3339).
startTime string When the mover began restoring (RFC3339).

Maintenance

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

spec

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.

spec.ownership

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.

spec.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.

spec.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.
spec.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).
spec.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).

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.

spec.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.

spec.mover

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; preserves UID/GID on restore.
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.
spec.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.
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).
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.
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.

status

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.
ownership object Current lease holder, if the lease has been claimed.
quick object Last/next-run state for the quick maintenance schedule.

status.conditions[]

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.

status.full

Field Type Default Description
consecutiveFailures integer Count of back-to-back failed runs of this kind; resets on success.
lastContentReclaimedBytes integer Bytes of storage reclaimed by the most recent run of this kind.
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).

status.manualRun

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).

status.ownership

Field Type Default Description
claimedAt string RFC3339 instant the lease was claimed.
owner string The current lease holder's identity (matches Ownership.owner).

status.quick

Field Type Default Description
consecutiveFailures integer Count of back-to-back failed runs of this kind; resets on success.
lastContentReclaimedBytes integer Bytes of storage reclaimed by the most recent run of this kind.
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).

RepositoryReplication

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

spec

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.

spec.destination

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.
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).
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).
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.
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.
spec.destination.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.
spec.destination.b2.auth
Field Type Default Description
secretRef object Secret holding the backend's access credentials, read by well-known keys.
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.
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.
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.
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).
spec.destination.filesystem.volume.pvc
Field Type Default Description
name string required Name of the PersistentVolumeClaim to mount (in the mover's namespace).
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.
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).
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.
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.
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).
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.
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.
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.
spec.destination.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.
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).
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.
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.
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.
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.
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.
spec.destination.sftp.auth
Field Type Default Description
secretRef object Secret holding the backend's access credentials, read by well-known keys.
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.
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.
spec.destination.webDav.auth
Field Type Default Description
secretRef object Secret holding the backend's access credentials, read by well-known keys.
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.

spec.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).

spec.sourceRef

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.

spec.mover

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; preserves UID/GID on restore.
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.
spec.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.
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).
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.
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.

spec.sync

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).

status

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.

status.conditions[]

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.

status.manualRun

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.

SnapshotReplication

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

spec

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).

spec.destinationRef

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.

spec.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).

spec.sourceRef

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.

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.

spec.migrate

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.
spec.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.
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).
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).

spec.mover

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; preserves UID/GID on restore.
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.
spec.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.
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).
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.
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.

spec.pruning

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.
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.

spec.selection

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.
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.
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.
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.

status

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.

status.conditions[]

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.

status.lastRun

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.
pruned integer
min 0
Copies pruned this run per spec.pruning.
snapshotsCopied integer
min 0
Snapshots newly copied to the destination this run.

status.manualRun

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.