I want to configure opensearch dashboards behind a reverse proxy, that will do the SSL authentication for me

Versions (relevant - OpenSearch/Dashboard/Server OS/Browser):
I checked couple of versions, but let’s stick with the last one I tried: 2.9.0

Describe the issue:
Hello,
I have a Opensearch cluster, that I want to enable SSO for. I have configured apache server to be the reverse proxy for open dashboards (openIdc can use external proxies to fetch the OAuth token).
And when I try to access my Dashboards, I can see that the authentication is done, but somehow the Dashboards still requests user and password from the user.
I thought that mostly, what I need to have is to configure: proxy_auth_domain in opensearch-security/config.yml

Configuration:

opensearch_dashboards.yml:
opensearch.hosts: ["https://opensearch-node1.bosch.org:9200/"]
opensearch.ssl.verificationMode: none
opensearch.username: kibanaserver
opensearch.password: xxxxxxxxxxxxxxxxxx
opensearch.requestHeadersWhitelist: [ "authorization", "securitytenant", "OIDC_access_token", "oidc_clai
m_userroles" ]

opensearch_security.multitenancy.enabled: true
opensearch_security.multitenancy.tenants.preferred: [Private, Global]
opensearch_security.readonly_mode.roles: [kibana_read_only]
#opensearch_security.auth.type: 'proxy'
opensearch_security.auth.multiple_auth_enabled: true
opensearch_security.cookie.secure: false
server.host: '0.0.0.0'

my opensearch-security/config.yml

_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
    authc:
        proxy_auth_domain:
          http_enabled: true
          transport_enabled: true
          order: 0
          http_authenticator:
            type: proxy
            challenge: false
            config:
              user_header: "OIDC_access_token"
              roles_header: "oidc_claim_userroles"
          authentication_backend:
            type: noop
      kerberos_auth_domain:
        http_enabled: false
        transport_enabled: false
        order: 6
        http_authenticator:
          type: kerberos
          challenge: false
          config:
            krb_debug: false
            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
         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
            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:
          type: ldap
          config:
            enable_ssl: false
            enable_start_tls: false
            enable_ssl_client_auth: false
            verify_hostnames: true
            hosts:
            - localhost:8389
            bind_dn: null
            password: null
            userbase: 'ou=people,dc=example,dc=com'
            usersearch: '(sAMAccountName={0})'
            username_attribute: null
    authz:
      roles_from_myldap:
        description: "Authorize via LDAP or Active Directory"
        http_enabled: false
        transport_enabled: false
        authorization_backend:
          type: ldap
          config:
            enable_ssl: false
            enable_start_tls: false
            enable_ssl_client_auth: false
            verify_hostnames: true
            hosts:
            - localhost:8389
            bind_dn: null
            password: null
            rolebase: 'ou=groups,dc=example,dc=com'
            rolesearch: '(member={0})'
            userroleattribute: null
            userrolename: disabled
            rolename: cn
            resolve_nested_roles: true
            userbase: 'ou=people,dc=example,dc=com'
            usersearch: '(uid={0})'
      roles_from_another_ldap:
        description: "Authorize via another Active Directory"
        http_enabled: false
        transport_enabled: false
        authorization_backend:
          type: ldap

Relevant Logs or Screenshots:

@cyprian.zawadzki Just to clarify. Are you looking to have OIDC authentication configured in OpenSearch Dashboards that is behind a reverse proxy?

Not exactly.
I have reverse proxy, that is apache server, that has openIdc plugin installed (and configured). Therefore Apache server will be acting as a reverse proxy for Opensearch Dashboards, and will also authenticate the user.
I can see in the logs, that it passes all the necessary headers, at least i thought that it does that.

The reason for that I want to do it this way is:

  • I’m located behind a proxy, and OpenSearch dashboards cannot use it to fetch OAuth token
  • I’m more confident with apache server than nginx.
  • and the last but not least, I do not want to manage the user’s list/base

@cyprian.zawadzki Did you follow the OpenSearch Dashboards configuration?

yes, I even modified my files:
so my opensearch-dashboards.yml looks like this:

opensearch.hosts: ["https://opensearch-node1:9200/"]
opensearch.ssl.verificationMode: none
opensearch.username: kibanaserver
opensearch.password: edited_out
opensearch.requestHeadersWhitelist: [authorization, securitytenant, OIDC_access_token, oidc_claim_upn, oidc_claim_roles, x-forwarded-for]

opensearch_security.multitenancy.enabled: true
opensearch_security.multitenancy.tenants.preferred: [Private, Global]
opensearch_security.readonly_mode.roles: [kibana_read_only]
opensearch_security.auth.type: "basicauth"


opensearch_security.cookie.secure: false
server.host: '0.0.0.0'

and my config.yml looks like this:






_meta:
  type: "config"
  config_version: 2

config:
  dynamic:
    http:
      anonymous_auth_enabled: true
      xff:
        enabled: true
        internalProxies: '.*' # regex pattern
        remoteIpHeader:  'x-forwarded-for'
    authc:
        proxy_auth_domain:
          http_enabled: true
          transport_enabled: true
          order: 0
          http_authenticator:
            type: proxy
            challenge: false
            config:
              user_header: "oidc_claim_upn"
              roles_header: "oidc_claim_userroles"
          authentication_backend:
            type: noop
      kerberos_auth_domain:
        http_enabled: false
        transport_enabled: false
        order: 6
        http_authenticator:
          type: kerberos
          challenge: false
          config:
            krb_debug: false
            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


      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
            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:
          type: ldap
          config:
            enable_ssl: false
            enable_start_tls: false
            enable_ssl_client_auth: false
            verify_hostnames: true
            hosts:
            - localhost:8389
            bind_dn: null
            password: null
            userbase: 'ou=people,dc=example,dc=com'
            usersearch: '(sAMAccountName={0})'
            username_attribute: null
    authz:
      roles_from_myldap:
        description: "Authorize via LDAP or Active Directory"
        http_enabled: false
        transport_enabled: false
        authorization_backend:
          type: ldap
          config:
            enable_ssl: false
            enable_start_tls: false
            enable_ssl_client_auth: false
            verify_hostnames: true
            hosts:
            - localhost:8389
            bind_dn: null
            password: null
            rolebase: 'ou=groups,dc=example,dc=com'
            rolesearch: '(member={0})'
            userroleattribute: null
            userrolename: disabled
            rolename: cn
            resolve_nested_roles: true
            userbase: 'ou=people,dc=example,dc=com'
            usersearch: '(uid={0})'
      roles_from_another_ldap:
        description: "Authorize via another Active Directory"
        http_enabled: false
        transport_enabled: false
        authorization_backend:
          type: ldap

when I change opensearch_security.auth.type: “basicauth”
to
opensearch_security.auth.type: “proxy”
I get:
{“statusCode”:401,“error”:“Unauthorized”,“message”:“Unauthorized”}

I see in the dashboards logs, that it gets the headers (edited out some values, but there were values there):
OSNodes_opensearch-dashboards.1.enegiz982iiu@si0vm08510 | {“type”:“response”,“@timestamp”:“2023-08-25T13:33:28Z”,“tags”:,“pid”:1,“method”:“get”,“statusCode”:401,“req”:{“url”:“/favicon.ico”,“method”:“get”,“headers”:{“host”:“bambarasz.bosch.com”,“sec-ch-ua”:“"Not/A)Brand";v="99", "Microsoft Edge";v="115", "Chromium";v="115"”,“dnt”:“1”,“sec-ch-ua-mobile”:“?0”,“user-agent”:“Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36 Edg/115.0.1901.200”,“sec-ch-ua-platform”:“"Windows"”,“accept”:“image/webp,image/apng,image/svg+xml,image/,/*;q=0.8”,“sec-fetch-site”:“same-origin”,“sec-fetch-mode”:“no-cors”,
“sec-fetch-dest”:“image”,“referer”:“https://bambarasz.bosch.com/",“accept-encoding”:"gzip, deflate, br”,“accept-language”:“en-US,en;q=0.9”,“oidc_claim_aud”:“edited_out”,“oidc_claim_iss”:“https://login.microsoftonline.com/edited_out/v2.0",“oidc_claim_iat”:"edited out”,“oidc_claim_nbf”:“edited out”,“oidc_claim_exp”:“edited out”,“oidc_claim_acct”:“0”,“oidc_claim_auth_time”:“edited out”,“oidc_claim_email”:“Cyedited out”,“oidc_claim_groups”:“edited out”,“oidc_claim_ipaddr”:“edited out”,“oidc_claim_login_hint”:“O.edited out==”,“oidc_claim_name”:“edited out”,“oidc_claim_nonce”:“edited out”,“oidc_claim_oid”:“edited out”,“oidc_claim_preferred_username”:“edited out”,
“oidc_claim_rh”:“edited out.”,“oidc_claim_roles”:“CYEODAdmin,CYEODUser”,“oidc_claim_sub”:“edited out”,“oidc_claim_tid”:“0edited out”,“oidc_claim_upn”:“myusername edited out”,“oidc_claim_uti”:“edited out”,“oidc_claim_ver”:“2.0”,
“oidc_claim_wids”:“edited out",“oidc_claim_emailadress”:"Cyprian.Zawadzki@pl.bosch.com”,“oidc_claim_userroles”:“CYEODAdmin,CYEODUser”,“oidc_access_token”:“edited out.”,
“oidc_access_token_expires”:“edited out”,“x-forwarded-host”:“(null), bambarasz”,“x-forwarded-for”:“10.0.16.111”,“x-forwarded-server”:“bambarasz”,“connection”:“Keep-Alive”},
“remoteAddress”:“10.0.15.181”,“userAgent”:“Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36 Edg/115.0.1901.200”,
“referer”:“https://bambarasz/"},“res”:{“statusCode”:401,“responseTime”:4,“contentLength”:9},“message”:"GET /favicon.ico 401 4ms - 9.0B”}

one more thing: in my roles mapping I have:


all_access:
  reserved: false
  backend_roles:
  - "admin"
  - "CYEODAdmin"

  description: "Maps admin to all_access"

and


kibana_user:
  reserved: false
  backend_roles:
  - "kibanauser"
  - "CYEODUser"
  description: "Maps kibanauser to kibana_user"


so the roles requested should be there

@cyprian.zawadzki Just a quick question about your config.yml
I see that proxy_auth_domain indent is different than other authentication domains.
It should be at the same level as kerberos_auth_domain:, basic_internal_auth_domain: etc.

Is that just a mistake in pasting?

Could you run the following command and compare the configs from the cluster with that config.yml file?

curl --insecure -u admin:admin -XGET https://<OpenSearch_node_FQDN_or_IP>:9200/_plugins/_security/api/securityconfig?pretty

That was accidental, I corrected that, so my config.yml looks now like this:


_meta:
  type: "config"
  config_version: 2

config:
  dynamic:
    http:
      anonymous_auth_enabled: true
      xff:
        enabled: true
        internalProxies: '.*' # regex pattern
        remoteIpHeader:  'x-forwarded-for'
    authc:
      proxy_auth_domain:
        http_enabled: true
        transport_enabled: true
        order: 0
        http_authenticator:
          type: proxy
          challenge: false
          config:
            user_header: "oidc_claim_upn"
            roles_header: "oidc_claim_userroles"
        authentication_backend:
          type: noop
      kerberos_auth_domain:
        http_enabled: false
        transport_enabled: false
        order: 6
        http_authenticator:
          type: kerberos
          challenge: false
          config:
            krb_debug: false
            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


      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
            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:
          type: ldap
          config:
            enable_ssl: false
            enable_start_tls: false
            enable_ssl_client_auth: false
            verify_hostnames: true
            hosts:
            - localhost:8389
            bind_dn: null
            password: null
            userbase: 'ou=people,dc=example,dc=com'
            usersearch: '(sAMAccountName={0})'
            username_attribute: null
    authz:
      roles_from_myldap:
        description: "Authorize via LDAP or Active Directory"
        http_enabled: false
        transport_enabled: false
        authorization_backend:
          type: ldap
          config:
            enable_ssl: false
            enable_start_tls: false
            enable_ssl_client_auth: false
            verify_hostnames: true
            hosts:
            - localhost:8389
            bind_dn: null
            password: null
            rolebase: 'ou=groups,dc=example,dc=com'
            rolesearch: '(member={0})'
            userroleattribute: null
            userrolename: disabled
            rolename: cn
            resolve_nested_roles: true
            userbase: 'ou=people,dc=example,dc=com'
            usersearch: '(uid={0})'
      roles_from_another_ldap:
        description: "Authorize via another Active Directory"
        http_enabled: false
        transport_enabled: false
        authorization_backend:
          type: ldap

As to checking the security context, it is strange, but I get:

{
  "status" : "FORBIDDEN",
  "message" : "No permission to access REST API: Role based access not enabled.. No client TLS certificate found in request"
}

@cyprian.zawadzki Could you share your opensearch.yml file?

Also, please run the same API call with admin certificates instead of the internal user. If you’re using demo configuration, then kirk.pem and kirk-key.pem are the ones you should use.

curl --insecure --cert kirk.pem --key kirk-key.pem -XGET https://<OpenSearch_node_FQDN_or_IP>:9200/_plugins/_security/api/securityconfig?pretty
{
  "config" : {
    "dynamic" : {
      "filtered_alias_mode" : "warn",
      "disable_rest_auth" : false,
      "disable_intertransport_auth" : false,
      "respect_request_indices_options" : false,
      "kibana" : {
        "multitenancy_enabled" : true,
        "private_tenant_enabled" : true,
        "default_tenant" : "",
        "server_username" : "kibanaserver",
        "index" : ".kibana"
      },
      "http" : {
        "anonymous_auth_enabled" : false,
        "xff" : {
          "enabled" : false,
          "internalProxies" : "192\\.168\\.0\\.10|192\\.168\\.0\\.11",
          "remoteIpHeader" : "X-Forwarded-For"
        }
      },
      "authc" : {
        "jwt_auth_domain" : {
          "http_enabled" : false,
          "transport_enabled" : false,
          "order" : 0,
          "http_authenticator" : {
            "challenge" : false,
            "type" : "jwt",
            "config" : {
              "signing_key" : "base64 encoded HMAC key or public RSA/ECDSA pem key",
              "jwt_header" : "Authorization"
            }
          },
          "authentication_backend" : {
            "type" : "noop",
            "config" : { }
          },
          "description" : "Authenticate via Json Web Token"
        },
        "ldap" : {
          "http_enabled" : false,
          "transport_enabled" : false,
          "order" : 5,
          "http_authenticator" : {
            "challenge" : false,
            "type" : "basic",
            "config" : { }
          },
          "authentication_backend" : {
            "type" : "ldap",
            "config" : {
              "enable_ssl" : false,
              "enable_start_tls" : false,
              "enable_ssl_client_auth" : false,
              "verify_hostnames" : true,
              "hosts" : [
                "localhost:8389"
              ],
              "userbase" : "ou=people,dc=example,dc=com",
              "usersearch" : "(sAMAccountName={0})"
            }
          },
          "description" : "Authenticate via LDAP or Active Directory"
        },
        "basic_internal_auth_domain" : {
          "http_enabled" : true,
          "transport_enabled" : true,
          "order" : 4,
          "http_authenticator" : {
            "challenge" : true,
            "type" : "basic",
            "config" : { }
          },
          "authentication_backend" : {
            "type" : "intern",
            "config" : { }
          },
          "description" : "Authenticate via HTTP Basic against internal users database"
        },
        "proxy_auth_domain" : {
          "http_enabled" : false,
          "transport_enabled" : false,
          "order" : 3,
          "http_authenticator" : {
            "challenge" : false,
            "type" : "proxy",
            "config" : {
              "user_header" : "x-proxy-user",
              "roles_header" : "x-proxy-roles"
            }
          },
          "authentication_backend" : {
            "type" : "noop",
            "config" : { }
          },
          "description" : "Authenticate via proxy"
        },
        "clientcert_auth_domain" : {
          "http_enabled" : false,
          "transport_enabled" : false,
          "order" : 2,
          "http_authenticator" : {
            "challenge" : false,
            "type" : "clientcert",
            "config" : {
              "username_attribute" : "cn"
            }
          },
          "authentication_backend" : {
            "type" : "noop",
            "config" : { }
          },
          "description" : "Authenticate via SSL client certificates"
        },
        "kerberos_auth_domain" : {
          "http_enabled" : false,
          "transport_enabled" : false,
          "order" : 6,
          "http_authenticator" : {
            "challenge" : true,
            "type" : "kerberos",
            "config" : {
              "krb_debug" : false,
              "strip_realm_from_principal" : true
            }
          },
          "authentication_backend" : {
            "type" : "noop",
            "config" : { }
          }
        }
      },
      "authz" : {
        "roles_from_another_ldap" : {
          "http_enabled" : false,
          "transport_enabled" : false,
          "authorization_backend" : {
            "type" : "ldap",
            "config" : { }
          },
          "description" : "Authorize via another Active Directory"
        },
        "roles_from_myldap" : {
          "http_enabled" : false,
          "transport_enabled" : false,
          "authorization_backend" : {
            "type" : "ldap",
            "config" : {
              "enable_ssl" : false,
              "enable_start_tls" : false,
              "enable_ssl_client_auth" : false,
              "verify_hostnames" : true,
              "hosts" : [
                "localhost:8389"
              ],
              "rolebase" : "ou=groups,dc=example,dc=com",
              "rolesearch" : "(member={0})",
              "userrolename" : "disabled",
              "rolename" : "cn",
              "resolve_nested_roles" : true,
              "userbase" : "ou=people,dc=example,dc=com",
              "usersearch" : "(uid={0})"
            }
          },
          "description" : "Authorize via LDAP or Active Directory"
        }
      },
      "auth_failure_listeners" : { },
      "do_not_fail_on_forbidden" : false,
      "multi_rolespan_enabled" : true,
      "hosts_resolver_mode" : "ip-only",
      "do_not_fail_on_forbidden_empty" : false
    }
  }
}

my opensearch.yml files look like this:

cluster.name: cye
node.name: opensearch-node1.org
network.host: 0.0.0.0
transport.host: "0.0.0.0"
transport.tcp.port: 9300
http.host: "0.0.0.0"
http.port: 9200


#transport.tcp.port: 9200
cluster.initial_master_nodes: opensearch-node1.bosch.org,opensearch-node2.org
discovery.seed_hosts: ["opensearch-node1.org", "opensearch-node2.bosch.org"]
plugins.security.ssl.transport.enabled_protocols:
  - "TLSv1"
  - "TLSv1.1"
  - "TLSv1.2"
plugins.security.ssl.transport.pemcert_filepath: node1.pem
plugins.security.ssl.transport.pemkey_filepath: node1-key.pem
plugins.security.ssl.transport.pemtrustedcas_filepath: root-ca.pem
plugins.security.ssl.transport.enforce_hostname_verification: false
plugins.security.ssl.transport.resolve_hostname: true
plugins.security.ssl.transport.enabled: true
plugins.security.ssl.http.enabled: true
plugins.security.ssl.http.pemcert_filepath: node1.pem
plugins.security.ssl.http.pemkey_filepath: node1-key.pem
plugins.security.ssl.http.pemtrustedcas_filepath: root-ca.pem
plugins.security.allow_unsafe_democertificates: false
plugins.security.allow_default_init_securityindex: true
plugins.security.authcz.admin_dn:
  - /.*/
plugins.security.nodes_dn:
#edited out
  - /.*/

Now i get:

{
    "statusCode": 401,
    "error": "Unauthorized",
    "message": "Unauthorized"
}

In opensearch dashboards. I tried to run something like this:

[opensearch-dashboards@opensearch-dashboards ~]$ curl http://opensearch-dashboards:5601 -v -H "claim_email: dupa@test" -H "claim_roles: CYEODAdmin"
*   Trying 10.0.15.216:5601...
* Connected to opensearch-dashboards (10.0.15.216) port 5601 (#0)
> GET / HTTP/1.1
> Host: opensearch-dashboards:5601
> User-Agent: curl/8.0.1
> Accept: */*
> claim_email: dupa@test
> claim_roles: CYEODAdmin
>
< HTTP/1.1 401 Unauthorized
< osd-name: opensearch-dashboards.bosch.org
< content-type: application/json; charset=utf-8
< cache-control: private, no-cache, no-store, must-revalidate
< set-cookie: security_authentication=; Max-Age=0; Expires=Thu, 01 Jan 1970 00:00:00 GMT; Secure; HttpOnly; Path=/
< content-length: 66
< Date: Tue, 29 Aug 2023 11:48:58 GMT
< Connection: keep-alive
< Keep-Alive: timeout=120
<
* Connection #0 to host opensearch-dashboards left intact
{"statusCode":401,"error":"Unauthorized","message":"Unauthorized"}[opensearch-dashboards@opensearch-dashboards ~]$

I noticed one strange thing:
in the config.yml I have following content

   http:
      anonymous_auth_enabled: false
      xff:
        enabled: true
        internalProxies: '.*' # 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

but the rest api returns:

      "http" : {
        "anonymous_auth_enabled" : false,
        "xff" : {
          "enabled" : false,
          "internalProxies" : "192\\.168\\.0\\.10|192\\.168\\.0\\.11",
          "remoteIpHeader" : "X-Forwarded-For"
        }
      }

@cyprian.zawadzki That means your config.yml hasn’t been applied to the cluster.

How did you deploy the cluster?

Try updating the config with securitydamin.sh script.

As per documentation:

Running securityadmin.sh overwrites one or more portions of the .opendistro_security index. Run it with extreme care to avoid losing your existing resources.

To avoid this situation, back up your current configuration before making changes and re-running the script

after some struggle (i noticed that I was not allowed to modify the roles.yml for some reason. It is good I do not really need to modify it) my security plugin reports this:

{
  "config" : {
    "dynamic" : {
      "filtered_alias_mode" : "warn",
      "disable_rest_auth" : false,
      "disable_intertransport_auth" : false,
      "respect_request_indices_options" : false,
      "kibana" : {
        "multitenancy_enabled" : true,
        "server_username" : "kibanaserver",
        "index" : ".kibana"
      },
      "http" : {
        "anonymous_auth_enabled" : true,
        "xff" : {
          "enabled" : true,
          "internalProxies" : ".*",
          "remoteIpHeader" : "x-forwarded-for"
        }
      },
      "authc" : {
        "jwt_auth_domain" : {
          "http_enabled" : false,
          "transport_enabled" : false,
          "order" : 0,
          "http_authenticator" : {
            "challenge" : false,
            "type" : "jwt",
            "config" : {
              "signing_key" : "base64 encoded HMAC key or public RSA/ECDSA pem key",
              "jwt_header" : "Authorization"
            }
          },
          "authentication_backend" : {
            "type" : "noop",
            "config" : { }
          },
          "description" : "Authenticate via Json Web Token"
        },
        "ldap" : {
          "http_enabled" : false,
          "transport_enabled" : false,
          "order" : 5,
          "http_authenticator" : {
            "challenge" : false,
            "type" : "basic",
            "config" : { }
          },
          "authentication_backend" : {
            "type" : "ldap",
            "config" : {
              "enable_ssl" : false,
              "enable_start_tls" : false,
              "enable_ssl_client_auth" : false,
              "verify_hostnames" : true,
              "hosts" : [
                "localhost:8389"
              ],
              "userbase" : "ou=people,dc=example,dc=com",
              "usersearch" : "(sAMAccountName={0})"
            }
          },
          "description" : "Authenticate via LDAP or Active Directory"
        },
        "basic_internal_auth_domain" : {
          "http_enabled" : true,
          "transport_enabled" : true,
          "order" : 4,
          "http_authenticator" : {
            "challenge" : true,
            "type" : "basic",
            "config" : { }
          },
          "authentication_backend" : {
            "type" : "intern",
            "config" : { }
          },
          "description" : "Authenticate via HTTP Basic against internal users database"
        },
        "proxy_auth_domain" : {
          "http_enabled" : true,
          "transport_enabled" : true,
          "order" : 0,
          "http_authenticator" : {
            "challenge" : false,
            "type" : "proxy",
            "config" : {
              "user_header" : "oidc_claim_email",
              "roles_header" : "oidc_claim_roles"
            }
          },
          "authentication_backend" : {
            "type" : "noop",
            "config" : { }
          },
          "description" : "Authenticate via proxy"
        },
        "clientcert_auth_domain" : {
          "http_enabled" : false,
          "transport_enabled" : false,
          "order" : 2,
          "http_authenticator" : {
            "challenge" : false,
            "type" : "clientcert",
            "config" : {
              "username_attribute" : "cn"
            }
          },
          "authentication_backend" : {
            "type" : "noop",
            "config" : { }
          },
          "description" : "Authenticate via SSL client certificates"
        },
        "kerberos_auth_domain" : {
          "http_enabled" : false,
          "transport_enabled" : false,
          "order" : 6,
          "http_authenticator" : {
            "challenge" : true,
            "type" : "kerberos",
            "config" : {
              "krb_debug" : false,
              "strip_realm_from_principal" : true
            }
          },
          "authentication_backend" : {
            "type" : "noop",
            "config" : { }
          }
        }
      },
      "authz" : {
        "roles_from_another_ldap" : {
          "http_enabled" : false,
          "transport_enabled" : false,
          "authorization_backend" : {
            "type" : "ldap",
            "config" : { }
          },
          "description" : "Authorize via another Active Directory"
        },
        "roles_from_myldap" : {
          "http_enabled" : false,
          "transport_enabled" : false,
          "authorization_backend" : {
            "type" : "ldap",
            "config" : {
              "enable_ssl" : false,
              "enable_start_tls" : false,
              "enable_ssl_client_auth" : false,
              "verify_hostnames" : true,
              "hosts" : [
                "localhost:8389"
              ],
              "rolebase" : "ou=groups,dc=example,dc=com",
              "rolesearch" : "(member={0})",
              "userrolename" : "disabled",
              "rolename" : "cn",
              "resolve_nested_roles" : true,
              "userbase" : "ou=people,dc=example,dc=com",
              "usersearch" : "(uid={0})"
            }
          },
          "description" : "Authorize via LDAP or Active Directory"
        }
      },
      "auth_failure_listeners" : { },
      "do_not_fail_on_forbidden" : false,
      "multi_rolespan_enabled" : true,
      "hosts_resolver_mode" : "ip-only",
      "do_not_fail_on_forbidden_empty" : false
    }
  }
}

my roles mapping looks like this:

{
  "manage_snapshots" : {
    "hosts" : [ ],
    "users" : [ ],
    "reserved" : false,
    "hidden" : false,
    "backend_roles" : [
      "snapshotrestore"
    ],
    "and_backend_roles" : [ ]
  },
  "logstash" : {
    "hosts" : [ ],
    "users" : [ ],
    "reserved" : false,
    "hidden" : false,
    "backend_roles" : [
      "logstash"
    ],
    "and_backend_roles" : [ ]
  },
  "own_index" : {
    "hosts" : [ ],
    "users" : [
      "*"
    ],
    "reserved" : false,
    "hidden" : false,
    "backend_roles" : [ ],
    "and_backend_roles" : [ ],
    "description" : "Allow full access to an index named like the username"
  },
  "kibana_user" : {
    "hosts" : [ ],
    "users" : [ ],
    "reserved" : false,
    "hidden" : false,
    "backend_roles" : [
      "kibanauser",
      "CYEODUser"
    ],
    "and_backend_roles" : [ ],
    "description" : "Maps kibanauser to kibana_user"
  },
  "all_access" : {
    "hosts" : [ ],
    "users" : [ ],
    "reserved" : false,
    "hidden" : false,
    "backend_roles" : [
      "admin",
      "CYEODAdmin"
    ],
    "and_backend_roles" : [ ],
    "description" : "Maps admin to all_access"
  },
  "readall" : {
    "hosts" : [ ],
    "users" : [ ],
    "reserved" : false,
    "hidden" : false,
    "backend_roles" : [
      "readall",
      "CYEODUser"
    ],
    "and_backend_roles" : [ ]
  },
  "kibana_server" : {
    "hosts" : [ ],
    "users" : [
      "kibanaserver"
    ],
    "reserved" : true,
    "hidden" : false,
    "backend_roles" : [ ],
    "and_backend_roles" : [ ]
  }
}

and the opensearch dashboards in the logs reports the headers:
,“oidc_claim_roles”:“CYEODAdmin,CYEODUser”
and
,“oidc_claim_emailadress”:“Cyprian.Zawadzki@myorg”

It seems I forgot to setup one thing in the opensearch dashboards:

You must also enable the authentication type in opensearch_dashboards.yml:

opensearch_security.auth.type: "proxy"
opensearch_security.proxycache.user_header: "x-proxy-user"
opensearch_security.proxycache.roles_header: "x-proxy-roles"

Now I have working SSO on my cluster, thanks for your patience and help.

1 Like