Skip to content

JWT support #72060

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
tvernum opened this issue Apr 22, 2021 · 18 comments
Closed

JWT support #72060

tvernum opened this issue Apr 22, 2021 · 18 comments
Labels
>enhancement :Security/Authentication Logging in, Usernames/passwords, Realms (Native/LDAP/AD/SAML/PKI/etc) Team:Security Meta label for security team team-discuss

Comments

@tvernum
Copy link
Contributor

tvernum commented Apr 22, 2021

Overview

We would like to offer some form of support for JSON Web Tokens in Elasticsearch Security.

JWTs are a JSON representation of security claims, typically (in practice, universally) about a User (where the term "user" covers any concept of identity, include systems).

JWTs are frequently used as a means of passing a representation of a user's identity between layers or services in an application. For example, a micro services based architecture may authenticate a user at the periphery (e.g on the server side of a web application), and then use JWT as the container for attaching the authenticated user's identity to subsequent service calls. Encapsulating the user's claims in a JWT avoids the need for each service to connect to a central identity store (which may not exist), and the use of JWS provides some degree of security between the layers, and reduces1 the extent to which each service must trust the caller.

JWTs can also be the basis for a distributed authentication protocol - OpenID Connect uses JWTs as the structure in which claims pass from the authentication service to the relying party.

However, JWTs are not, by default, an authentication protocol. They are simply a structure for representing (usually verifiable) claims about an entity. Possession of a JWT does not, on its own, imply that the holder is the user in question, any more than a certified copy of a birth certificate proves that the holder is the person named on that certificate.
This is not simply a theoretical issue - OAuth2 is a JWT based authorization protocol, that is explicitly not an authentication protocol, and treating OAuth JWTs as proof of identity (rather than a means of access) has led to security vulnerabilities in other applications.

That said, there is wide spread use of JWT as the underlying structure of a Bearer Tokens within OAuth and more generally. This is not inherently bad. Elasticsearch Security supports Bearer Tokens that are not implemented using JWT, but could have been - the design and implementation of Elasticsearch's access tokens would not have been compromised if we have elected to build them on top of a JWT format.
If a JWT is issued to a client with the express purpose of being used as a Bearer Token, then using it for that purpose is sound (subject to design/implementation flaws). But an arbitrary JWT may not have been intended as a Bearer Token, and treating it as one (even if it is signed by a trusted party) could result in significant security vulnerabilities.

Consequently, there is value in enhancing Elasticsearch Security to allow user identity to be provided in the form of a JWT, but there are risks with accepting externally generated JWTs as proof of identity.

Options

The following options have been proposed as possibly ways that Elasticsearch Security could support JWT based identity

  1. Implement a "run as JWT" feature.
  2. Implement a JWT realm
  3. Extend the existing Token Service to support JWTs
  4. Extend the existing Token Service to external tokens
  5. Implement an API to exchange JWTs for ES tokens,

Run as JWT

Elasticsearch Security has a feature to allow a request to "run as" another user. In current versions of Elasticsearch, this user must exist in a user store (natively within Elasticsearch, or in an external store such as an LDAP directory) and be able to be "looked up" by username from a configured realm.
Permission to "run as" another user is granted via the run_as privilege within a role, which grants access by username.

This model could be extended to support "run as" with JWTs instead of usernames. The behaviour would resemble the following:

  1. A new header would be added (e.g. es-security-runas-jwt), the value of which would be a JWT (possibly base64 encoded).
  2. As per the existing run as support, the request itself would need to be authenticated by another user. This could be performed using basic authentication, or another supported method such as PKI (mutual TLS).
  3. The role model would be extended to include some method by which "run-as-jwt" permissions could be declared. Further discussion would be required to determine what these permissions would look like.
  4. If the header is present, and the authenticated user is permitted to run as the JWT then a ephemeral user would be created by role-mapping the JWT in a manner similar to that used for the existing OpenID Connect realm.
  5. The request would execute under the scope & permissions of the ephemeral JWT user, as is the case for the existing run-as feature.
  6. The features above would be supported by new configuration values that define which keys to trust when validating JWT signatures, and rules for how JWTs should be exposed in role mapping.

Conceptually this reflect the fact that a JWT, absent any additional context, is a description of a security entity (a user) rather than a credential for that user. Thus it is analogous to looking up a user record in an LDAP directory, rather than authenticating against that directory.

JWT Realm

It is technically possible to implement JWT Bearer Token authentication as a new realm type. Since it is not possible to know whether an arbitrary JWT is intended to be used as a Bearer Token, the onus would be on the Elasticsearch cluster administrator to only configure trust against issuers (keys) that exclusively issue Bearer Tokens. If an administrator configured a realm that trusted an key that was used to sign non-bearer tokens, then this would introduce a security vulnerability in their cluster, but Elasticsearch would have no way of detecting the problem, since it is impossible to distinguish Bearer JWTs from other JWT usage.

Implementation wise, this option would require:

  1. A new realm type, with configuration options that are a subset of the OIDC realm configuration.
  2. Parsing & Validating JWTs from Authorization: Bearer headers
  3. Mapping JWTs to users in a way that mimics the OIDC realm.

JWTs in the Token Service

Since Elasticsearch Security already has Bearer token support, it would be possible to implement JWT Bearer Tokens as an extension to the token service, rather than a new realm.
However, the implementation (and risks) would be roughly equivalent.

External tokens

Elasticsearch supports OAuth-style access tokens (which are self issued) and Service Account Tokens.
We could extend this to also support "externally validated tokens". These would be tokens that are passed to Elasticsearch using an Authorization: Bearer header, but where the validation of the token is delegated to an external service.

Strictly speaking this would not add JWT support to Elasticsearch, but it would provide the foundation that allows users of Elasticsearch to relatively easily implement JWT support themselves, using their own validation rule.

This could be implemented by:

  1. Adding new configuration settings to Elasticsearch to support (one or more) token validation service URLs.
  2. When a Bearer token is received in Elasticsearch, and it does not match an Elasticsearch issued access token, or a Service Account token, then Elasticsearch would make an HTTP call to the external validation service(s), passing the token value.
  3. The external HTTP service would be required to validate the token and, if successful, return a representation of the user that was authenticated by the token.

This solution allows us to support any sort of bearer token that administrators need, but has some downsides:

  1. It simply pushes the validation problem to cluster administrators
  2. It adds new HTTP calls into the authentication flow
  3. It requires defining a new web service schema
  4. It is not clear what the service should return - is it a full user with role names? Or is it an object that can be passed into role mapping?

JWT / Access Token Exchange

This option is described here: #69996

It is based on the premise that another application is performing a full OIDC authentication process, and Elasticsearch is simply a downstream consumer of that OIDC JWT.

This assumption has the following consequences:

  1. It is only truly applicable for OIDC use cases, but there will be the temptation for administrators to try and adapt it for other JWT scenarios.
  2. It assume that the caller is able to orchestrate the exchange of a JWT for an access token and use that on subsequent requests, which may not be the case.

Footnotes

(1) "Reduces" because there is no guarantee that the user who is described in the JWT actually initiated the operation in question.
Assume that there are 3 processes: WebServer, AuthcService & BackendService, all connected using mutual-TLS.
A user provides some set of credentials to the WebServer. WebServer passes those credentials to AuthcService which validates them and returns a signed JWT. WebServer then makes a call to BackendService and provides this JWT as the identity of the originating user on which the call should operate. The BackendService can verify that such as user exists (by validating the JWT signature) and can verify that the request originated from the WebServer (by virtue of the mTLS connection) but it required to trust the WebServer's assertion that this operation was triggered by the User. It has no way of verifying that this is the case.

@tvernum tvernum added >enhancement :Security/Authentication Logging in, Usernames/passwords, Realms (Native/LDAP/AD/SAML/PKI/etc) team-discuss labels Apr 22, 2021
@elasticmachine elasticmachine added the Team:Security Meta label for security team label Apr 22, 2021
@elasticmachine
Copy link
Collaborator

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

@jkakavas
Copy link
Member

In my view, the options that would be close to satisfying the use cases I've seen while making sense technically are the two first ones: run-as and a jwt realm.
I'm biased towards the realm solution as this is the one I've been thinking about but I don't dislike the run-as based one, in fact I like it a lot. Some points:

  • The run-as solution presumes that the JWTs are validated externally before submitted to ES? There are also risks associated with this I think, with administrators not realizing this and never validating JWTs on their side and allowing user impersonation or privilege escalation ( if the means by which end users get a JWT is i.e. OIDC implicit flow) . If we do validate JWTs on our side ( their signature, expiration time, audience etc ) based on some configuration , then it makes more sense to me to do this in a realm
  • The run-as solution adds a burden to the system/client that integrates with elasticsearch to implement something ES specific ( assuming that the client system can already handle sending Authorization headers with a Bearer token ). It's a minor point though, as this is still a header.
  • A JWT realm could be make to work stack-wide if we( or our users) would like it to, with the help of a Kibana authentication provider

Would it be worth to add a summary of the use cases that we know of for how this solution would be used in order to help us come to a conclusion?

@albertzaharovits
Copy link
Contributor

albertzaharovits commented Apr 27, 2021

I think historically we (at least it is my impression that this is shared) held the right stance that we cannot validate a JWT, outside of a protocol, as a credential, hence JWT support is not an authentication method. JWT support is about trusting authorization decisions.
I also think that there's a lot of confusion around the support for this feature because of the multitude of roles ES can take: ES can authenticate users, act as a Service Provider in a Single Sign-On flow (also as an Idp), and now it's also being asked to function as a Resource Server.

But, pragmatically, I think the ask is clear: pass a value in a request header (which discounts the JWT / Access Token Exchange option) to let the caller access the resource on ES. Assuming this, I think the best we can do is to try to distinguish the JWT support, where ES acts as the Resource Server, from the authentication role that ES can otherwise take. Concretely, I can think of:

  • don't pass the JWT in the HTTP Authorization Header
  • don't put the JWT "thing" in the realm chain
  • don't support run-as for JWT "users"
  • offer minimal convention-based "role mapping" for JWTs (ie the "role" names must be present verbatim in a claim list, so that when the human user grants consent to a service to access the resources on the ES server on his behalf, it can see the "permissions" it's granting)
  • don't name the JWT permissions "roles" (because users have roles, JWTs have permissions)
  • disable authentication if JWT access is permitted and vice-versa

I'm getting a bit extreme, but my overarching point is separation from authentication in terms of configuration, usage and documentation.
That being said, Run as JWT would work as well, as it is acknowledges that a JWT is more akin to an username than a password, but I fear there is opportunity for confusion.

@tvernum
Copy link
Contributor Author

tvernum commented Apr 27, 2021

The run-as solution presumes that the JWTs are validated externally before submitted to ES?

My expectation was that we would absolutely do that validation in ES (I make no presumptions about whether they are validated before they're passed to ES - though I would expect that they should be).

The issue is that JWTs fall into 3 rough categories:

  1. JWTs that are used for authentication (e.g. OIDC)
  2. JWTs that are used for authorization (e.g OAuth2)
  3. JWTs that are used for something else entirely.

A realm is reasonable for (1), but has no real way to know distinguish between those cases, other than indirectly by signing key (that is, an admin knows that a key is only used to generate keys that are intended for authc, and configures the realm to trust that key).

Category (2) is really a run-as scenario. I am this system identity (logically equivalent to an OAuth client) authenticated by this credential (e.g. PKI cert/key), and I have a JWT that authorizes me to do something on behalf of this user.
However, we can reasonably expect that people will try to use the realm for (2) as well. That's not automatically a vulnerability (assuming the realm is performing role mapping, then it will map against the claims in the JWT, which is the intention of something like OAuth), but can be (if you use authorization_realms and lookup by userid) and it loses information from an audit point of view - we only audit the authz user and don't track the system identity (client) that is running as the user.

Category (3) should be entirely avoided. Trusting a JWT that is neither an authc credential nor an authz token is always going to be a problem. In the realm case the only protection you have against that is the keys that you trust. In the run-as case you have a second layer of protection because you validate that the request came from an authorized client (system account) and your trust model assumes that the client is restrictive about which JWTs it passes through.

@ywangd
Copy link
Member

ywangd commented Apr 29, 2021

I'd like to propose another option which is a variant of JWT Realm. Instead of just using the JWT as the bearer token, we could configure a secret value for the JWT realm and requires it to be passed along with the JWT. So the bearer header would be something like:

Authorization: secret_value:{JWT}

The secret value basically acts as a system password, which prevents malicious usages of arbitrary JWTs. I think it has all the advantages of the JWT Realm while adding extra protection like the run-as option. I'd also assume that this header variant is something that the customer side can easily handle with its current setup.

@bytebilly
Copy link
Contributor

From a user perspective, I see the JWT realm as the best option for various reasons. It's simple to communicate, it is more consistent with other authentication/authorization options we already provide, and it would be more complete.

Said that, I'm +1 to evaluate security implications and protect our users from common misconfiguration cases. What Yang proposed could be a good option.

@colings86
Copy link
Contributor

@ywangd Since JWT already assumes a secret that the server knows what is the function of the additional secret in your suggestion?

Personally I am in favour of the run-as option. It makes it clear that we intend JWTs to be used for Authorization and enforces that the client sending the request is a genuine client allowed to connect to that Elasticsearch Cluster. For me this option is the easiest for users to ensure they are implementing correctly and not leaving themselves open to unknown clients connecting

@ywangd
Copy link
Member

ywangd commented May 26, 2021

Since JWT already assumes a secret that the server knows what is the function of the additional secret in your suggestion?

@colings86 The extra secret is to prevent authentication using an arbitrary JWT signed by the same issuer. Specifically this is to solve the following problem listed for the JWT Realm option:

Since it is not possible to know whether an arbitrary JWT is intended to be used as a Bearer Token, the onus would be on the Elasticsearch cluster administrator to only configure trust against issuers (keys) that exclusively issue Bearer Tokens. If an administrator configured a realm that trusted an key that was used to sign non-bearer tokens, then this would introduce a security vulnerability in their cluster, but Elasticsearch would have no way of detecting the problem, since it is impossible to distinguish Bearer JWTs from other JWT usage.

You can think of this additional secret as the actual credential used for authentication and the JWT is for run-as. So it is kinda a cross between the Run As option and the JWT Realm option. Its advantages compared to the pure Run As option are:

  1. Itself support run as, i.e. one can authenticate using JWT and also run as another user
  2. It likely means less changes for clients

@tvernum tvernum closed this as completed Jul 14, 2022
@owainrutherford
Copy link

Hello, since elasticsearch has moved on in minor versions since this was released, is this feature still considered beta? If not, is there a rough timescale as to when it will become a GA feature?

@bytebilly
Copy link
Contributor

Hi @owainrutherford, the feature is still in beta even if we haven't got negative feedback so far.
We are planning to release other iterations in the near future that will eventually bring the status to GA.

@owainrutherford
Copy link

Thank you for the quick response. Just to clarify, would this be a future minor version of elasticsearch 8, and there are no (planned) breaking changes to this feature?

@bytebilly
Copy link
Contributor

would this be a future minor version of elasticsearch 8

We're planning to release improved support in one of the next few minor releases for 8.x. However, our plans may change because of other factors so we cannot commit to any specific version at the moment.

there are no (planned) breaking changes to this feature

Currently we don't have any planned breaking changes on the table. However, since it's still a beta feature, it may be subject to breaking changes before it goes GA.

@owainrutherford
Copy link

Hi there, I see with elasticsearch 8.8 the beta warning is removed from the documentation. As of 8.8 is the jwt feature now considered GA?
Thanks

@bytebilly
Copy link
Contributor

Yes, the JWT realm is now GA.

@miriam-orion
Copy link

miriam-orion commented Nov 6, 2023

Hello,
Another question regarding availability: Does the description on JWT authentication refer to the feature "Single sign-on (SAML, OpenID Connect, Kerberos, JWT)" that requires the paid subscription? Or are the JWT realm and authentication part of the basic version?

[Update]
Found the answer: it is part of paid subscriptions.

@bytebilly
Copy link
Contributor

Hi @miriam-orion, the JWT realm is included in the Platinum and Enterprise subscriptions and it's not available in the Basic tier. You can see it listed along with other Platinum SSO realms in the subscriptions page.

@miriam-orion
Copy link

miriam-orion commented Nov 6, 2023

Hi @miriam-orion, the JWT realm is included in the Platinum and Enterprise subscriptions and it's not available in the Basic tier. You can see it listed along with other Platinum SSO realms in the subscriptions page.

Thanks for the reply.
@ elastic team: In general, it would save lot of researching time if requirements for a feature were listed at the top of its feature docs page.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
>enhancement :Security/Authentication Logging in, Usernames/passwords, Realms (Native/LDAP/AD/SAML/PKI/etc) Team:Security Meta label for security team team-discuss
Projects
None yet
Development

No branches or pull requests

9 participants