Hello all,
I have been working on configuring Wazuh to use Keycloak as an IdP via OIDC authentication. I followed this Medium article to get me where I'm at:
https://medium.com/@jaishiaditya2000/integrating-wazuh-with-keycloak-for-secure-sso-authentication-0b2eebd00632Currently, when I navigate to Wazuh's dashboard URL (
https://10.95.1.24:30100), my browser (firefox-vnc) routes me to sign-in via the WazuhOpenID Keycloak realm's portal. After correctly entering the 'test' user's credentials, I am prompted to change the password. After changing the password, I believe I should be authenticated into the Wazuh Dashboard. However, I instead receive the following error:
statusCode: 401
error: "Unauthorized"
message: "Unauthorized"
Both Wazuh and Keycloak are configured with TLS, and I have created a cert (ca-bundle.pem) that is the result of cat'ing Wazuh's root-ca.pem + Keycloak's tls.pem, in that order. This secret is stored on the wazuh-dashboard pod at '/usr/share/wazuh-dashboard/certs/ca-bundle.pem', and the wazuh-indexer pod at '/usr/share/wazuh-indexer/certs/ca-bundle.pem'.
Below are some of my Wazuh files:
/usr/share/wazuh-dashboard/config/opensearch_dashboards.yml: server.host: 0.0.0.0
server.port: 5601
opensearch.hosts: https://indexer:9200
opensearch.ssl.verificationMode: none
opensearch.requestHeadersWhitelist: [ authorization,securitytenant ]
opensearch_security.multitenancy.enabled: false
opensearch_security.readonly_mode.roles: ["kibana_read_only"]
server.ssl.enabled: true
server.ssl.key: "/usr/share/wazuh-dashboard/certs/key.pem"
server.ssl.certificate: "/usr/share/wazuh-dashboard/certs/cert.pem"
opensearch.ssl.certificateAuthorities: ["/usr/share/wazuh-dashboard/certs/ca-bundle.pem"]
uiSettings.overrides.defaultRoute: /app/wz-home
# Session expiration settings
opensearch_security.cookie.ttl: 900000
opensearch_security.session.ttl: 900000
opensearch_security.session.keepalive: true
# OIDC stuff
opensearch_security.auth.multiple_auth_enabled: true
opensearch_security.auth.type: ["basicauth","openid"]
opensearch_security.openid.connect_url: https://keycloak.keycloak.svc.cluster.local:8443/realms/WazuhOpenID/.well-known/openid-configuration
opensearch_security.openid.base_redirect_url: https://10.95.1.24:30100
opensearch_security.openid.client_id: wazuh-OpenID
'authc' block inside /usr/share/wazuh-indexer/config/opensearch-security/config.yml:
authc:
openid_auth_domain:
http_enabled: true
transport_enabled: true
order: 0
http_authenticator:
type: openid
challenge: false
config:
openid_connect_idp:
enable_ssl: true
verify_hostnames: true
subject_key: preferred_username
roles_key: roles
openid_connect_url:
https://keycloak.keycloak.svc.cluster.local:8443/realms/WazuhOpenID/.well-known/openid-configuration authentication_backend:
type: noop
basic_internal_auth_domain:
description: "Authenticate via HTTP Basic against internal users database"
http_enabled: true
transport_enabled: true
order: 1
http_authenticator:
type: basic
challenge: true
authentication_backend:
type: intern
kerberos_auth_domain:
http_enabled: false
transport_enabled: false
order: 6
http_authenticator:
type: kerberos
challenge: true
config:
# If true a lot of kerberos/security related debugging output will be logged to standard out
krb_debug: false
# If true then the realm will be stripped from the user name
strip_realm_from_principal: true
authentication_backend:
type: noop
proxy_auth_domain:
description: "Authenticate via proxy"
http_enabled: false
transport_enabled: false
order: 3
http_authenticator:
type: proxy
challenge: false
config:
user_header: "x-proxy-user"
roles_header: "x-proxy-roles"
authentication_backend:
type: noop
jwt_auth_domain:
description: "Authenticate via Json Web Token"
http_enabled: false
transport_enabled: false
order: 1
http_authenticator:
type: jwt
challenge: false
config:
signing_key: "base64 encoded HMAC key or public RSA/ECDSA pem key"
jwt_header: "Authorization"
jwt_url_parameter: null
jwt_clock_skew_tolerance_seconds: 30
roles_key: null
subject_key: null
authentication_backend:
type: noop
clientcert_auth_domain:
description: "Authenticate via SSL client certificates"
http_enabled: false
transport_enabled: false
order: 2
http_authenticator:
type: clientcert
config:
username_attribute: cn #optional, if omitted DN becomes username
challenge: false
authentication_backend:
type: noop
ldap:
description: "Authenticate via LDAP or Active Directory"
http_enabled: false
transport_enabled: false
order: 5
http_authenticator:
type: basic
challenge: false
authentication_backend:
# LDAP authentication backend (authenticate users against a LDAP or Active Directory)
type: ldap
config:
# enable ldaps
enable_ssl: false
# enable start tls, enable_ssl should be false
enable_start_tls: false
# send client certificate
enable_ssl_client_auth: false
# verify ldap hostname
verify_hostnames: true
hosts:
- localhost:8389
bind_dn: null
password: null
userbase: 'ou=people,dc=example,dc=com'
# Filter to search for users (currently in the whole subtree beneath userbase)
# {0} is substituted with the username
usersearch: '(sAMAccountName={0})'
# Use this attribute from the user as username (if not set then DN is used)
username_attribute: null
I also set the 'NODE_EXTRA_CA_CERTS' environment variable inside of the wazuh-dashboard container to equal '/usr/share/wazuh-dashboard/certs/ca-bundle.pem'.
wazuh-dashboard pod logs after I attempt to sign-in, resulting in that 401 'Unauthorized' error:
{"type":"log","@timestamp":"2026-02-24T00:10:01Z","tags":["error","plugins","securityDashboards"],"pid":54,"message":"OpenId authentication failed: Error: Authentication Exception"}
{"type":"response","@timestamp":"2026-02-24T00:10:01Z","tags":[],"pid":54,"method":"get","statusCode":401,"req":{"url":"/auth/openid/login?state=_Qppr3iTK6vuohYKl6L9KO&session_state=050c68e6-600a-3a67-d56a-e97262622907&iss=https%3A%2F%2Fkeycloak.keycloak.svc.cluster.local%3A8443%2Frealms%2FWazuhOpenID&code=61d1bc0d-8d37-2d28-43de-1e4efc72c6b3.050c68e6-600a-3a67-d56a-e97262622907.8ffe91e2-c2a9-425a-9c82-9e0be8f0d0f6","method":"get","headers":{"host":"
10.95.1.24:30100","user-agent":"Mozilla/5.0 (X11; Linux x86_64; rv:140.0) Gecko/20100101 Firefox/140.0","accept":"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8","accept-language":"en-US,en;q=0.5","accept-encoding":"gzip, deflate, br, zstd","connection":"keep-alive","upgrade-insecure-requests":"1","sec-fetch-dest":"document","sec-fetch-mode":"navigate","sec-fetch-site":"none","sec-fetch-user":"?1","priority":"u=0, i"},"remoteAddress":"10.150.1.0","userAgent":"Mozilla/5.0 (X11; Linux x86_64; rv:140.0) Gecko/20100101 Firefox/140.0"},"res":{"statusCode":401,"responseTime":92,"contentLength":9},"message":"GET /auth/openid/login?state=_Qppr3iTK6vuohYKl6L9KO&session_state=050c68e6-600a-3a67-d56a-e97262622907&iss=https%3A%2F%2Fkeycloak.keycloak.svc.cluster.local%3A8443%2Frealms%2FWazuhOpenID&code=61d1bc0d-8d37-2d28-43de-1e4efc72c6b3.050c68e6-600a-3a67-d56a-e97262622907.8ffe91e2-c2a9-425a-9c82-9e0be8f0d0f6 401 92ms - 9.0B"}
{"type":"response","@timestamp":"2026-02-24T00:10:01Z","tags":[],"pid":54,"method":"get","statusCode":401,"req":{"url":"/favicon.ico","method":"get","headers":{"host":"
10.95.1.24:30100","user-agent":"Mozilla/5.0 (X11; Linux x86_64; rv:140.0) Gecko/20100101 Firefox/140.0","accept":"image/avif,image/webp,image/png,image/svg+xml,image/*;q=0.8,*/*;q=0.5","accept-language":"en-US,en;q=0.5","accept-encoding":"gzip, deflate, br, zstd","connection":"keep-alive","referer":"
https://10.95.1.24:30100/auth/openid/login?state=_Qppr3iTK6vuohYKl6L9KO&session_state=050c68e6-600a-3a67-d56a-e97262622907&iss=https%3A%2F%2Fkeycloak.keycloak.svc.cluster.local%3A8443%2Frealms%2FWazuhOpenID&code=61d1bc0d-8d37-2d28-43de-1e4efc72c6b3.050c68e6-600a-3a67-d56a-e97262622907.8ffe91e2-c2a9-425a-9c82-9e0be8f0d0f6","sec-fetch-dest":"image","sec-fetch-mode":"no-cors","sec-fetch-site":"cross-site","priority":"u=6"},"remoteAddress":"10.150.1.0","userAgent":"Mozilla/5.0 (X11; Linux x86_64; rv:140.0) Gecko/20100101 Firefox/140.0","referer":"
https://10.95.1.24:30100/auth/openid/login?state=_Qppr3iTK6vuohYKl6L9KO&session_state=050c68e6-600a-3a67-d56a-e97262622907&iss=https%3A%2F%2Fkeycloak.keycloak.svc.cluster.local%3A8443%2Frealms%2FWazuhOpenID&code=61d1bc0d-8d37-2d28-43de-1e4efc72c6b3.050c68e6-600a-3a67-d56a-e97262622907.8ffe91e2-c2a9-425a-9c82-9e0be8f0d0f6"},"res":{"statusCode":401,"responseTime":2,"contentLength":9},"message":"GET /favicon.ico 401 2ms - 9.0B"}
I have been troubleshooting this for a painfully long time. If anybody can offer me some kind of advice here, it would be appreciated beyond words.
Please feel free to ask me for any additional information and I will be more than happy to provide it.
Thank you,
Jacob Molland