Skip to content

Backups & Disaster Recovery

The operator can snapshot the indexer to a repository on a schedule and restore from a snapshot. Backups are opt-in (spec.backup.enabled: true).

Two repository backends are supported:

  • filesystem (default) — a shared volume mounted on the indexer pods. Built into the indexer image (no plugin).
  • s3 — any S3-compatible bucket (AWS S3, MinIO, …) via the repository-s3 plugin, which the operator installs into the indexer at start-up.

Filesystem backend

spec:
  backup:
    enabled: true
    type: filesystem
    schedule: "0 1 * * *"        # daily at 01:00 (cron)
    storage:
      size: 100Gi
      storageClassName: nfs       # see note below

The operator provisions a shared PersistentVolumeClaim (<cluster>-backup), mounts it on every indexer pod at /mnt/wazuh-snapshots, and sets path.repo accordingly.

HA needs ReadWriteMany

Single-node uses ReadWriteOnce. In ha mode all indexer nodes must share the same repository, so the StorageClass must support ReadWriteMany (e.g. NFS, CephFS). A per-pod ReadWriteOnce volume will not work.

S3 backend

spec:
  backup:
    enabled: true
    type: s3
    schedule: "0 1 * * *"
    s3:
      bucket: wazuh-backup
      endpoint: https://s3.eu-central-1.amazonaws.com   # or http://minio:9000
      region: eu-central-1
      credentialsSecret: s3-backup     # keys: access_key, secret_key
      # pluginImage: opensearchproject/opensearch:2.19.5   # must match the indexer's OpenSearch version

The bucket credentials come from a Secret you create:

kubectl create secret generic s3-backup -n wazuh-demo \
  --from-literal=access_key= --from-literal=secret_key=

How it works: an init container installs the repository-s3 plugin (using a version-matched OpenSearch image — override with s3.pluginImage if needed) and a second init container loads the credentials into the indexer keystore. The endpoint's scheme (http/https) and path_style_access are handled for you, so MinIO works out of the box. Plugin install needs network egress from the init container.

Restore

Restore is explicit and one-shot — set the restore annotation to a snapshot name:

kubectl annotate wazuhcluster demo -n wazuh-demo \
  wazuh.bnerd.com/restore-snapshot="snap-20260615-010000" --overwrite

The operator closes the target wazuh-* indices, restores them from the repository and reopens them; status.appliedRestore records the applied snapshot. List available snapshots with the indexer API:

curl -sk -u admin:<pw> 'https://<cluster>-indexer:9200/_snapshot/wazuh-backup/_all'

Note

Restoring overwrites the named indices. For full disaster recovery, restore into a freshly provisioned cluster.

Retention vs backups

Retention (spec.indexer.retention) deletes old indices to bound disk usage; backups copy indices to a separate repository for recovery. They are complementary — see Day-2 Operations.