Security Hardening¶
The operator ships secure-by-default and exposes a few opt-in hardening controls.
Pod Security Admission¶
The indexer and dashboard containers run with a restricted security context —
runAsNonRoot, a fixed non-root UID, allowPrivilegeEscalation: false, all
capabilities dropped — and every pod sets the RuntimeDefault seccomp profile.
The stack therefore runs under PSA restricted/baseline, with two caveats:
- The manager runs as root and keeps the Linux capabilities ossec needs, so it uses the seccomp baseline only (not the full restricted profile).
- The indexer's privileged
vm.max_map_countinit container is gated byindexer.tuneMaxMapCount. On arestrictednamespace, pre-tune the sysctl on the node pool and settuneMaxMapCount: false.
NetworkPolicies¶
spec.networkPolicy.enabled: true creates per-component ingress policies that
allow only the flows the stack needs:
| Component | Allowed inbound |
|---|---|
| indexer | 9200 from indexer/manager/dashboard/init-jobs; 9300 between indexer nodes |
| manager master | 1516 from manager nodes; 55000 from the dashboard; 1514/1515 (agents) from anywhere |
| manager worker | 1516 from manager nodes; 1514 (agents) from anywhere |
| dashboard | 5601 from anywhere (users / ingress) |
Egress is left unrestricted (the SIEM needs outbound to agents, S3, integrations and DNS). Requires a CNI that enforces NetworkPolicy (Calico, Cilium, k3s's built-in controller, …); with a non-enforcing CNI the policies are inert.
TLS & certificate rotation¶
The operator generates a self-signed CA (10-year) and per-component leaf certs, or
you can bring your own CA via spec.tls.caSecretRef. To rotate the leaf
certificates (e.g. on expiry or compromise), change the rotate annotation:
kubectl annotate wazuhcluster demo -n wazuh-demo \
wazuh.bnerd.com/rotate-certificates="$(date +%s)" --overwrite
The operator re-issues the indexer/manager/dashboard certs from the existing CA
and rolls the pods; status.appliedCertRotation records the trigger. Agents are
unaffected (they authenticate with the registration password and per-agent keys,
not this CA).
Credentials¶
Passwords are generated and stored in a Secret (never inlined in ConfigMaps).
Changing a password re-keys the running indexer via a securityadmin Job and
rolls the consumers — see TLS & Credentials and
Day-2 Operations.
Admission webhook¶
Most cross-field invariants are enforced by CEL rules baked into the CRD (see WazuhCluster reference → Validation), which need no extra components. Two checks that CEL cannot express — the JVM heap not exceeding the indexer memory limit, and not shrinking the indexer below its 3-node quorum — are enforced by an optional validating admission webhook.
It is off by default. Enable it at install/upgrade:
When enabled, the operator generates its own self-signed serving certificate
(no cert-manager dependency), stores it in two Secrets in the operator namespace,
and patches the CA bundle into the ValidatingWebhookConfiguration at startup. The
webhook uses failurePolicy: Fail (set webhook.failurePolicy: Ignore to fail
open) and never applies to the operator's own namespace, so a broken operator pod
cannot deadlock its own recreation. Add extra namespace exclusions with
webhook.namespaceSelector.additionalExclusions.
Requires Kubernetes ≥ 1.16 for
admissionregistration.k8s.io/v1. The CEL rules additionally require Kubernetes ≥ 1.25.