Kibana ECK OIDC with DEX

Hi,

we configured Elastic Cloud on Kubernetes (version 1.1.2) on our own Bare Metal Kubernetes Stack.

We set up Elasticsearch (version 7.8.0) with an OpenID Connect "oidc" realm with DEX as provider. We called the realm "dex":

[...]
        security:
          authc:
            token.enabled: true
            realms:
              oidc:
                dex:
                  order: 0
                  op:
                    issuer: "https://dex.test/dex"
                    authorization_endpoint: "https://dex.test/dex/auth"
                    token_endpoint: "https://dex.test/dex/token"
                    jwkset_path: "https://dex.test/dex/keys"
                    userinfo_endpoint: "https://dex.test/dex/userinfo"
                  rp:
                    # The "rp.client_secret" is injected into keystore from secret.
                    client_id: "kibana"
                    redirect_uri: "https://ip removed:443/api/security/v1/oidc/callback"
                    response_type: code
                    signature_algorithm: RS256
                    requested_scopes:
                    - groups
                    - openid
                    - profile
                    - email
                    - federated:id
                  claims:
                    principal: name
                    groups: groups
                    mail: email

To make Kibana (version 7.8.0) use this OpenId Connect realm we added to the Kibana config:

    xpack.security.authc.providers:
      oidc.oidc1:
        order: 0
        realm: "dex"
      # Basic Access is required e.g. to utilize the Kibana API for automated shard allocation with elastic user.
      basic.basic1:
        order: 1

We experience the following issue:

  • Kibana correctly shows the login selections: "Login with oidc/oidc1" and "Login with Elasticsearch" as expected
  • Choosing "Log in with oidc/oidc1" redirects to our oidc provider. Completing the login there results in being redirected to Kibana as expected.
  • But: Kibana then redirects again to the oidc provider instead of considering the succeeded auth and forward to the Kibana GUI.

We received the following logs from Kibana:

    {"type":"log","@timestamp":"2020-07-17T15:06:28Z","tags":"debug","plugins","security","oidc","oidc1"],"pid":6,"message":"Trying to authenticate via state."}
    {"type":"log","@timestamp":"2020-07-17T15:06:28Z","tags":["debug","plugins","security","oidc","oidc1"],"pid":6,"message":"Elasticsearch access token is not  found in state."}
    {"type":"log","@timestamp":"2020-07-17T15:06:28Z","tags":["debug","plugins","security","oidc","oidc1"],"pid":6,"message":"Trying to initiate OpenID Connect authentication."}
    {"type":"log","@timestamp":"2020-07-17T15:06:28Z","tags":["debug","plugins","security","oidc","oidc1"],"pid":6,"message":"Redirecting to OpenID Connect Provider with authentication request."}
    {"type":"response","@timestamp":"2020-07-17T15:06:28Z","tags":[],"pid":6,"method":"get","statusCode":302,"req":{"url":"/api/security/v1/oidc/callback? code=sdnjxcqizxl73ffik46vmsvvu&state=gtXhZLWuN1p_Dljz9VZSGVCfBiu61MzTuMYkxdSsKrQ","method":"get","headers":{"host":"ip removed","user-agent":"Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0","accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8","accept-language":"en-US,en;q=0.5","accept-encoding":"gzip, deflate, br","referer":"https://dex.test/","dnt":"1","connection":"keep-alive","upgrade-insecure-requests":"1"},"remoteAddress":"ip removed","userAgent":"ip removed","referer":"https://dex.test"},"res":{"statusCode":302,"responseTime":11,"contentLength":9},"message":"GET /api/security/v1/oidc/callback?code=sdnjxcqizxl73ff3k46vmsvvu&state=gtXhZLWuN1p_Dljz9VZSGVCfBiu61MzTuMYkxdSsKrQ 302 11ms - 9.0B"}

In the Elasticsearch log there is literally nothing(!) regarding this oidc login. Even with enabled debug/ trace logging there is no interaction betwen Kibana and Elasticsearch while the login happens.

We expect Elasticsearch to issue an Access Token or something.

Any idea how to let Kibana/ Elasticsearch consider the succeeded OpenID Connect auth and stop forwarding to the oidc provider again and again?

Help is really appreciated!

Thanks,
Tobias

I think the redirect_uri is wrong, please try "https://ip removed:443/api/security/oidc/callback" (note it is without the v1 part)

Thanks a lot, this helped.

Now we get

401 "Unauthorized"

	"[security_exception] unable to authenticate user [<OIDC Token>] for action [cluster:admin/xpack/security/oidc/authenticate], with { header={ WWW-Authenticate={ 0=\"Bearer realm=\\\"security\\\"\" & 1=\"ApiKey\" & 2=\"Basic realm=\\\"security\\\" charset=\\\"UTF-8\\\"\" } } }"

Without logs it's hard to tell where it went wrong. Could you please turn on trace logs for oidc:

PUT _cluster/settings
{"transient":{"logger.org.elasticsearch.xpack.security.authc.oidc":"trace"}}

and share the logs for analysis?

Elasticsearch log:

{"type":"log","@timestamp":"2020-07-20T14:11:27Z","tags":["debug","plugins","security","oidc","dex"],"pid":6,"message":"Trying to perform a login."}
{"type":"log","@timestamp":"2020-07-20T14:11:27Z","tags":["debug","plugins","security","oidc","dex"],"pid":6,"message":"OpenID Connect Authorization Code Authentication flow is used."}
{"type":"log","@timestamp":"2020-07-20T14:11:27Z","tags":["debug","plugins","security","oidc","dex"],"pid":6,"message":"Failed to authenticate request via OpenID Connect: [security_exception] unable to a
uthenticate user [<OIDC Token>] for action [cluster:admin/xpack/security/oidc/authenticate], with { header={ WWW-Authenticate={ 0=\"Bearer realm=\\\"security\\\"\" & 1=\"ApiKey\" & 2=\"Basic realm=\\\"se
curity\\\" charset=\\\"UTF-8\\\"\" } } }"}

We realize the error message but the client_secret in the vault equals the one that is expected.

We inject the password for the OIDC client with Ansible via K8s secret as required by ECK like this:

---
apiVersion: v1
kind: Secret
metadata:
  name: es-oicd-client-secret
  namespace: elastic-system
type: Opaque
data:
  xpack.security.authc.realms.oidc.dex.rp.client_secret: "{{ vault.es.oidc.client_secret }}"

Verifying the password is injected correctly into elasticsearch:

[root@dwp-test-es-default-0 bin]# ./elasticsearch-keystore list
keystore.seed
xpack.security.authc.realms.oidc.dex.rp.client_secret

Is this password key correct?

The key was correct but the base 64 endoding was missing. The correct string is:

  xpack.security.authc.realms.oidc.dex.rp.client_secret: "{{ vault.es.oidc.client_secret | string | b64encode }}"

The login succeeded but we need to extract the DN from "federated_claim" field "user_id".

{
  "type": "server",
  "timestamp": "2020-07-20T15:35:38,047Z",
  "level": "TRACE",
  "component": "o.e.x.s.a.o.OpenIdConnectAuthenticator",
  "cluster.name": "test",
  "node.name": "test-es-default-0",
  "message": "Successfully retrieved user information: [{\"at_hash\":\"removed\",\"federated_claims\":{\"user_id\":\"cn=achim.admin,ou=People,dc=removed,dc=de\",\"connector_id\":\"dwp_ldap_openldap\"},\"sub\":\"removed\",\"aud\":\"kibana\",\"email_verified\":true,\"iss\":\"https:\\/\\/dex.test.fi-ts.io\\/dex\",\"name\":\"test000\",\"groups\":[\"testsecu\",\"dwpstwpdir\",\"k8s_kaas-admin\",\"test_kaas-all-all-admin\",\"test_prmt-all-all-admin\",\"test_k8s-test-all-clusteradmin\",\"test_k8s-qa$poc-all-clusteradmin\",\"test_k8s-dwp$poc-all-clusteradmin\",\"test_k8s-prod$poc-all-clusteradmin\"],\"exp\":1595302537,\"iat\":1595259337,\"nonce\":\"removed\",\"email\":\"achim.admin@removed\"}]",
}

What would be the correct syntax to read input federated_claims->user_id into claims.dn?

                claims:
                    principal: name
                    groups: groups
                    mail: email
                    dn: federated_claims.user_id # What is the syntax required here?

P.S. The encoded JWT token structure:

# {
#   "iss": "https://dex.test",
#   "sub": "test",
#   "aud": "auth-go-cli",
#   "exp": 1594428593,
#   "iat": 1594385393,
#   "at_hash": "test",
#   "email": "achim.admin@test.de",
#   "email_verified": true,
#   "groups": [
#     "k8s_kaas-admin",
#   ],
#   "name": "test000",
#   "federated_claims": {
#     "connector_id": "test_ldap_openldap",
#     "user_id": "cn=achim.admin,ou=People,dc=test,dc=de"
#   }
# }

What would be the correct syntax to read input federated_claims->user_id into claims.dn ?

It is currently impossible to map nested fields to claims. I think it is a reasonable thing to ask. I'll check with the team and get back to you.

Hi @Yang_Wang,

do you have already any kind of feedback?

Thanks!

Hi Tobias,

Sorry for the delay. I have talked to the team and it turns out we don't currently support mapping claims that is type of JSON object. The currently supported ones are String, Number, Boolean or arrays of them. I have opened an issue for this. But I don't have any timeline on when this can be resolved.

In the meantime, the alternatives would be asking if your OP can return the claims in a slightly different format, e.g. elevate user_id to a top level field, or mapping user roles based on a different attribute. Thanks!