Skip to content

[performance] Apply minimal auth to the search route#257497

Merged
drewdaemon merged 18 commits intoelastic:mainfrom
drewdaemon:minimal-auth-data-plugin
Apr 14, 2026
Merged

[performance] Apply minimal auth to the search route#257497
drewdaemon merged 18 commits intoelastic:mainfrom
drewdaemon:minimal-auth-data-plugin

Conversation

@drewdaemon
Copy link
Copy Markdown
Contributor

@drewdaemon drewdaemon commented Mar 12, 2026

Summary

Part of #84923

Enable minimal authentication for the search route!

Comment on lines -186 to -191
const user = getCurrentUser(request);
if (user?.roles.length === 0) {
this.logger.warn(
`A user authenticated with the "${user.authentication_realm.name}" (${user.authentication_realm.type}) realm doesn't have any roles and isn't authorized to perform request.`
);
}
Copy link
Copy Markdown
Contributor Author

@drewdaemon drewdaemon Apr 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This log statement was creating a server error in some cases:

Error: Property "authentication_realm" is not available for minimally authenticated users.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

Context: "With minimal auth, we won’t always have roles available, so this message will become more and more misleading when debugging issues."

* to reduce number of saved object updates and reduce a chance of running over update retries limit
* @internal
*/
public trackId = async (
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

trackId is called from the now-minimally-authenticated search route, so it needs to avoid accessing authentication_realm

* request can continue rather than restart.
* @internal
*/
public getId = async (
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getId is called from the now-minimally-authenticated search route, so it needs to avoid accessing authentication_realm

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does it mean that it's possible to get search sessions from other users?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getId is called when restoring a search, so technically it's possible for them to get a search ID from another search session (in the rare case that they have the same username but different realms) but it shouldn't matter all that much because they still won't have access to the results from that ID.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah or your could add a search to another user's session with trackId. But the same data access controls ultimately apply

@drewdaemon drewdaemon changed the title Minimal auth data plugin Apply minimal auth to the search route Apr 2, 2026
@drewdaemon drewdaemon marked this pull request as ready for review April 3, 2026 15:58
@drewdaemon drewdaemon requested review from a team as code owners April 3, 2026 15:58
@drewdaemon drewdaemon requested a review from jeramysoucy April 3, 2026 15:58
@drewdaemon drewdaemon added release_note:skip Skip the PR/issue when compiling release notes backport:skip This PR does not require backporting labels Apr 3, 2026
@drewdaemon drewdaemon changed the title Apply minimal auth to the search route [performance] Apply minimal auth to the search route Apr 3, 2026
@elastic elastic deleted a comment from elasticmachine Apr 6, 2026
Copy link
Copy Markdown
Contributor

@AlexGPlay AlexGPlay left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

took me a bit to understand but i think now i get it, but let me go over it just in case:

  1. the search route now has minimal auth which means we only care about the credentials being there and the full auth is deferred to elastic
  2. this means we now don't have authentication_realm present so we can't run those checks
  3. getId and trackId are called from this route so this two can't run the ownership checks now - this last part was the one that i didn't get, but if i'm not mistaken this 2 functions are only used from that route so it makes sense now

i'm happy to give my approval as i think it makes sense, not sure if you prefer to have it also from Lukas

Copy link
Copy Markdown
Contributor

@jeramysoucy jeramysoucy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kibana Security changed LGTM!

Comment on lines -186 to -191
const user = getCurrentUser(request);
if (user?.roles.length === 0) {
this.logger.warn(
`A user authenticated with the "${user.authentication_realm.name}" (${user.authentication_realm.type}) realm doesn't have any roles and isn't authorized to perform request.`
);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

Context: "With minimal auth, we won’t always have roles available, so this message will become more and more misleading when debugging issues."

Copy link
Copy Markdown
Contributor

@walterra walterra left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

datavis owned changes LGTM, just added some nit comments/considerations.

},
authc: {
enabled: 'minimal',
reason: `This route is optimized for performant retrieval of data from Elasticsearch.`,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Absolute nit: This string should be find with regular single quotes '.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


const session = await this.get(deps, user, sessionId);
// Skip user check for getId - called from minimal auth search route
const session = await this.get(deps, user, sessionId, true);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks fine for now, just a thought about possible future route that would use full auth also calling getId/trackId, they would silently skip the user check too. Is it worth hardening this down a bit more to avoid this slipping through in a future update?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

queue[0].user,
sessionId,
{ idMapping: batchedIdMapping },
true // Skip user check for trackId - called from minimal auth search route
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks fine for now, just a thought about possible future route that would use full auth also calling getId/trackId, they would silently skip the user check too. Is it worth hardening this down a bit more to avoid this slipping through in a future update?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is unlikely to happen, but I still think it's good feedback. I'll look at turning off this check from route instead of by default.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

});

it('works with minimal auth user (no authentication_realm access)', async () => {
const minimalAuthUser = new Proxy(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be moved to a shared factory at the top of the file to avoid code duplication.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

});

it('works with minimal auth user (no authentication_realm access)', async () => {
const minimalAuthUser = new Proxy(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be moved to a shared factory at the top of the file to avoid code duplication.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@drewdaemon
Copy link
Copy Markdown
Contributor Author

@AlexGPlay

took me a bit to understand but i think now i get it, but let me go over it just in case:

Your understanding is correct!

i'm happy to give my approval as i think it makes sense, not sure if you prefer to have it also from Lukas

I'd like a review from both of you. I changed some things in d3ea63a, feel free to re-check.

@drewdaemon drewdaemon requested a review from AlexGPlay April 7, 2026 17:06
@drewdaemon drewdaemon requested a review from lukasolson April 7, 2026 17:29
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@AlexGPlay AlexGPlay left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice 😄

Copy link
Copy Markdown
Contributor

@lukasolson lukasolson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, just a couple of small comments below

searchId: string,
options: ISearchOptions
options: ISearchOptions,
skipRealmCheck: boolean = false
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since trackId is always called with skipRealmCheck: true does it make sense to even have this parameter?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lol, well I got the opposite feedback above #257497 (comment)

searchRequest: IKibanaSearchRequest,
{ sessionId, isStored, isRestore, requestHash }: ISearchOptions
{ sessionId, isStored, isRestore, requestHash }: ISearchOptions,
skipRealmCheck: boolean = false
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same question as above, isn't this always called with true now?

* request can continue rather than restart.
* @internal
*/
public getId = async (
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getId is called when restoring a search, so technically it's possible for them to get a search ID from another search session (in the rare case that they have the same username but different realms) but it shouldn't matter all that much because they still won't have access to the results from that ID.

@drewdaemon drewdaemon enabled auto-merge (squash) April 11, 2026 02:20
@drewdaemon drewdaemon disabled auto-merge April 11, 2026 02:21
@drewdaemon drewdaemon enabled auto-merge (squash) April 13, 2026 15:25
@drewdaemon drewdaemon disabled auto-merge April 13, 2026 15:26
@elasticmachine
Copy link
Copy Markdown
Contributor

💛 Build succeeded, but was flaky

Failed CI Steps

Test Failures

  • [job] [logs] FTR Configs #191 / console app console autocomplete feature ESQL queries does not suggest ESQL when inside non-query triple quotes

Metrics [docs]

Public APIs missing comments

Total count of every public API that lacks a comment. Target amount is 0. Run node scripts/build_api_docs --plugin [yourplugin] --stats comments for more detailed information.

id before after diff
data 2619 2621 +2
Unknown metric groups

API count

id before after diff
data 3243 3245 +2

History

@drewdaemon drewdaemon merged commit c92af98 into elastic:main Apr 14, 2026
19 checks passed
mbondyra added a commit to mbondyra/kibana that referenced this pull request Apr 14, 2026
* commit '11ed3645c5ededae2a6e29f2a79b31f52208b441': (157 commits)
  remove sync register uiAction methods (elastic#254590)
  [performance] Apply minimal auth to the search route (elastic#257497)
  [ES|QL] Reports correctly the controls server side errors (elastic#263020)
  [SecuritySolution][Navigation] Enable classic nav updates (elastic#262358)
  [Inference] Use pretty name and logo on feature settings page (elastic#262531)
  [Security Solution] fix AT-AB cypress test (elastic#262991)
  [SigEvents] Seed sigevents env script (elastic#261172)
  Adjust conditions for validating no refetch for expanded row (elastic#262978)
  [Agent Builder] update copy for the announcement modal (elastic#263034)
  [Search] Hide index management links for users without privileges (elastic#262627)
  Simplify OAS schema for GET `/api/spaces/space` query params (elastic#260831)
  Fix fleet output OAS regressions: SSL type explosion and Kafka union wrappers (elastic#260842)
  [Dashboards in chat] fix agent confusing the axes in a horizontal chat (elastic#263064)
  [One Workflow] Add alert state checkbox UI for workflow connector (elastic#259770)
  [One Workflow] Deprecate legacy Cases step types in workflow authoring (elastic#262070)
  skip failing test suite (elastic#248090)
  fix flaky test: MonitorDetails filter apply button not enabled (elastic#260788)
  fix: propagate AbortSignal to executeAsReasoningAgent for task cancellation (elastic#262811)
  [Security Solution][Alert KPI] Fix white space bug in alert KPIs (elastic#260803)
  [Streams] Move helpers and format_size_unit to utils folder (elastic#262550)
  ...

# Conflicts:
#	x-pack/platform/plugins/shared/dashboard_agent/public/attachment_types/canvas_integration/dashboard_canvas_content.test.tsx
#	x-pack/platform/plugins/shared/dashboard_agent/public/attachment_types/canvas_integration/dashboard_canvas_content.tsx
#	x-pack/platform/plugins/shared/dashboard_agent/public/attachment_types/canvas_integration/use_register_canvas_action_buttons.ts
#	x-pack/platform/plugins/shared/dashboard_agent/public/attachment_types/index.test.tsx
#	x-pack/platform/plugins/shared/dashboard_agent/public/attachment_types/index.tsx
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport:skip This PR does not require backporting release_note:skip Skip the PR/issue when compiling release notes v9.5.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants