Wazuh Deployment

Deploying Wazuh on Kubernetes

Walk through the Wazuh Kubernetes deployment in a guided SOC lab format: clone the deployment repository, generate certificates, validate storage, apply the local manifests, verify the platform, access the dashboard, and document what was built.

Domain alignment

SIEM Operations Platform Operations Kubernetes Security

What this lesson covers

  • Cloning the Wazuh Kubernetes deployment repository
  • Understanding the local Kubernetes deployment layout
  • Preparing certificate scripts on Windows / PowerShell
  • Generating Wazuh indexer and dashboard certificates
  • Checking Kubernetes storage before deploying a stateful platform
  • Applying Wazuh manifests with Kustomize
  • Validating namespaces, services, pods, PVCs, and events
  • Accessing the dashboard with port-forwarding
  • Reviewing default credentials and password-change expectations
  • Understanding expected kubectl apply namespace warnings
  • Troubleshooting common deployment failures
Operator note: This lab follows the Wazuh Kubernetes deployment flow, but explains each step in SOC/operator terms so you understand what is being created and how to validate it.

Before you start

This lesson assumes you already completed the earlier preparation lesson and have a working Kubernetes lab with kubectl, working storage, enough CPU and memory, Git, and a shell that can run Bash scripts.

Keep the current Wazuh Kubernetes deployment documentation open while doing the lab. The training below is written in Stealth IT Group style, but Wazuh version branches, manifests, resource names, service ports, and credentials may change over time.

Step 1: Confirm Kubernetes is ready

Do not start by applying manifests. First make sure the cluster is healthy enough to host a stateful SOC platform.

kubectl config current-context
kubectl get nodes
kubectl get pods -A
kubectl get storageclass

What you are checking

  • Context: kubectl is pointed at the lab cluster you intend to use.
  • Nodes: the cluster has Ready nodes.
  • System pods: the cluster is not already unhealthy.
  • StorageClass: the cluster can dynamically provision storage for stateful Wazuh components.
Field note: Wazuh has stateful components. If your lab has no working StorageClass, Wazuh pods may sit in Pending because persistent volume claims cannot bind.

Step 2: Clone the Wazuh Kubernetes deployment repository

Wazuh publishes Kubernetes deployment manifests in the wazuh-kubernetes repository. Clone the current versioned branch shown in the Wazuh documentation. At the time this page was prepared, the current Wazuh docs used v4.14.5.

git clone https://github.com/wazuh/wazuh-kubernetes.git -b v4.14.5 --depth=1
cd wazuh-kubernetes

What this does

This pulls the Kubernetes manifests, Kustomize overlays, certificate scripts, secrets, services, and workload definitions Wazuh uses to deploy its Kubernetes components.

Operator note: The branch matters. Do not blindly keep using one version forever. Check the current Wazuh documentation before running this lab so the branch matches the supported release you intend to deploy.

Step 3: Review the repository layout

Before applying anything, inspect the directories. This builds operator confidence and helps later troubleshooting.

ls
ls envs
ls envs/local-env
ls wazuh
ls wazuh/certs
ls wazuh/secrets

What to notice

  • envs/local-env/ is the local Kubernetes deployment overlay.
  • envs/eks/ is for Amazon EKS deployments.
  • wazuh/certs/ contains certificate generation material.
  • wazuh/secrets/ contains secret manifests that deserve review.
  • Kustomize is used through kubectl apply -k.

Step 4: Prepare certificate scripts on Windows / PowerShell

If you cloned the Wazuh Kubernetes repository on Windows and are running the certificate scripts through WSL, confirm the scripts use Linux line endings before generating certificates. If the files have Windows CRLF line endings, Bash may fail with errors such as $'\r': command not found, broken cd paths, or OpenSSL parsing errors.

Windows / PowerShell note: This is a common Windows lab issue. The repository may be located under C:\k8s\wazuh-kubernetes, but the certificate scripts are Bash scripts. Run them through WSL after converting the script and config files to Linux line endings.

From PowerShell, while you are in C:\k8s\wazuh-kubernetes, run:

wsl bash -lc "cd /mnt/c/k8s/wazuh-kubernetes && sudo apt-get update && sudo apt-get install -y dos2unix && find wazuh/certs -type f \( -name '*.sh' -o -name '*.cnf' -o -name '*.conf' -o -name '*.yml' -o -name '*.yaml' \) -print0 | xargs -0 dos2unix"

If WSL asks for a password, it is asking for the Linux user password for your WSL distribution. It is not your Kubernetes password, not your Wazuh password, and not the Wazuh dashboard password.

Clean up failed partial certificate output

If you already tried to run the scripts and saw $'\r' errors, clean up any partial certificate files before rerunning the scripts.

wsl bash -lc "cd /mnt/c/k8s/wazuh-kubernetes/wazuh/certs/indexer_cluster && rm -f *.pem *.csr *.srl *-temp.pem && cd ../dashboard_http && rm -f *.pem *.csr *.srl *-temp.pem"

Step 5: Generate the Wazuh indexer certificates

Wazuh components need certificates so the indexer, dashboard, manager, and related services can communicate securely. In a local lab, self-signed certificates are acceptable. In production, certificate handling needs real lifecycle ownership.

bash wazuh/certs/indexer_cluster/generate_certs.sh

PowerShell / WSL command

If you are running the lab from PowerShell with the repository at C:\k8s\wazuh-kubernetes, run the script through WSL:

wsl bash -lc "cd /mnt/c/k8s/wazuh-kubernetes && bash wazuh/certs/indexer_cluster/generate_certs.sh"

What you should see

The script should create certificate material for multiple Wazuh components. Successful output should show certificate and key creation rather than shell errors.

If this fails

  • Confirm you are in the wazuh-kubernetes directory.
  • Confirm the script exists at wazuh/certs/indexer_cluster/generate_certs.sh.
  • Confirm your shell can run Bash scripts.
  • Confirm file permissions allow the script to execute or run it explicitly through bash.
  • If you see $'\r': command not found, convert the files to Linux line endings using the Windows / PowerShell step above.

Step 6: Generate the Wazuh dashboard certificates

The dashboard also needs certificate material for HTTPS access.

bash wazuh/certs/dashboard_http/generate_certs.sh

PowerShell / WSL command

If you are running the lab from PowerShell with the repository at C:\k8s\wazuh-kubernetes, run the script through WSL:

wsl bash -lc "cd /mnt/c/k8s/wazuh-kubernetes && bash wazuh/certs/dashboard_http/generate_certs.sh"

What this means

The generated certificate files are later consumed by Kustomize secret generators or secret manifests so Kubernetes can mount the certificate material into the appropriate Wazuh components.

Security note: Lab certificates are not production certificate management. In production, certificate ownership, rotation, secret storage, trust chains, and access control must be designed intentionally.

Step 7: Confirm your storage class

Wazuh has stateful components, so storage must work before the platform will become healthy.

kubectl get sc

Look for a default StorageClass. If your cluster uses a local lab platform, the provisioner name may be different than Wazuh's examples. That is normal. What matters is that your PVCs can bind successfully.

If you need to adjust storage

Wazuh's local deployment includes storage configuration under envs/local-env/. Review the storage class file before applying manifests:

cat envs/local-env/storage-class.yaml

If your lab requires a different provisioner, adjust the file before applying the local manifests. Do not guess. Match the provisioner to what your cluster actually supports.

Step 8: Review the local deployment overlay

Before you deploy, inspect the local overlay.

cat envs/local-env/kustomization.yml
kubectl kustomize envs/local-env/ | head -n 80

What you are checking

  • The namespace and resources being created
  • Secret generators or secret references
  • Services and service types
  • Stateful components and PVC definitions
  • Image names and tags
  • Resource requests, limits, and storage sizes
Operator note: Previewing generated manifests is a strong habit. It helps you understand what Kubernetes is about to receive before you ask the API server to create it.

Step 9: Apply the local Kubernetes manifests

Before applying the manifests, confirm the generated certificate files exist. Kustomize will fail if files such as wazuh/certs/indexer_cluster/root-ca.pem are missing.

Get-ChildItem .\wazuh\certs\indexer_cluster\*.pem
Get-ChildItem .\wazuh\certs\dashboard_http\*.pem

You should see files such as:

root-ca.pem
node.pem
node-key.pem
dashboard.pem
dashboard-key.pem
admin.pem
admin-key.pem
filebeat.pem
filebeat-key.pem
Do not skip this check: If root-ca.pem does not exist, stop and fix certificate generation before running kubectl apply -k envs/local-env/.

For a local lab, use the local-env overlay.

kubectl apply -k envs/local-env/

Expected warning if the namespace already exists

If you created the wazuh namespace earlier during lab preparation, you may see a warning similar to this:

Warning: resource namespaces/wazuh is missing the kubectl.kubernetes.io/last-applied-configuration annotation...
namespace/wazuh configured

This is not a deployment failure. It means the namespace was originally created with kubectl create namespace instead of kubectl apply, so it did not have the apply-tracking annotation. Kubernetes patches the annotation automatically and continues.

What this creates

Expect Kubernetes to create the Wazuh namespace, secrets, services, StatefulSets, Deployments, persistent volume claims, and supporting configuration.

Step 10: Watch the deployment come up

Stateful platforms take time. Watch the pods instead of immediately assuming failure.

kubectl get pods -n wazuh -w

Press Ctrl+C when you are done watching.

What you may see

  • Pending: scheduling or storage may not be ready.
  • ContainerCreating: images, volumes, or mounts are being prepared.
  • Running: the container started.
  • Ready 0/1: the container started but readiness checks may not be satisfied yet.
  • CrashLoopBackOff: the container started and failed repeatedly.

Step 11: Verify the Wazuh namespace

kubectl get namespaces | grep wazuh

You should see the wazuh namespace active.

Step 12: Verify Wazuh services

kubectl get services -n wazuh
kubectl get services -n wazuh -o wide

Look for services for the dashboard, indexer, Wazuh manager, Wazuh cluster, and workers. Exact names and service types can vary by version and environment.

Step 13: Verify pods, storage, and events

kubectl get pods -n wazuh -o wide
kubectl get statefulset -n wazuh
kubectl get deployment -n wazuh
kubectl get pvc -n wazuh
kubectl get secrets -n wazuh
kubectl get events -n wazuh --sort-by=.lastTimestamp

What healthy looks like

  • Pods should eventually reach Running and Ready states.
  • PVCs should be Bound.
  • Services should exist for expected components.
  • Events should not show ongoing image pull, mount, scheduling, or readiness failures.

Step 14: Access the dashboard with port-forwarding

In a local lab, do not expose the dashboard broadly. Use port-forwarding to bind dashboard access to the local machine.

kubectl -n wazuh port-forward --address 127.0.0.1 service/dashboard 8443:443

Then open:

https://127.0.0.1:8443

Your browser may warn about the certificate because the lab uses self-signed certificates.

Step 15: Login and immediately review credentials

Wazuh's Kubernetes deployment documentation lists the default lab dashboard credentials as:

Username: admin
Password: SecretPassword

Use these only as lab defaults. After confirming the dashboard works, review the Wazuh documentation for changing default user passwords and document what you changed.

Security note: Default credentials are acceptable only as a short-lived lab bootstrap step. They are not acceptable for persistent, shared, exposed, or production-like environments.

Step 16: Document the deployment

Before moving to the next lesson, capture a short deployment record.

Deployment date:
Wazuh branch/version:
Kubernetes context:
StorageClass:
Namespace:
Dashboard access method:
Default credentials changed:
Pods healthy:
PVCs bound:
Windows / PowerShell line-ending fix needed:
Known issues:
Cleanup procedure:

Common deployment problems

Certificate script fails with $'\r': command not found

This means the Bash scripts have Windows CRLF line endings. Convert the certificate scripts and config files with dos2unix, remove partial certificate output, and rerun both certificate generation scripts through WSL.

wsl bash -lc "cd /mnt/c/k8s/wazuh-kubernetes && find wazuh/certs -type f \( -name '*.sh' -o -name '*.cnf' -o -name '*.conf' -o -name '*.yml' -o -name '*.yaml' \) -print0 | xargs -0 dos2unix"

wsl bash -lc "cd /mnt/c/k8s/wazuh-kubernetes/wazuh/certs/indexer_cluster && rm -f *.pem *.csr *.srl *-temp.pem && cd ../dashboard_http && rm -f *.pem *.csr *.srl *-temp.pem"

wsl bash -lc "cd /mnt/c/k8s/wazuh-kubernetes && bash wazuh/certs/indexer_cluster/generate_certs.sh && bash wazuh/certs/dashboard_http/generate_certs.sh"

Kustomize fails because root-ca.pem is missing

This means certificate generation did not complete successfully. Confirm the PEM files exist before applying manifests.

Get-ChildItem .\wazuh\certs\indexer_cluster\*.pem
Get-ChildItem .\wazuh\certs\dashboard_http\*.pem

kubectl apply warns that the wazuh namespace is missing the last-applied annotation

This is expected if you created the namespace earlier with kubectl create namespace wazuh. The apply command patches the missing annotation automatically and continues. Treat it as a warning, not a deployment failure.

StatefulSet pods stay Pending because PVCs are Pending

If the dashboard is Running but the Wazuh indexer and manager pods are Pending, check PVCs before troubleshooting Wazuh itself.

kubectl get pvc -n wazuh
kubectl get events -n wazuh --sort-by=.lastTimestamp

If events show failed to provision volume with StorageClass "wazuh-storage": configuration error, no node was specified, the local StorageClass likely needs volumeBindingMode: WaitForFirstConsumer. The next lesson walks through this in detail.

Pods stay Pending

kubectl describe pod -n wazuh <pod-name>
kubectl get pvc -n wazuh
kubectl describe pvc -n wazuh <pvc-name>
kubectl get events -n wazuh --sort-by=.lastTimestamp

Most Pending problems are scheduling, resource, or storage related.

PVCs stay Pending

Check your StorageClass and provisioner. If dynamic provisioning is not working, Wazuh stateful components will not become healthy.

Image pull failures

kubectl describe pod -n wazuh <pod-name>

Look for image name, tag, registry, authentication, or network-related errors.

Readiness failures

kubectl logs -n wazuh <pod-name>
kubectl describe pod -n wazuh <pod-name>

Readiness failures can happen while Wazuh components initialize. If they persist, inspect logs and events.

Dashboard does not open

  • Confirm the dashboard service exists.
  • Confirm the port-forward command is still running.
  • Confirm you are browsing to https://127.0.0.1:8443.
  • Confirm dashboard pods are Running and Ready.

Cleanup note

Do not delete Wazuh casually unless you are done with the lab. Stateful workloads can leave PVCs and storage behind. Use Wazuh cleanup guidance and confirm what will be removed before deleting resources.

Bottom line: You did not just install Wazuh. You deployed a stateful SOC platform into Kubernetes, validated its moving parts, accessed the dashboard safely, and documented the operational state of the lab.

Check your understanding

Use these questions to check whether the deployment concepts are clear before moving forward.

  1. Why should you confirm cluster health before applying Wazuh manifests?
  2. Why does the Wazuh version branch matter?
  3. What is the purpose of the Wazuh Kubernetes repository?
  4. Why are certificates generated before applying the manifests?
  5. Why does storage matter for Wazuh?
  6. What is the difference between envs/eks and envs/local-env?
  7. What does kubectl apply -k envs/local-env/ do?
  8. Why should you watch pods after applying manifests?
  9. What does a Bound PVC indicate?
  10. Why use port-forwarding for dashboard access in a local lab?
  11. Why are default credentials a security concern?
  12. What should you document after deployment?
  13. What should you check first if pods are Pending?
  14. What should you check if the dashboard will not open?
  15. What does $'\r': command not found usually mean when running the certificate scripts?
  16. Why should you remove partial certificate output after a failed certificate-generation attempt?
  17. Is the missing last-applied-configuration namespace warning a deployment failure?
Answer key
  1. A broken cluster makes Wazuh troubleshooting unreliable because platform failures can look like Wazuh failures.
  2. The branch controls which manifests, images, scripts, and deployment structure you are using.
  3. It provides the Kubernetes manifests, overlays, scripts, secrets, and configuration used to deploy Wazuh.
  4. Wazuh components use certificate material for secure component communication and dashboard access.
  5. Stateful Wazuh components need persistent storage, and pods may not start if PVCs cannot bind.
  6. envs/eks is for Amazon EKS; envs/local-env is for other/local Kubernetes clusters.
  7. It applies the Kustomize local deployment overlay to the cluster.
  8. Stateful platforms take time, and watching status helps distinguish normal initialization from failure.
  9. The PVC has successfully matched to storage and is available for the pod.
  10. It avoids broadly exposing the sensitive dashboard while learning locally.
  11. They are publicly documented and should not remain in persistent, shared, or exposed deployments.
  12. Version, context, StorageClass, namespace, dashboard access, credential status, pod health, PVC state, known issues, and cleanup plan.
  13. Describe the pod, check PVCs, check resources, and review namespace events.
  14. Check the service name, port-forward process, URL, certificate warning, and dashboard pod readiness.
  15. The scripts have Windows CRLF line endings and need to be converted to Linux line endings before running through Bash.
  16. Partial files can leave the certificate directories in a confusing broken state, so clean them up before rerunning the scripts.
  17. No. In this lab it usually means the namespace was created earlier with kubectl create namespace; Kubernetes patches the annotation automatically and continues.
← Previous: Preparing the Kubernetes Lab for Wazuh Series index Next: Troubleshooting Wazuh on Kubernetes →