elastic / elasticsearch

Free and Open, Distributed, RESTful Search Engine
https://www.elastic.co/products/elasticsearch
Other
69.45k stars 24.58k forks source link

OIDC realm delegate ID Token (JWT) validation #69996

Open albertzaharovits opened 3 years ago

albertzaharovits commented 3 years ago

This is a proposal to convert a JWT ID token (that contains claims) into an Elasticsearch internal Access Token, by using the OIDC realms, but not really enforcing the OIDC protocol flows.

Preamble

The Elasticsearch OIDC realm, with Kibana as the facilitator, implements the OIDC code flow. Kibana is required because the OIDC flow relies on HTTP Redirects. The code flow is designed for Relying Parties that can keep a secret (the rp.client_secret realm secure setting in the keystore). To obtain the JWT ID token, which contains the user claims, Elasticsearch exchanges a code through a secure back-channel with the OP. The code is designed to be un-replay-able and bound to an end user and an RP, and is obtained in the front channel interaction (using the browser), following a successful authentication at the OP.

For this purpose, Elasticsearch exposes two APIs, that the Kibana facilitator calls: one to construct the authentication request to submit to the OP (_security/oidc/prepare), and another one that validates the response, which contains the code, of the aforementioned request (_security/oidc/authenticate).

Implicit flow uses JWTs already

In addition to the code flow, OIDC also standardizes what's called the implicit flow. In the implicit flow, the JWT ID Token is released directly in the front-channel. This is to support serverless Relying Parties (where the client runs in the browser/phone, not on a server). Elasticsearch supports this flow as well: the response to validate by the ES _security/oidc/authenticate call will contain the ID Token instead of the code. The API returns an Elasticsearch internal Access Token.

Therefore there is already a protocol way to exchange JWTs with ES internal Access Tokens. But of course, the protocol must be followed, eg calling the ES prepare API, binding the state parameter to a cookie and validating that on the response, etc...

Proposal

For a more "direct" way to exchange a JWT into an ES token, we could introduce something analogous to the PKI realm delegation. There, we rely on a trusted proxy to perform the authentication as part of the TLS protocol. In the OIDC case, the facilitator actually becomes a full-fledged OIDC RP, and the OIDC realm in ES works in a delegated mode. It trusts that the proxying RP obtained and validated the JWT according to the OIDC flow of choice. Before releasing an access token, the ES OIDC realm, working in a delegated mode (a new realm setting), authenticates (validates signature) and possibly decrypts the JWT and maps the claims to a principal and roles.

Analogous to the POST /_security/delegate_pki there would be a new API and a new cluster privilege to restrict the clients that are trusted in this way.

elasticmachine commented 3 years ago

Pinging @elastic/es-security (Team:Security)

jkakavas commented 3 years ago

Some first thoughts to get the discussion going:

Update

(leaving the above for reference, even though I have answered some of my Qs in my head :) )

I thought about this again this morning and I guess my main concerns where regarding how this is framed and not with the technical solution which I summarized in my mind as:

Advantages
Disadvantages
Open questions

(Always happy to have a chat about his - I just wanted to write down my thoughts and augment my half-baked response from yesterday)

ywangd commented 3 years ago

This solution depends on a facilitator component. I'm not certain if this is actually a disadvantage (compared to a "JWT realm") as I haven't thought through how the JWT realm would work, but I was assuming that we would consume these JWTs as Bearer tokens from an HTTP header and as such the realm would be usable by end users without a facilitator.

I think this is the critical question for the issue. I also had the impression that what users ask for is not partial oidc function, but instead an authentication mechanism that happens to use a JWT as the credentials. With this proposal, the end user will need not only a faciliator to act as RP proxy, but also managing the access/refresh token lifecycle. If I remember correctly, there are users claimed that their system cannot do much other than forward the JWT token in a HTTP header. I think we need to be clear on the exact use case (or cases) that we are trying to cater first before deciding on the approach.

albertzaharovits commented 3 years ago

The question of whether the client has the capacity to call APIs to exchange for ES token credentials is the most important point. If they don't, then this feature is not suitable.