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.