Skip to content

record index resolution for _all expressions#135425

Merged
richard-dennehy merged 15 commits intoelastic:mainfrom
richard-dennehy:record-_all-index-resolution
Oct 15, 2025
Merged

record index resolution for _all expressions#135425
richard-dennehy merged 15 commits intoelastic:mainfrom
richard-dennehy:record-_all-index-resolution

Conversation

@richard-dennehy
Copy link
Copy Markdown
Contributor

@richard-dennehy richard-dennehy commented Sep 25, 2025

Follow up to #135081

Records resolution for _all index expressions

Resolves: ES-13004

@richard-dennehy richard-dennehy added >non-issue :Security/Security Security issues without another label Team:Security Meta label for security team labels Sep 25, 2025
@richard-dennehy richard-dennehy marked this pull request as ready for review September 25, 2025 11:51
@elasticsearchmachine
Copy link
Copy Markdown
Collaborator

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

@n1v0lg n1v0lg requested a review from ywangd October 7, 2025 16:14
Copy link
Copy Markdown
Member

@ywangd ywangd left a comment

Choose a reason for hiding this comment

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

I am not sure about the status of this PR. It has not implemented the CPS resolution yet. Maybe it should be draft?

Copy link
Copy Markdown
Member

@ywangd ywangd left a comment

Choose a reason for hiding this comment

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

I had some more comments.

I think it's also possible to get a pattern like *:_all which takes the other path as opposed to isAllIndices == true. I suspect it may not work as is since indexAbstractionResolver.resolveIndexAbstractions does not handle _all. We can address it separately.

Comment on lines +374 to +395
var resolvedExpressionsBuilder = ResolvedIndexExpressions.builder();
Set<String> remoteIndices = Collections.emptySet();
if (crossProjectModeDecider.resolvesCrossProject(replaceable)) {
remoteIndices = CrossProjectIndexExpressionsRewriter.rewriteIndexExpression(
"*",
authorizedProjects.originProjectAlias(),
authorizedProjects.allProjectAliases()
).remoteExpressions();
}

resolvedExpressionsBuilder.addExpressions(
indicesRequest.indices().length > 0 ? indicesRequest.indices()[0] : Metadata.ALL,
localExpressions,
ResolvedIndexExpression.LocalIndexResolutionResult.SUCCESS,
remoteIndices
);
var resolved = resolvedExpressionsBuilder.build();

if (crossProjectModeDecider.crossProjectEnabled()) {
setResolvedIndexExpressionsIfUnset(replaceable, resolved);
}
resolvedIndicesBuilder.addLocal(resolved.getLocalIndicesList());
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

A couple comments:

  1. It needs to be moved inside the above if (indicesOptions.expandWildcardExpressions()) { block since there is no need to resolve CPS if something like _all is used along with expandWildcards=false, i.e. it resolves to nothing everywhere so that we can short circuit
  2. The first argument to CrossProjectIndexExpressionsRewriter.rewriteIndexExpression should use the actual pattern passed in, i.e. something like indicesRequest.indices() == null || indicesRequest.indices().isEmpty() ? "_all" : indicesRequest.indices()[0]. This should ensure the any selector pattern is included and the current code should throw an exception for them on rewriting as intended.
  3. Code related to CPS is better all put inside the if (crossProjectModeDecider.resolvesCrossProject(replaceable)) { block so that it is clear they do not apply when the request is not CPS relevant. setResolvedIndexExpressionsIfUnset is an exception since it is already wrapped with CPS enabled check.

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.

For 3 - I don't think there's anything I can move; line 395 needs to always happen, to match the existing behaviour - this means everything else currently outside the CPS branch needs to stay out of that branch

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I should have been more specific. I had performance in mind. The index resolution can be performance sensitive when a cluster has a large number of indices.

The original code adds each resolved index inline with resolvedIndicesBuilder.addLocal thus build the list of indices only once.

The proposed change builds a HashSet first. It then builds a List (getLocalIndicesList) and finally calls resolvedIndicesBuilder.addLocal(List) which internally builds yet another list. So I was thinking whether we could separate the CPS path a bit more from the current code path so that it does not impact current production. That said, we can defer this as a follow-up.

Copy link
Copy Markdown
Member

@ywangd ywangd left a comment

Choose a reason for hiding this comment

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

I think this is almost there for a reasonable first version. Could you please raise a linked serverless side PR to augument the REST test CrossProjectSearchRestIT#testCrossProjectResolveIndexWithUniversalApiKey for the change here?

Comment on lines +374 to +395
var resolvedExpressionsBuilder = ResolvedIndexExpressions.builder();
Set<String> remoteIndices = Collections.emptySet();
if (crossProjectModeDecider.resolvesCrossProject(replaceable)) {
remoteIndices = CrossProjectIndexExpressionsRewriter.rewriteIndexExpression(
"*",
authorizedProjects.originProjectAlias(),
authorizedProjects.allProjectAliases()
).remoteExpressions();
}

resolvedExpressionsBuilder.addExpressions(
indicesRequest.indices().length > 0 ? indicesRequest.indices()[0] : Metadata.ALL,
localExpressions,
ResolvedIndexExpression.LocalIndexResolutionResult.SUCCESS,
remoteIndices
);
var resolved = resolvedExpressionsBuilder.build();

if (crossProjectModeDecider.crossProjectEnabled()) {
setResolvedIndexExpressionsIfUnset(replaceable, resolved);
}
resolvedIndicesBuilder.addLocal(resolved.getLocalIndicesList());
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I should have been more specific. I had performance in mind. The index resolution can be performance sensitive when a cluster has a large number of indices.

The original code adds each resolved index inline with resolvedIndicesBuilder.addLocal thus build the list of indices only once.

The proposed change builds a HashSet first. It then builds a List (getLocalIndicesList) and finally calls resolvedIndicesBuilder.addLocal(List) which internally builds yet another list. So I was thinking whether we could separate the CPS path a bit more from the current code path so that it does not impact current production. That said, we can defer this as a follow-up.

@elasticsearchmachine elasticsearchmachine added the serverless-linked Added by automation, don't add manually label Oct 13, 2025
if (crossProjectModeDecider.crossProjectEnabled()) {
setResolvedIndexExpressionsIfUnset(replaceable, resolved);
}
resolvedIndicesBuilder.addLocal(resolved.getLocalIndicesList());
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We need to call resolvedIndicesBuilder.addRemote(resolved.getRemoteIndicesList()) as well to ensure remote indices are not lost after rewriting.

Copy link
Copy Markdown
Member

@ywangd ywangd left a comment

Choose a reason for hiding this comment

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

LGTM

Please make sure CI is green before merging. Thanks!

@richard-dennehy richard-dennehy merged commit ec2b7f0 into elastic:main Oct 15, 2025
40 checks passed
Kubik42 pushed a commit to Kubik42/elasticsearch that referenced this pull request Oct 16, 2025
* record index resolution for _all expressions

* [CI] Auto commit changes from spotless

* cleanup

* fix compile

* include remote expressions in _all index resolution

* address review comments

* clean up tests

* [CI] Auto commit changes from spotless

* address review comments

* [CI] Auto commit changes from spotless

* update remote indices list

* use order-insensitive assertion

---------

Co-authored-by: elasticsearchmachine <infra-root+elasticsearchmachine@elastic.co>
Co-authored-by: Nikolaj Volgushev <n1v0lg@users.noreply.github.com>
elasticsearchmachine pushed a commit that referenced this pull request Nov 6, 2025
Follow up to #135425

As identified, expressions such as `*:_all` currently don't resolve
correctly (it appears that it currently tries to authorize the user
against the literal index "_all").

This PR fixes the resolution of prefixed `_all` expressions.

Relates: ES-13213
afoucret pushed a commit to afoucret/elasticsearch that referenced this pull request Nov 6, 2025
Follow up to elastic#135425

As identified, expressions such as `*:_all` currently don't resolve
correctly (it appears that it currently tries to authorize the user
against the literal index "_all").

This PR fixes the resolution of prefixed `_all` expressions.

Relates: ES-13213
Kubik42 pushed a commit to Kubik42/elasticsearch that referenced this pull request Nov 10, 2025
Follow up to elastic#135425

As identified, expressions such as `*:_all` currently don't resolve
correctly (it appears that it currently tries to authorize the user
against the literal index "_all").

This PR fixes the resolution of prefixed `_all` expressions.

Relates: ES-13213
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

>non-issue :Security/Security Security issues without another label serverless-linked Added by automation, don't add manually Team:Security Meta label for security team v9.3.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants