Skip to content

WazuhCluster reference

apiVersion: wazuh.bnerd.com/v1alpha1, kind: WazuhCluster (namespaced).

Spec

Field Type Default Description
version string 4.14.5 Wazuh release for all component images.
deploymentMode enum ha ha or single-node.
imageRegistry string wazuh Registry/namespace prefix for images.
indexer.replicas int 3 (ha) / 1 (single) Indexer nodes.
indexer.image string derived Override indexer image.
indexer.heapSize string derived OpenSearch JVM heap (-Xms/-Xmx). If unset, derived from indexer.resources.limits.memory (~50%, clamped to [256m, 31g]); falls back to 1g when no memory limit is set.
indexer.storage.size string 50Gi Indexer PVC size.
indexer.storage.storageClassName string cluster default Indexer storage class.
indexer.resources ResourceRequirements 500m / 2Gi Indexer container resources (default applied when unset).
indexer.extraConfig string – Appended to opensearch.yml.
indexer.podDisruptionBudget.enabled bool true (≥2 replicas) Create a PodDisruptionBudget (maxUnavailable: 1) protecting indexer quorum on node drains. Never created below 2 replicas.
indexer.tuneMaxMapCount bool true Run a privileged init container to set vm.max_map_count=262144. Set false on PSA-restricted clusters that pre-tune the sysctl at the node pool.
indexer.retention.enabled bool false Apply an OpenSearch ISM policy that deletes old wazuh-alerts-*/wazuh-archives-* indices. Opt-in (deletes security data).
indexer.retention.days int 90 Index age after which indices are deleted when retention is enabled.
manager.image string derived Override manager image (master + workers).
manager.config.fileIntegrityMonitoring.enabled bool true FIM (syscheck) on/off.
manager.config.fileIntegrityMonitoring.directories []string baseline set FIM monitored paths.
manager.config.vulnerabilityDetection.enabled bool true Vulnerability detection on/off.
manager.config.securityConfigurationAssessment.enabled bool true SCA on/off.
manager.config.extraConfig string – Raw XML appended inside <ossec_config>.
manager.config.customRules map[string]string – Custom rule files (name→XML) placed in etc/rules (synced to workers).
manager.config.customDecoders map[string]string – Custom decoder files (name→XML) placed in etc/decoders.
manager.config.cdbLists map[string]string – CDB lists (name→content) placed in etc/lists.
manager.alerts.logLevel int 3 Minimum alert severity (1-16).
manager.alerts.email.enabled bool false Enable SMTP email alerts.
manager.alerts.email.smtpServer / .from / .to[] string(s) – SMTP settings.
manager.master.storage StorageSpec 50Gi Master PVC.
manager.master.resources ResourceRequirements 250m / 1536Mi Master resources (default when unset).
manager.workers.replicas int 2 (ha) / 0 (single) Worker nodes.
manager.workers.storage StorageSpec 50Gi Worker PVC.
manager.workers.resources ResourceRequirements 250m / 1536Mi Worker resources (default when unset).
manager.workers.podDisruptionBudget.enabled bool true (≥2 replicas) Create a PodDisruptionBudget (maxUnavailable: 1) for the workers. Never created below 2 replicas (so off in single-node).
dashboard.replicas int 1 Dashboard pods.
dashboard.image string derived Override dashboard image.
dashboard.resources ResourceRequirements 100m / 1536Mi Dashboard resources (default when unset).
dashboard.service.type enum ClusterIP ClusterIP/NodePort/LoadBalancer.
dashboard.ingress.enabled bool false Create an Ingress for the dashboard.
dashboard.ingress.host string – Ingress host.
dashboard.ingress.className string – ingressClassName.
dashboard.ingress.tls.enabled bool false Enable Ingress TLS.
dashboard.ingress.tls.secretName string dashboard cert TLS secret.
agentService.type enum ClusterIP Exposure for enrollment (1515), events (1514), API (55000).
tls.caSecretRef string – Existing CA secret (tls.crt/tls.key); self-signed if empty.
credentials.credentialsSecret string <name>-credentials Secret holding credentials; set automatically after scrubbing inline values.
credentials.adminPassword string generated Indexer admin password (inline; scrubbed into the Secret).
credentials.kibanaserverPassword string generated Dashboard→indexer password (inline; scrubbed).
credentials.apiPassword string generated Wazuh API password (inline; scrubbed).
credentials.registrationPassword string generated Agent enrollment password / authd.pass (inline; scrubbed).
credentials.clusterKey string generated Manager cluster key (inline; scrubbed).
backup.enabled bool false Register a snapshot repository and run scheduled snapshots.
backup.type enum filesystem filesystem (shared volume) or s3 (repository-s3 plugin).
backup.schedule string 0 1 * * * Cron schedule for snapshots.
backup.storage.size / .storageClassName string 50Gi Shared snapshot volume (filesystem backend; RWX for HA).
backup.s3.bucket / .endpoint / .region / .pathPrefix string – S3 repository settings (s3 backend).
backup.s3.credentialsSecret string – Secret with access_key/secret_key for the bucket.
backup.s3.pluginImage string opensearchproject/opensearch:2.19.5 Version-matched image used to install repository-s3 (needs network).
networkPolicy.enabled bool false Create per-component ingress NetworkPolicies (needs a CNI that enforces them).

Inline credentials.* plaintext is written into the Secret and then removed from the CR, which is rewritten to reference credentialsSecret. See TLS & Credentials.

Status

Field Description
phase Pending / Provisioning / Ready / Degraded / Failed.
observedVersion Version actually running (advances only when fully rolled out).
appliedSecurityRevision Credential revision currently applied to the indexer; drives rotation re-keying.
appliedRestore Snapshot name last restored (via the wazuh.bnerd.com/restore-snapshot annotation).
appliedCertRotation Value of the wazuh.bnerd.com/rotate-certificates annotation last acted on; change the annotation to re-issue leaf certs.
endpoints.dashboard / .agentEnrollment / .indexer Reachable endpoints.
indexer / managerMaster / managerWorkers / dashboard readyReplicas / desiredReplicas.
conditions[] CertificatesReady, IndexerReady, ManagerReady, DashboardReady, Ready.

Example (HA)

apiVersion: wazuh.bnerd.com/v1alpha1
kind: WazuhCluster
metadata:
  name: acme
  namespace: wazuh-acme
spec:
  deploymentMode: ha
  indexer:
    replicas: 3
    storage:
      size: 100Gi
      storageClassName: fast-ssd
  manager:
    workers:
      replicas: 2
  dashboard:
    ingress:
      enabled: true
      host: wazuh.acme.example.com
      className: nginx
      tls:
        enabled: true
  agentService:
    type: LoadBalancer

Full examples live in the repository under examples/.

Validation

The CRD rejects invalid manifests at kubectl apply time using CEL (x-kubernetes-validations), which requires Kubernetes ≥ 1.25 (CEL validation is GA in 1.29; on older API servers these rules are silently skipped). The enforced cross-field invariants are:

  • deploymentMode: ha requires indexer.replicas ≥ 3 (OpenSearch master quorum).
  • deploymentMode: single-node requires indexer.replicas == 1 and no manager workers.
  • backup.type: s3 requires backup.s3.bucket to be set.

A few rules cannot be expressed in CEL (they need quantity math or old-vs-new comparison) and are enforced by the optional validating admission webhook (webhook.enabled in the chart, off by default):

  • indexer.heapSize must not exceed indexer.resources.limits.memory (else the JVM OOMs).
  • The indexer may not be scaled below its 3-node quorum on an ha cluster.

See the Security Hardening guide for how to enable the webhook.