Skip to content
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

[8.11] Fix memory leak from JWT cache (and fix the usage of the JWT auth cache) (#101799) #101841

Merged

Conversation

jakelandis
Copy link
Contributor

Backport

This will backport the following commits from main to 8.11:

Questions ?

Please refer to the Backport tool documentation

…he) (elastic#101799)

This commit fixes a memory leak and ensures that the JWT authentication cache is actually used to short circuit authenticate.

When JWT authentication is successful we cache a hash(JWT) -> User. On subsequent authentication attempts we should
short circuit some of the more expensive validation thanks to this cache. The existing cache key is a `BytesArray` constructed
from `jwtAuthenticationToken.getUserCredentialsHash()` (the hash value of the JWT). However,  `jwtAuthenticationToken` is
comes from the security context which is effectively a request scoped object. When the security context goes out of scope the
value of `jwtAuthenticationToken.getUserCredentialsHash()` is zero'ed out to help keep sensitive data out of the heap. It is
arguable if zero'ing out that data is  useful especially for a hashed value, but is inline with the internal contract/expectations.
Since the cache key is derived from `jwtAuthenticationToken.getUserCredentialsHash()` when that get object is zero'ed out,
so is the cache key.

This results in a cache key that changes from a valid value to an empty byte array. This results in a junk  cache entry.  Subsequent
authentication with the same JWT will result in a new cache entry which will then follow the same pattern of getting zero'ed out.
This results in a useless cache with nothing but zero'ed out cache keys. This negates any benefits of having a cache at all in that
a full authentication is preformed all the time which can be expensive for JWT (especially since JWT requires role mappings
and role mappings are not cached).

Fortunately the default cache size is 100k (by count) so the actual memory leak is technically capped but can vary depending
on how large the cache values. This is an approximate cap of ~55MB where 3.125 MB (100k * 256 bits) for the
sha256 cache keys + ~50MB (100k * ~50 bytes) cache values, however, it is possible for the cache to be larger if the values in
the cache are larger.

The fix here is to ensure the cache key used is a copy of the value that is zero'ed out (before it is zero'ed out).

fixes: elastic#101752
(cherry picked from commit cef2b80)

# Conflicts:
#	x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/jwt/JwtRealm.java
@jakelandis jakelandis added auto-merge-without-approval Automatically merge pull request when CI checks pass (NB doesn't wait for reviews!) backport labels Nov 6, 2023
@elasticsearchmachine elasticsearchmachine merged commit edf7016 into elastic:8.11 Nov 6, 2023
@jakelandis jakelandis deleted the backport/8.11/pr-101799 branch November 6, 2023 17:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
auto-merge-without-approval Automatically merge pull request when CI checks pass (NB doesn't wait for reviews!) backport v8.11.1
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants