Open distro - openid connect - keycloak

Hello,
we want to use amazon open distro with openid connect. We use keycloak and followed the instructions here “Kibana Single Sign-On with OpenID and Keycloak | Search Guard” to configure open distro and keycloak. After a successful login we get a screen with error message “Authentication failed. Please provide a new token.” instead of Kibana.
Thx a lot for help

some more details:

docker-compose.yml

version: ‘3’
services:
odfe-node1:
image: amazon/opendistro-for-elasticsearch:1.1.0
container_name: odfe-node1
environment:
- cluster.name=odfe-cluster
- node.name=odfe-node1
- discovery.seed_hosts=odfe-node1,odfe-node2
- cluster.initial_master_nodes=odfe-node1,odfe-node2
- bootstrap.memory_lock=true # along with the memlock settings below, disables swapping
- “ES_JAVA_OPTS=-Xms512m -Xmx512m” # minimum and maximum Java heap size, recommend setting both to 50% of system RAM
ulimits:
memlock:
soft: -1
hard: -1
nofile:
soft: 65536 # maximum number of open files for the Elasticsearch user, set to at least 65536 on modern systems
hard: 65536
volumes:
- odfe-data1:/usr/share/elasticsearch/data
- ./cert/root-ca.pem:/usr/share/elasticsearch/config/root-ca.pem
- ./cert/node1.pem:/usr/share/elasticsearch/config/node1.pem
- ./cert/node1-key.pem:/usr/share/elasticsearch/config/node1-key.pem
- ./cert/admin.pem:/usr/share/elasticsearch/config/admin.pem
- ./cert/admin-key.pem:/usr/share/elasticsearch/config/admin-key.pem
- ./elasticsearch1.yml:/usr/share/elasticsearch/config/elasticsearch.yml
- ./config.yml:/usr/share/elasticsearch/plugins/opendistro_security/securityconfig/config.yml
ports:
- 9200:9200
- 9600:9600 # required for Performance Analyzer
networks:
- odfe-net
depends_on:
- keycloak

odfe-node2:
image: amazon/opendistro-for-elasticsearch:1.1.0
container_name: odfe-node2
environment:
- cluster.name=odfe-cluster
- node.name=odfe-node2
- discovery.seed_hosts=odfe-node1,odfe-node2
- cluster.initial_master_nodes=odfe-node1,odfe-node2
- bootstrap.memory_lock=true
- “ES_JAVA_OPTS=-Xms512m -Xmx512m”
ulimits:
memlock:
soft: -1
hard: -1
nofile:
soft: 65536
hard: 65536
volumes:
- odfe-data2:/usr/share/elasticsearch/data
- ./cert/root-ca.pem:/usr/share/elasticsearch/config/root-ca.pem
- ./cert/node2.pem:/usr/share/elasticsearch/config/node2.pem
- ./cert/node2-key.pem:/usr/share/elasticsearch/config/node2-key.pem
- ./cert/admin.pem:/usr/share/elasticsearch/config/admin.pem
- ./cert/admin-key.pem:/usr/share/elasticsearch/config/admin-key.pem
- ./elasticsearch2.yml:/usr/share/elasticsearch/config/elasticsearch.yml
- ./config.yml:/usr/share/elasticsearch/plugins/opendistro_security/securityconfig/config.yml
networks:
- odfe-net
depends_on:
- keycloak

odfe-kibana:
image: amazon/opendistro-for-elasticsearch-kibana:1.1.0
container_name: odfe-kibana
ports:
- 5601:5601
expose:
- “5601”
environment:
ELASTICSEARCH_URL: https://odfe-node1:9200
ELASTICSEARCH_HOSTS: https://odfe-node1:9200
volumes:
- ./kibana.yml:/usr/share/kibana/config/kibana.yml
- ./cert/root-ca.pem:/usr/share/kibana/config/root-ca.pem
- ./cert/kibana.pem:/usr/share/kibana/config/kibana.pem
- ./cert/kibana-key.pem:/usr/share/kibana/config/kibana-key.pem
networks:
- odfe-net
depends_on:
- odfe-node1
- odfe-node2

mysql:
image: mysql:5.7
container_name: mysql
volumes:
- mysql_data:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: keycloak
MYSQL_USER: keycloak
MYSQL_PASSWORD: password
networks:
- odfe-net

keycloak:
image: jboss/keycloak
container_name: keycloak
environment:
DB_VENDOR: MYSQL
DB_ADDR: mysql
DB_DATABASE: keycloak
DB_USER: keycloak
DB_PASSWORD: password
KEYCLOAK_USER: admin
KEYCLOAK_PASSWORD: admin
KEYCLOAK_LOGLEVEL: DEBUG
ROOT_LOGLEVEL: DEBUG
volumes:
- ./cert/tls.key:/etc/x509/https/tls.key
- ./cert/tls.crt:/etc/x509/https/tls.crt
networks:
- odfe-net
ports:
- 8080:8080
- 8443:8443
depends_on:
- mysql

volumes:
mysql_data:
odfe-data1:
odfe-data2:

networks:
odfe-net:
external: true

config.yml - uploaded using

plugins/opendistro_security/tools/securityadmin.sh --diagnose -f plugins/opendistro_security/securityconfig/config.yml -icl -nhnv -cert config/admin.pem -cacert config/root-ca.pem -key config/admin-key.pem -t config


This is the main Open Distro Security configuration file where authentication

and authorization is defined.

You need to configure at least one authentication domain in the authc of this file.

An authentication domain is responsible for extracting the user credentials from

the request and for validating them against an authentication backend like Active Directory for example.

If more than one authentication domain is configured the first one which succeeds wins.

If all authentication domains fail then the request is unauthenticated.

In this case an exception is thrown and/or the HTTP status is set to 401.

After authentication authorization (authz) will be applied. There can be zero or more authorizers which collect

the roles from a given backend for the authenticated user.

Both, authc and auth can be enabled/disabled separately for REST and TRANSPORT layer. Default is true for both.

http_enabled: true

transport_enabled: true

For HTTP it is possible to allow anonymous authentication. If that is the case then the HTTP authenticators try to

find user credentials in the HTTP request. If credentials are found then the user gets regularly authenticated.

If none can be found the user will be authenticated as an “anonymous” user. This user has always the username “anonymous”

and one role named “anonymous_backendrole”.

If you enable anonymous authentication all HTTP authenticators will not challenge.

Note: If you define more than one HTTP authenticators make sure to put non-challenging authenticators like “proxy” or “clientcert”

first and the challenging one last.

Because it’s not possible to challenge a client with two different authentication methods (for example

Kerberos and Basic) only one can have the challenge flag set to true. You can cope with this situation

by using pre-authentication, e.g. sending a HTTP Basic authentication header in the request.

Default value of the challenge flag is true.

HTTP

basic (challenging)

proxy (not challenging, needs xff)

kerberos (challenging)

clientcert (not challenging, needs https)

jwt (not challenging)

host (not challenging) #DEPRECATED, will be removed in a future version.

host based authentication is configurable in roles_mapping

Authc

internal

noop

ldap

Authz

ldap

noop

_meta:
type: “config”
config_version: 2

config:
dynamic:
# Set filtered_alias_mode to ‘disallow’ to forbid more than 2 filtered aliases per index
# Set filtered_alias_mode to ‘warn’ to allow more than 2 filtered aliases per index but warns about it (default)
# Set filtered_alias_mode to ‘nowarn’ to allow more than 2 filtered aliases per index silently
#filtered_alias_mode: warn
#do_not_fail_on_forbidden: false
#kibana:
# Kibana multitenancy
#multitenancy_enabled: true
#server_username: kibanaserver
#index: ‘.kibana’
http:
anonymous_auth_enabled: false
xff:
enabled: false
internalProxies: ‘192.168.0.10|192.168.0.11’ # regex pattern
#internalProxies: ‘.*’ # trust all internal proxies, regex pattern
#remoteIpHeader: ‘x-forwarded-for’

authc:
  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
  basic_internal_auth_domain:
    description: "Authenticate via HTTP Basic against internal users database"
    http_enabled: true
    transport_enabled: true
    order: 0
    http_authenticator:
      type: basic
      challenge: true
    authentication_backend:
      type: intern
  openid_auth_domain:
    http_enabled: true
    transport_enabled: true
    order: 1
    http_authenticator:
      type: openid
      challenge: false
      config:
        subject_key: preferred_username
        roles_key: roles
        openid_connect_url: https://keycloak:8443/auth/realms/kibana-sso/.well-known/openid-configuration
        enable_ssl: true
        verify_hostnames: false
        pemtrustedcas_filepath: /usr/share/elasticsearch/config/root-ca.pem
    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: 4
    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
        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
authz:
  roles_from_myldap:
    description: "Authorize via LDAP or Active Directory"
    http_enabled: false
    transport_enabled: false
    authorization_backend:
      # LDAP authorization backend (gather roles from a LDAP or Active Directory, you have to configure the above LDAP authentication backend settings too)
      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
        rolebase: 'ou=groups,dc=example,dc=com'
        # Filter to search for roles (currently in the whole subtree beneath rolebase)
        # {0} is substituted with the DN of the user
        # {1} is substituted with the username
        # {2} is substituted with an attribute value from user's directory entry, of the authenticated user. Use userroleattribute to specify the name of the attribute
        rolesearch: '(member={0})'
        # Specify the name of the attribute which value should be substituted with {2} above
        userroleattribute: null
        # Roles as an attribute of the user entry
        userrolename: disabled
        #userrolename: memberOf
        # The attribute in a role entry containing the name of that role, Default is "name".
        # Can also be "dn" to use the full DN as rolename.
        rolename: cn
        # Resolve nested roles transitive (roles which are members of other roles and so on ...)
        resolve_nested_roles: true
        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: '(uid={0})'
        # Skip users matching a user name, a wildcard or a regex pattern
        #skip_users:
        #  - 'cn=Michael Jackson,ou*people,o=TEST'
        #  - '/\S*/'
  roles_from_another_ldap:
    description: "Authorize via another Active Directory"
    http_enabled: false
    transport_enabled: false
    authorization_backend:
      type: ldap
      #config goes here ...

auth_failure_listeners:

ip_rate_limiting:

type: ip

allowed_tries: 10

time_window_seconds: 3600

block_expiry_seconds: 600

max_blocked_clients: 100000

max_tracked_clients: 100000

internal_authentication_backend_limiting:

type: username

authentication_backend: intern

allowed_tries: 10

time_window_seconds: 3600

block_expiry_seconds: 600

max_blocked_clients: 100000

max_tracked_clients: 100000

elasticsearch1.yml (es node 1)

cluster.name: “odfe-cluster”
network.host: 0.0.0.0

opendistro_security.ssl.transport.pemcert_filepath: node1.pem
opendistro_security.ssl.transport.pemkey_filepath: node1-key.pem
opendistro_security.ssl.transport.pemtrustedcas_filepath: root-ca.pem
opendistro_security.ssl.transport.enforce_hostname_verification: false
opendistro_security.ssl.http.enabled: true
opendistro_security.ssl.http.pemcert_filepath: node1.pem
opendistro_security.ssl.http.pemkey_filepath: node1-key.pem
opendistro_security.ssl.http.pemtrustedcas_filepath: root-ca.pem
#opendistro_security.allow_unsafe_democertificates: true
opendistro_security.allow_default_init_securityindex: true
opendistro_security.authcz.admin_dn:
- ‘CN=admin,O=TSIUS,L=NewYork,C=US’

opendistro_security.nodes_dn:
- ‘CN=odfe-node1,O=TSI,L=Darmstadt,C=DE’
- ‘CN=odfe-node2,O=TSI,L=Darmstadt,C=DE’
- ‘CN=odfe-kibana,O=TSI,L=Darmstadt,C=DE’
- ‘CN=,O=TSI,L=Darmstadt,C=DE’
- 'CN=odfe-cluster

- ‘/CN=.*regex/’

opendistro_security.audit.type: internal_elasticsearch
opendistro_security.enable_snapshot_restore_privilege: true
opendistro_security.check_snapshot_restore_write_privileges: true
opendistro_security.restapi.roles_enabled: [“all_access”, “security_rest_api_access”]
cluster.routing.allocation.disk.threshold_enabled: false
node.max_local_storage_nodes: 3

kibana.yml


server.name: odfe-kibana
#server.host: “0”
server.host: odfe-kibana
server.port: 5601
elasticsearch.hosts: https://odfe-node1:9200
elasticsearch.ssl.verificationMode: none
elasticsearch.username: kibanaserver
elasticsearch.password: kibanaserver
elasticsearch.requestHeadersWhitelist: [“securitytenant”,“Authorization”, “security_tenant”]

server.ssl.enabled: true
server.ssl.key: /usr/share/kibana/config/kibana-key.pem
server.ssl.certificate: /usr/share/kibana/config/kibana.pem

opendistro_security.multitenancy.enabled: true
opendistro_security.multitenancy.tenants.preferred: [“Private”, “Global”]
opendistro_security.readonly_mode.roles: [“kibana_read_only”]

opendistro_security.allow_client_certificates: false
opendistro_security.cookie.secure: false
opendistro_security.cookie.password: “12345678901234567890123456789012”
opendistro_security.auth.type: “openid”
opendistro_security.openid.connect_url: “h-t-t-p-s://keycloak:8443/auth/realms/kibana-sso/.well-known/openid-configuration”
opendistro_security.openid.client_id: “kibana-sso”
opendistro_security.openid.client_secret: “00f5e45c-a632-40d3-b595-a908450839ec”
opendistro_security.openid.root_ca: /usr/share/kibana/config/root-ca.pem
opendistro_security.openid.base_redirect_url: “h-t-t-p-s://odfe-kibana:5601/”

config.yml again without some remarks


_meta:
type: “config”
config_version: 2

config:
dynamic:
http:
anonymous_auth_enabled: false
xff:
enabled: false
internalProxies: ‘192.168.0.10|192.168.0.11’ # regex pattern
#internalProxies: ‘.’ # trust all internal proxies, regex pattern
#remoteIpHeader: ‘x-forwarded-for’
authc:
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
basic_internal_auth_domain:
description: “Authenticate via HTTP Basic against internal users database”
http_enabled: true
transport_enabled: true
order: 0
http_authenticator:
type: basic
challenge: true
authentication_backend:
type: intern
openid_auth_domain:
http_enabled: true
transport_enabled: true
order: 1
http_authenticator:
type: openid
challenge: false
config:
subject_key: preferred_username
roles_key: roles
openid_connect_url: https://keycloak:8443/auth/realms/kibana-sso/.well-known/openid-configuration
enable_ssl: true
verify_hostnames: false
pemtrustedcas_filepath: /usr/share/elasticsearch/config/root-ca.pem
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: 4
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
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
authz:
roles_from_myldap:
description: “Authorize via LDAP or Active Directory”
http_enabled: false
transport_enabled: false
authorization_backend:
# LDAP authorization backend (gather roles from a LDAP or Active Directory, you have to configure the above LDAP authentication backend settings too)
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
rolebase: ‘ou=groups,dc=example,dc=com’
# Filter to search for roles (currently in the whole subtree beneath rolebase)
# {0} is substituted with the DN of the user
# {1} is substituted with the username
# {2} is substituted with an attribute value from user’s directory entry, of the authenticated user. Use userroleattribute to specify the name of the attribute
rolesearch: ‘(member={0})’
# Specify the name of the attribute which value should be substituted with {2} above
userroleattribute: null
# Roles as an attribute of the user entry
userrolename: disabled
#userrolename: memberOf
# The attribute in a role entry containing the name of that role, Default is “name”.
# Can also be “dn” to use the full DN as rolename.
rolename: cn
# Resolve nested roles transitive (roles which are members of other roles and so on …)
resolve_nested_roles: true
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: ‘(uid={0})’
# Skip users matching a user name, a wildcard or a regex pattern
#skip_users:
# - 'cn=Michael Jackson,ou
people,o=TEST’
# - ‘/\S*/’
roles_from_another_ldap:
description: “Authorize via another Active Directory”
http_enabled: false
transport_enabled: false
authorization_backend:
type: ldap
#config goes here …

Facing this problem. Can u help me with this

https://stackoverflow.com/questions/60622018/opendistro-throwing-an-error-on-accepting-a-jwt-token-from-keycloak

Hello,
unfortunately I have no stackoverflow account.
At the end we didn’t use the configuration I described, because we couldn’t solve the problem. I think there was a DNS problem and may be wrong certificates.
Now we are using an Apache reverse proxy in front of Kibana (Keycloak Client with apache and mod_auth_oidc). A description of this solution is here: GitHub - thomasdarimont/keycloak_mod_auth_oidc_example: Demonstrates the configuration of the mod_auth_oidc Apache Module for use with Keycloak.
best regards

Please find the clear question llauber
I am buidling a setup where there are three components:

  1. Keycloak as An IDP using openid connect , as well as client authentication method as client_secret.

  2. Opendistro security plugin with JWT token configuration.

  3. Python code trying to make an API call from access token got through curl command.

OpenDistro security plugin configuration:

---

---

# This is the main Open Distro Security configuration file where authentication
# and authorization is defined.
#
# You need to configure at least one authentication domain in the authc of this file.
# An authentication domain is responsible for extracting the user credentials from
# the request and for validating them against an authentication backend like Active Directory for example.
#
# If more than one authentication domain is configured the first one which succeeds wins.
# If all authentication domains fail then the request is unauthenticated.
# In this case an exception is thrown and/or the HTTP status is set to 401.
#
# After authentication authorization (authz) will be applied. There can be zero or more authorizers which collect
# the roles from a given backend for the authenticated user.
#
# Both, authc and auth can be enabled/disabled separately for REST and TRANSPORT layer. Default is true for both.
#        http_enabled: true
#        transport_enabled: true
#
# For HTTP it is possible to allow anonymous authentication. If that is the case then the HTTP authenticators try to
# find user credentials in the HTTP request. If credentials are found then the user gets regularly authenticated.
# If none can be found the user will be authenticated as an "anonymous" user. This user has always the username "anonymous"
# and one role named "anonymous_backendrole".
# If you enable anonymous authentication all HTTP authenticators will not challenge.
#
#
# Note: If you define more than one HTTP authenticators make sure to put non-challenging authenticators like "proxy" or "clientcert"
# first and the challenging one last.
# Because it's not possible to challenge a client with two different authentication methods (for example
# Kerberos and Basic) only one can have the challenge flag set to true. You can cope with this situation
# by using pre-authentication, e.g. sending a HTTP Basic authentication header in the request.
#
# Default value of the challenge flag is true.
#
#
# HTTP
#   basic (challenging)
#   proxy (not challenging, needs xff)
#   kerberos (challenging)
#   clientcert (not challenging, needs https)
#   jwt (not challenging)
#   host (not challenging) #DEPRECATED, will be removed in a future version.
#                          host based authentication is configurable in roles_mapping

# Authc
#   internal
#   noop
#   ldap

# Authz
#   ldap
#   noop



_meta:
  type: "config"
  config_version: 2

config:
  dynamic:
    # Set filtered_alias_mode to 'disallow' to forbid more than 2 filtered aliases per index
    # Set filtered_alias_mode to 'warn' to allow more than 2 filtered aliases per index but warns about it (default)
    # Set filtered_alias_mode to 'nowarn' to allow more than 2 filtered aliases per index silently
    #filtered_alias_mode: warn
    #do_not_fail_on_forbidden: false
    #kibana:
    # Kibana multitenancy
    #multitenancy_enabled: true
    #server_username: kibanaserver
    #index: '.kibana'
    http:
      anonymous_auth_enabled: false
      xff:
        enabled: false
        internalProxies: '192\.168\.0\.10|192\.168\.0\.11' # regex pattern
        #internalProxies: '.*' # trust all internal proxies, regex pattern
        #remoteIpHeader:  'x-forwarded-for'
        ###### see https://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html for regex help
        ###### more information about XFF https://en.wikipedia.org/wiki/X-Forwarded-For
        ###### and here https://tools.ietf.org/html/rfc7239
        ###### and https://tomcat.apache.org/tomcat-8.0-doc/config/valve.html#Remote_IP_Valve
    authc:
      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
      basic_internal_auth_domain:
        description: "Authenticate via HTTP Basic against internal users database"
        http_enabled: true
        transport_enabled: true
        order: 4
        http_authenticator:
          type: basic
          challenge: true
        authentication_backend:
          type: intern
      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: true
        transport_enabled: false
        order: 0
        http_authenticator:
          type: jwt
          challenge: false
          config:
            signing_key: "-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt6GjgJTJUztz7ATm3+vYPGnnotQ5hFX57OL1UkLoqVKr+sfS6DxCl9f4/2L818TLYbtn0h9GnUOf/8XJLQpWy+B6uK3X0vVMJyzYqIaRrhUStZTXUnxOwSCzEk2sq7MT2akStA4QwtsJ9b6YbkWq4Tp0ml0kWYsqIDELnza7YJRjmDR/AFPbqiFdCANFpUtuq/heiVux9vZb881dYUmkcYtC3voH2J+KYAoCmljOtg33ioeVBLkrhzGW/7u2XJ+ELTrk7ZrXrDxpQmYaL3aojMv60BFI+WoY4xFjrTai2D1fao32I6sOcITyY6K74HCo+Fyx6cc6UiJEO5bDGrfFNQIDAQAB-----END PUBLIC KEY-----"
            jwt_header: "Authorization"
            jwt_url_parameter: null
            roles_key: roles
            subject_key: preferred_username
            openid_connect_url: "http://10.95.126.45:8080/auth/realms/demo/protocol/openid-connect/certs"
        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
      saml_auth_domain:
        http_enabled: true
        transport_enabled: false
        order: 8
        http_authenticator:
          type: saml
          challenge: true
          config:
            idp:
              metadata_url: http://10.95.126.45:8080/auth/realms/demo/protocol/saml/descriptor
              entity_id: http://10.95.126.45:8080/auth/realms/demo
            sp:
              entity_id: kibana-saml
            #kibana_url: http://10.95.126.45:5601
            roles_key: Role
            exchange_key: E3B0C44298FC000000000000000000000000000000000000A495991B7852B855
        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
    authz:
      roles_from_myldap:
        description: "Authorize via LDAP or Active Directory"
        http_enabled: false
        transport_enabled: false
        authorization_backend:
          # LDAP authorization backend (gather roles from a LDAP or Active Directory, you have to configure the above LDAP authentication backend settings too)
          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
            rolebase: 'ou=groups,dc=example,dc=com'
            # Filter to search for roles (currently in the whole subtree beneath rolebase)
            # {0} is substituted with the DN of the user
            # {1} is substituted with the username
            # {2} is substituted with an attribute value from user's directory entry, of the authenticated user. Use userroleattribute to specify the name of the attribute
            rolesearch: '(member={0})'
            # Specify the name of the attribute which value should be substituted with {2} above
            userroleattribute: null
            # Roles as an attribute of the user entry
            userrolename: disabled
            #userrolename: memberOf
            # The attribute in a role entry containing the name of that role, Default is "name".
            # Can also be "dn" to use the full DN as rolename.
            rolename: cn
            # Resolve nested roles transitive (roles which are members of other roles and so on ...)
            resolve_nested_roles: true
            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: '(uid={0})'
            # Skip users matching a user name, a wildcard or a regex pattern
            #skip_users:
            #  - 'cn=Michael Jackson,ou*people,o=TEST'
            #  - '/\S*/'
      roles_from_another_ldap:
        description: "Authorize via another Active Directory"
        http_enabled: false
        transport_enabled: false
        authorization_backend:
          type: ldap
          #config goes here ...
  #    auth_failure_listeners:
  #      ip_rate_limiting:
  #        type: ip
  #        allowed_tries: 10
  #        time_window_seconds: 3600
  #        block_expiry_seconds: 600
  #        max_blocked_clients: 100000
  #        max_tracked_clients: 100000
  #      internal_authentication_backend_limiting:
  #        type: username
  #        authentication_backend: intern
  #        allowed_tries: 10
  #        time_window_seconds: 3600
  #        block_expiry_seconds: 600
  #        max_blocked_clients: 100000
  #        max_tracked_clients: 100000


KeyCloak configuration: KeyCloak-Client-OpenIDconnect-Client-Authentication-picture

KeyCloak-Client-Configuration-page-main

KeyCloak-Realm-configuration-page

KeyCloak OIDC JSON for reference:

{
  "realm": "demo",
  "auth-server-url": "http://10.95.126.45:8080/auth/",
  "ssl-required": "none",
  "resource": "elastic-2",
  "verify-token-audience": true,
  "credentials": {
    "secret": "9e30fff3-ab4b-4b5d-89c9-0d94cf807483"
  },
  "confidential-port": 0,
  "policy-enforcer": {}
}

The application i am making query is as follows:

curl http://10.95.126.45:8080/auth/realms/demo/protocol/openid-connect/token \
-H 'Cache-Control: nocache' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-H 'Postman-Token: c43306f5-f2b9-46c9-b0fb-efd63314df4c' \
-H 'cache-control: no-cache' \
-d 'grant_type=client_credentials&client_id=elastic-2&client_secret=9e30fff3-ab4b-4b5d-89c9-0d94cf807483'

I am able to get the access token from this command. With jwt.io , verify the signature by putting the public key in keys section of realm in keycloak.

Verification of JWT Token using the same signing key in JWT configuration of opendistro

Then I am quering elastic search using a python requests library.

import requests
access_token="eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJGLUpqN0VRWjU2anJoNDFrQjBsdzBoYmpreUQwNEpNVEtENDkxa0RaLTlVIn0.eyJqdGkiOiJkNzNiNWI4Ni1lNjgwLTQ0ZDMtYTgyNC00Mjk3NjVhZTM1YzkiLCJleHAiOjE1ODM4NTYwNTIsIm5iZiI6MCwiaWF0IjoxNTgzODU1NzUyLCJpc3MiOiJodHRwOi8vMTAuOTUuMTI2LjQ1OjgwODAvYXV0aC9yZWFsbXMvZGVtbyIsImF1ZCI6ImFjY291bnQiLCJzdWIiOiJlOWI4NGJkZC1lZDgyLTQ3YWYtOTg2OC1lYzc5NDE3Y2NkOWEiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJlbGFzdGljLTIiLCJhdXRoX3RpbWUiOjAsInNlc3Npb25fc3RhdGUiOiI3MDcyZGRhZi1iMWVjLTQxYTUtODAwZi1lNzNlNTExMmNkMjEiLCJhY3IiOiIxIiwiYWxsb3dlZC1vcmlnaW5zIjpbIioiXSwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbIm9mZmxpbmVfYWNjZXNzIiwidW1hX2F1dGhvcml6YXRpb24iXX0sInJlc291cmNlX2FjY2VzcyI6eyJlbGFzdGljLTIiOnsicm9sZXMiOlsidW1hX3Byb3RlY3Rpb24iXX0sImFjY291bnQiOnsicm9sZXMiOlsibWFuYWdlLWFjY291bnQiLCJtYW5hZ2UtYWNjb3VudC1saW5rcyIsInZpZXctcHJvZmlsZSJdfX0sInNjb3BlIjoicHJvZmlsZSBlbWFpbCIsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwiY2xpZW50SG9zdCI6IjEwLjk1LjEyNi40NSIsImNsaWVudElkIjoiZWxhc3RpYy0yIiwicHJlZmVycmVkX3VzZXJuYW1lIjoic2VydmljZS1hY2NvdW50LWVsYXN0aWMtMiIsImNsaWVudEFkZHJlc3MiOiIxMC45NS4xMjYuNDUifQ.AI7_jkNAK_LD5jsgOn-wn4xdk4ZKXqAo1G7m0MjaIjco37dfxGEL-cKhDnZYvsRiULmXtsBXjBBZchOpsoyWbAczH-cNxeQ9bPwbi8saV-9sHLccTpHdZZAY_vG3JyrCaHhno4F9VnU-smks4E-fe8H-Wm1v7yfX6WiCb3txUOwE5z4VTjgNyCOsEpAVQZ2luMiwXK6a450F3DCmzg3gwfseAIPOJxfQBdGje20wK8eRMBSapEHOY75JTFM9ADjN6bOEFHhiWFeaAz0aii20tgNUcfJHCGnDPjrPdUkjy0vqYTSW1SDyhltFgoYJMF9-XWKBM3mL4ctEZw9VmKdBwA"
headers = {'Authorization': 'Bearer %s' % (access_token)}
            # YOLO
response = requests.get('https://localhost:9200/demo_index*/_search', headers=headers, verify=False)
print(response.text)

NOTE: The access token above is valid one you can check with Signing key of jwt opendistro and this token to see the signatures verified.

However , when run the above python script i get an error.

The error on elastic search is as follows:

[2020-03-10T11:59:06,295][INFO ][c.a.d.a.h.j.AbstractHTTPJwtAuthenticator] [localhost.localdomain] Extracting JWT token from eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJGLUpqN0VRWjU2anJoNDFrQjBsdzBoYmpreUQwNEpNVEtENDkxa0RaLTlVIn0.eyJqdGkiOiJkNzNiNWI4Ni1lNjgwLTQ0ZDMtYTgyNC00Mjk3NjVhZTM1YzkiLCJleHAiOjE1ODM4NTYwNTIsIm5iZiI6MCwiaWF0IjoxNTgzODU1NzUyLCJpc3MiOiJodHRwOi8vMTAuOTUuMTI2LjQ1OjgwODAvYXV0aC9yZWFsbXMvZGVtbyIsImF1ZCI6ImFjY291bnQiLCJzdWIiOiJlOWI4NGJkZC1lZDgyLTQ3YWYtOTg2OC1lYzc5NDE3Y2NkOWEiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJlbGFzdGljLTIiLCJhdXRoX3RpbWUiOjAsInNlc3Npb25fc3RhdGUiOiI3MDcyZGRhZi1iMWVjLTQxYTUtODAwZi1lNzNlNTExMmNkMjEiLCJhY3IiOiIxIiwiYWxsb3dlZC1vcmlnaW5zIjpbIioiXSwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbIm9mZmxpbmVfYWNjZXNzIiwidW1hX2F1dGhvcml6YXRpb24iXX0sInJlc291cmNlX2FjY2VzcyI6eyJlbGFzdGljLTIiOnsicm9sZXMiOlsidW1hX3Byb3RlY3Rpb24iXX0sImFjY291bnQiOnsicm9sZXMiOlsibWFuYWdlLWFjY291bnQiLCJtYW5hZ2UtYWNjb3VudC1saW5rcyIsInZpZXctcHJvZmlsZSJdfX0sInNjb3BlIjoicHJvZmlsZSBlbWFpbCIsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwiY2xpZW50SG9zdCI6IjEwLjk1LjEyNi40NSIsImNsaWVudElkIjoiZWxhc3RpYy0yIiwicHJlZmVycmVkX3VzZXJuYW1lIjoic2VydmljZS1hY2NvdW50LWVsYXN0aWMtMiIsImNsaWVudEFkZHJlc3MiOiIxMC45NS4xMjYuNDUifQ.AI7_jkNAK_LD5jsgOn-wn4xdk4ZKXqAo1G7m0MjaIjco37dfxGEL-cKhDnZYvsRiULmXtsBXjBBZchOpsoyWbAczH-cNxeQ9bPwbi8saV-9sHLccTpHdZZAY_vG3JyrCaHhno4F9VnU-smks4E-fe8H-Wm1v7yfX6WiCb3txUOwE5z4VTjgNyCOsEpAVQZ2luMiwXK6a450F3DCmzg3gwfseAIPOJxfQBdGje20wK8eRMBSapEHOY75JTFM9ADjN6bOEFHhiWFeaAz0aii20tgNUcfJHCGnDPjrPdUkjy0vqYTSW1SDyhltFgoYJMF9-XWKBM3mL4ctEZw9VmKdBwA failed
com.amazon.dlic.auth.http.jwt.keybyoidc.BadCredentialsException: Algorithm of JWT does not match algorithm of JWK (HS512 != RS256)
        at com.amazon.dlic.auth.http.jwt.keybyoidc.JwtVerifier.validateSignatureAlgorithm(JwtVerifier.java:98) ~[opendistro_security-1.4.0.0.jar:1.4.0.0]
        at com.amazon.dlic.auth.http.jwt.keybyoidc.JwtVerifier.getInitializedSignatureVerifier(JwtVerifier.java:106) ~[opendistro_security-1.4.0.0.jar:1.4.0.0]
        at com.amazon.dlic.auth.http.jwt.keybyoidc.JwtVerifier.getVerifiedJwtToken(JwtVerifier.java:66) ~[opendistro_security-1.4.0.0.jar:1.4.0.0]
        at com.amazon.dlic.auth.http.jwt.AbstractHTTPJwtAuthenticator.extractCredentials0(AbstractHTTPJwtAuthenticator.java:103) [opendistro_security-1.4.0.0.jar:1.4.0.0]
        at com.amazon.dlic.auth.http.jwt.AbstractHTTPJwtAuthenticator.access$000(AbstractHTTPJwtAuthenticator.java:45) [opendistro_security-1.4.0.0.jar:1.4.0.0]
        at com.amazon.dlic.auth.http.jwt.AbstractHTTPJwtAuthenticator$1.run(AbstractHTTPJwtAuthenticator.java:85) [opendistro_security-1.4.0.0.jar:1.4.0.0]
        at com.amazon.dlic.auth.http.jwt.AbstractHTTPJwtAuthenticator$1.run(AbstractHTTPJwtAuthenticator.java:82) [opendistro_security-1.4.0.0.jar:1.4.0.0]
        at java.security.AccessController.doPrivileged(AccessController.java:312) [?:?]
        at com.amazon.dlic.auth.http.jwt.AbstractHTTPJwtAuthenticator.extractCredentials(AbstractHTTPJwtAuthenticator.java:82) [opendistro_security-1.4.0.0.jar:1.4.0.0]
        at com.amazon.dlic.auth.http.saml.HTTPSamlAuthenticator.extractCredentials(HTTPSamlAuthenticator.java:140) [opendistro_security-1.4.0.0.jar:1.4.0.0]
        at com.amazon.opendistroforelasticsearch.security.auth.BackendRegistry.authenticate(BackendRegistry.java:412) [opendistro_security-1.4.0.0.jar:1.4.0.0]
        at com.amazon.opendistroforelasticsearch.security.filter.OpenDistroSecurityRestFilter.checkAndAuthenticateRequest(OpenDistroSecurityRestFilter.java:146) [opendistro_security-1.4.0.0.jar:1.4.0.0]
        at com.amazon.opendistroforelasticsearch.security.filter.OpenDistroSecurityRestFilter.access$000(OpenDistroSecurityRestFilter.java:63) [opendistro_security-1.4.0.0.jar:1.4.0.0]
        at com.amazon.opendistroforelasticsearch.security.filter.OpenDistroSecurityRestFilter$1.handleRequest(OpenDistroSecurityRestFilter.java:93) [opendistro_security-1.4.0.0.jar:1.4.0.0]
        at org.elasticsearch.rest.RestController.dispatchRequest(RestController.java:222) [elasticsearch-7.4.2.jar:7.4.2]
        at org.elasticsearch.rest.RestController.tryAllHandlers(RestController.java:295) [elasticsearch-7.4.2.jar:7.4.2]
        at org.elasticsearch.rest.RestController.dispatchRequest(RestController.java:166) [elasticsearch-7.4.2.jar:7.4.2]
        at com.amazon.opendistroforelasticsearch.security.ssl.http.netty.ValidatingDispatcher.dispatchRequest(ValidatingDispatcher.java:63) [opendistro_security-1.4.0.0.jar:1.4.0.0]
        at org.elasticsearch.http.AbstractHttpServerTransport.dispatchRequest(AbstractHttpServerTransport.java:322) [elasticsearch-7.4.2.jar:7.4.2]
        at org.elasticsearch.http.AbstractHttpServerTransport.handleIncomingRequest(AbstractHttpServerTransport.java:372) [elasticsearch-7.4.2.jar:7.4.2]
        at org.elasticsearch.http.AbstractHttpServerTransport.incomingRequest(AbstractHttpServerTransport.java:301) [elasticsearch-7.4.2.jar:7.4.2]
        at org.elasticsearch.http.netty4.Netty4HttpRequestHandler.channelRead0(Netty4HttpRequestHandler.java:69) [transport-netty4-client-7.4.2.jar:7.4.2]
        at org.elasticsearch.http.netty4.Netty4HttpRequestHandler.channelRead0(Netty4HttpRequestHandler.java:31) [transport-netty4-client-7.4.2.jar:7.4.2]
        at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:105) [netty-transport-4.1.38.Final.jar:4.1.38.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374) [netty-transport-4.1.38.Final.jar:4.1.38.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360) [netty-transport-4.1.38.Final.jar:4.1.38.Final]
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352) [netty-transport-4.1.38.Final.jar:4.1.38.Final]
        at org.elasticsearch.http.netty4.Netty4HttpPipeliningHandler.channelRead(Netty4HttpPipeliningHandler.java:58) [transport-netty4-client-7.4.2.jar:7.4.2]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374) [netty-transport-4.1.38.Final.jar:4.1.38.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360) [netty-transport-4.1.38.Final.jar:4.1.38.Final]
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352) [netty-transport-4.1.38.Final.jar:4.1.38.Final]
        at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:102) [netty-codec-4.1.38.Final.jar:4.1.38.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374) [netty-transport-4.1.38.Final.jar:4.1.38.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360) [netty-transport-4.1.38.Final.jar:4.1.38.Final]
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352) [netty-transport-4.1.38.Final.jar:4.1.38.Final]
        at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:102) [netty-codec-4.1.38.Final.jar:4.1.38.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374) [netty-transport-4.1.38.Final.jar:4.1.38.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360) [netty-transport-4.1.38.Final.jar:4.1.38.Final]
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352) [netty-transport-4.1.38.Final.jar:4.1.38.Final]
        at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:328) [netty-codec-4.1.38.Final.jar:4.1.38.Final]
        at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:302) [netty-codec-4.1.38.Final.jar:4.1.38.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374) [netty-transport-4.1.38.Final.jar:4.1.38.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360) [netty-transport-4.1.38.Final.jar:4.1.38.Final]
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352) [netty-transport-4.1.38.Final.jar:4.1.38.Final]
        at io.netty.handler.timeout.IdleStateHandler.channelRead(IdleStateHandler.java:287) [netty-handler-4.1.38.Final.jar:4.1.38.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374) [netty-transport-4.1.38.Final.jar:4.1.38.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360) [netty-transport-4.1.38.Final.jar:4.1.38.Final]
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352) [netty-transport-4.1.38.Final.jar:4.1.38.Final]
        at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1475) [netty-handler-4.1.38.Final.jar:4.1.38.Final]
        at io.netty.handler.ssl.SslHandler.decodeJdkCompatible(SslHandler.java:1224) [netty-handler-4.1.38.Final.jar:4.1.38.Final]
        at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1271) [netty-handler-4.1.38.Final.jar:4.1.38.Final]
        at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:505) [netty-codec-4.1.38.Final.jar:4.1.38.Final]
        at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:444) [netty-codec-4.1.38.Final.jar:4.1.38.Final]
        at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:283) [netty-codec-4.1.38.Final.jar:4.1.38.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374) [netty-transport-4.1.38.Final.jar:4.1.38.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360) [netty-transport-4.1.38.Final.jar:4.1.38.Final]
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352) [netty-transport-4.1.38.Final.jar:4.1.38.Final]
        at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1421) [netty-transport-4.1.38.Final.jar:4.1.38.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374) [netty-transport-4.1.38.Final.jar:4.1.38.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360) [netty-transport-4.1.38.Final.jar:4.1.38.Final]
        at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:930) [netty-transport-4.1.38.Final.jar:4.1.38.Final]
        at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163) [netty-transport-4.1.38.Final.jar:4.1.38.Final]
        at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:697) [netty-transport-4.1.38.Final.jar:4.1.38.Final]
        at io.netty.channel.nio.NioEventLoop.processSelectedKeysPlain(NioEventLoop.java:597) [netty-transport-4.1.38.Final.jar:4.1.38.Final]
        at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:551) [netty-transport-4.1.38.Final.jar:4.1.38.Final]
        at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:511) [netty-transport-4.1.38.Final.jar:4.1.38.Final]
        at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:918) [netty-common-4.1.38.Final.jar:4.1.38.Final]
        at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) [netty-common-4.1.38.Final.jar:4.1.38.Final]
        at java.lang.Thread.run(Thread.java:830) [?:?]

Hello,

I’m not a Java specialist. We couldn’t solve the problems with Keycloak and Open Distro.

What’s why we decided to use an Apache reverse proxy in front of Kibana (https://www.mod-auth-openidc.org/).

This is not a really good solution because a double login is necessary (1st Keycloak and 2nd Kibana).

We suspect that a poor DNS solution and inappropriate certificates have caused the problems.

We want to analyze this in near future again, using an actual version of open distro.

I’m afraid this will not solve your problem.

Open Distro is using a tool named Search Guard (https://search-guard.com/ ).

May be you can find examples in a Java / Search Guard environment.

Best regards

Lorenz

thanks llauber… I can take up the support ticket with search guard for might be extra price.

Thanks a lot