Wazuh — Authentik edge SSO (proxy auth)¶
Wazuh Dashboard uses OpenSearch Security login by default. When the stack is deployed, configure proxy authentication so Traefik forward-auth headers satisfy the dashboard.
URL: https://wazuh.infra.realemail.app
Stack: services/wazuh/ on infra-services (edge SSO live — see
infra-single-login).
Prerequisites¶
- Wazuh stack up:
docker compose --env-file compose.env up -d - Traefik
authentik@fileon the Wazuh router (already in compose) - Authentik outpost passes
X-authentik-username(seeservices/traefik/config/dynamic/authentik.yml)
Repo configuration¶
| File | Purpose |
|---|---|
services/wazuh/config/wazuh_dashboard/opensearch_dashboards.yml |
auth.type: proxy + proxycache headers (not proxycache — unsupported on Wazuh 4.11) |
services/wazuh/config/wazuh_indexer/config.yml |
Indexer proxy auth domain + internal proxy CIDRs |
services/wazuh/config/wazuh_indexer/roles_mapping.yml |
Map Authentik admins group → OpenSearch roles |
compose.yml mounts the dashboard config. Indexer needs config.yml (proxy auth
domain + trusted proxy CIDRs) and roles_mapping.yml (map Authentik admins
group). Apply after deploy:
Or manually:
bash scripts/sync-internal-users-from-env.sh
bash scripts/sync-wazuh-yml.sh
docker compose --env-file compose.env up -d --force-recreate wazuh-manager wazuh-dashboard
bash scripts/ensure-wazuh-apid.sh
Komodo deploy-infra only runs docker compose up — it does not run
post-deploy-wazuh.sh unless the wazuh stack hooks in
services/komodo/resources.toml are synced. After a Wazuh redeploy without
hooks, run bash scripts/post-deploy-wazuh.sh manually.
Verify¶
Incognito → https://wazuh.infra.realemail.app → Authentik → Wazuh home (no OpenSearch login).
Then verify the containers stay healthy:
cd /opt/homelab/services/wazuh
docker compose --env-file compose.env ps
docker logs --since=10m wazuh-dashboard | grep -iE 'error|fatal' || true
Internal user rotation¶
The repo keeps only the two required internal users: admin and
kibanaserver. Before treating Wazuh as production-ready, the owner must
replace the upstream bootstrap hashes with owner-chosen passwords.
Recommended (scripted): passwords live in secrets.sops.yaml (encrypted in
git). compose.env is rendered from SOPS; bcrypt hashes in internal_users.yml
are derived from the rendered file — you cannot reverse hashes back into passwords.
- Edit
services/wazuh/secrets.sops.yamlwithsops(or VS Code SOPS extension). - Render and apply:
bash /opt/homelab/scripts/render-wazuh-compose-env.sh
bash scripts/sync-internal-users-from-env.sh
bash scripts/sync-wazuh-yml.sh
docker compose --env-file compose.env up -d --force-recreate wazuh-manager wazuh-dashboard
- Commit and push the encrypted
secrets.sops.yaml.
Manual alternative: generate bcrypt with the indexer hash.sh tool, edit
internal_users.yml by hand, set the same plaintext in secrets.sops.yaml,
re-render compose.env, then run bash scripts/apply-security-config.sh and
recreate manager/dashboard.
Troubleshooting¶
| Symptom | Check |
|---|---|
| OpenSearch login still shown | Dashboard config not mounted — docker exec wazuh-dashboard grep auth.type |
| 401 after Authentik | Indexer config.yml proxy domain; indexer logs |
| Dashboard won't start | SSL settings — server.ssl.enabled must be false behind Traefik |
Dashboard healthcheck failing / endless starting |
/api/status returns 401 under proxy auth — run post-deploy-wazuh.sh after deploy-infra |
Filebeat or dashboard 401 to wazuh.indexer:9200 |
Running containers have stale env after hash sync — bash scripts/post-deploy-wazuh.sh |
securityadmin permission denied on admin-key.pem |
TLS keys still owned by uid 1001 — bash scripts/fix-cert-permissions.sh |