Skip to content

TLS & Credentials

The operator manages all TLS material and credentials itself — no cert-manager dependency and no manual wazuh-cert-tool step.

Certificates

On first reconcile the operator generates a self-signed CA and signs the leaf certificates the stack needs, storing each in a Secret (created once, reused afterwards):

Secret Contents Used by
<name>-ca CA cert + key signing all leaves
<name>-indexer-certs node cert/key, CA, admin client cert/key indexer transport/HTTP, securityadmin
<name>-manager-certs filebeat client cert/key, CA manager → indexer (9200, TLS)
<name>-dashboard-certs dashboard server cert/key, CA dashboard HTTPS

Keys are PKCS#8 (required by the OpenSearch security tooling). The indexer node cert carries SANs for the service and per-pod headless DNS names.

Bring your own CA

Set spec.tls.caSecretRef to an existing Secret holding tls.crt/tls.key and the operator signs all leaves from it instead of generating one.

Credentials

The credentials Secret (<name>-credentials by default) holds:

Key Purpose
admin-password indexer admin (login + filebeat)
kibanaserver-password dashboard → indexer service account
api-password Wazuh API
registration-password agent enrollment password (authd.pass)
cluster-key manager cluster key
admin-hash, kibanaserver-hash bcrypt hashes for internal_users.yml

Passwords are injected into pods via environment variables and are never written into ConfigMaps. Bcrypt hashes are stored so the rendered internal_users.yml stays stable across reconciles. A one-shot securityadmin Job applies the hashed users to the running indexer.

Setting credentials

Three ways, following the nextcloud-operator pattern. Anything you omit is generated.

1. Inline (scrubbed into a Secret). Set values under spec.credentials; the operator writes them into the Secret, then removes the plaintext from the CR and records credentialsSecret — so the stored object never keeps plaintext (GitOps-safe):

spec:
  credentials:
    adminPassword: "choose-a-strong-one"
    registrationPassword: "agent-enrollment-secret"

After reconcile the CR reads:

spec:
  credentials:
    credentialsSecret: demo-credentials   # plaintext removed

2. Reference an existing Secret you manage:

spec:
  credentials:
    credentialsSecret: my-wazuh-creds

Populate it with any of the keys above; the operator fills in (and hashes) only what is missing.

3. Omit spec.credentials — everything is generated into <name>-credentials.

Getting credentials

NS=wazuh-demo; NAME=demo
SECRET=$(kubectl get wazuhcluster $NAME -n $NS -o jsonpath='{.spec.credentials.credentialsSecret}')
# Dashboard / API login (user: admin)
kubectl get secret $SECRET -n $NS -o jsonpath='{.data.admin-password}' | base64 -d; echo
# Agent enrollment password
kubectl get secret $SECRET -n $NS -o jsonpath='{.data.registration-password}' | base64 -d; echo

Rotating credentials

Rotation is automated. Change a password — inline under spec.credentials (scrubbed again) or directly in the referenced Secret — and the operator:

  1. recomputes the security revision (status.appliedSecurityRevision tracks what the indexer currently has);
  2. runs a fresh securityadmin Job to re-key the running indexer to the new password;
  3. only then rolls the affected consumers — the dashboard and manager pods carry a wazuh.bnerd.com/credentials-checksum annotation, so they restart and reconnect with the new value.

Because the consumers are gated on the re-key Job, they never start or roll against an indexer that still has the old password — so a rotation cannot lock you out.

TLS certificate rotation

Credential rotation is automated; certificate/CA rotation is not yet — see the Roadmap.