Skip to content

Conversation

@richard-dennehy
Copy link
Contributor

@richard-dennehy richard-dennehy commented Oct 29, 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

@richard-dennehy richard-dennehy added >non-issue :Security/Security Security issues without another label Team:Security Meta label for security team labels Oct 29, 2025
);
}

public void testResolveIndexWithRemotePrefix() {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I noticed that I could just set all cross project requests to go down the "all indices" path and all the tests would pass, even though this is obviously wrong; I've added this test which fails under that scenario

Copy link
Member

Choose a reason for hiding this comment

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

all the tests would pass

Do you mean all tests in this test class? I am surprised unless all existing tests are effectively resolving to all accessible indices. Is that the case? Also, I assume tests in other places, e.g. the serverless REST test, should fail?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think it's because the majority of the other tests in this file have CPS mode disabled; I'll see if the REST test guards against this, but I don't want it to be the only test that would fail - it makes the feedback loop too long

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Confirmed that the REST test fails when this functionality is implemented incorrectly

@richard-dennehy richard-dennehy marked this pull request as ready for review October 29, 2025 16:01
@elasticsearchmachine
Copy link
Collaborator

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

Copy link
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.

This look mostly good. I have only minor comments.

Can you also have a serverless side PR to update the test scenarios?

Comment on lines 338 to 350
isAllIndices = crossProjectModeDecider.resolvesCrossProject(replaceable)
? IndexNameExpressionResolver.isAllIndices(
indicesList(indicesRequest.indices()),
(expr) -> CrossProjectIndexExpressionsRewriter.rewriteIndexExpression(
expr,
authorizedProjects.originProjectAlias(),
authorizedProjects.allProjectAliases()
).localExpression()
)
: IndexNameExpressionResolver.isAllIndices(
indicesList(indicesRequest.indices()),
(expr) -> IndexNameExpressionResolver.splitSelectorExpression(expr).v1()
);
Copy link
Member

Choose a reason for hiding this comment

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

This matches what I was thinking, i.e. let cases like *:_all go through the all indices handling. I suggest we use RemoteClusterAware#splitIndexName instead of rewriteIndexExpression. It is lighter and we don't care about resolving projects at this point. It also needs to handle syntax like selector. I'd prefer we don't error out at isAllIndices check. The unsupported syntax will still be caught later when we call rewriteIndexExpression. So overall I am suggeting something like

IndexNameExpressionResolver.isAllIndices(
    indicesList(indicesRequest.indices()), 
    expr -> {
        IndexNameExpressionResolver.splitSelectorExpression(RemoteClusterAware.splitIndexName(expr)[1]).v1()
    }
)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It appears this isn't enough, as this means any expression targeting _all will resolve all indices on the local project, even if that expression is e.g. some_remote_project:_all.

We need to check if the expression is _all, and that the prefix includes the local project. It looks to me like rewriteIndexExpression handles all the edge cases here, even if it does more than what's necessary here.

Copy link
Member

Choose a reason for hiding this comment

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

Yes we will resolve local indices unnecessarily in this case. But I think local indices should still be excluded because of this code. I was going to leave the unnecessary expansion for a future optimization.

Even if we use rewriteIndexExpression here, it is not sufficient due to project_routing, e.g. we will still expand local indices unnecessarily when the request has expression _all and project routing some_remote_project. If you are keen to avoid local expansion, I'd rather prefer we solve this more comprehensively to cover this TODO as well.

What I have in mind is something like the follows:

  1. Still use the splitIndexName and splitSelectorExpression for checking isAllIndices which IMO should be interpreted as "is it an all indices pattern for any project".
  2. Before expanding local indices, check crossProjectModeDecider.resolvesCrossProject and only expand locally if the final resolved projects include the origin project.

Copy link
Member

Choose a reason for hiding this comment

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

But I think local indices should still be excluded because of this code.

It appears that this logic only handles project routing filtering but not the qualified projects in index expression. So it does not work for linked_project:_all.

I am still a little suspicious on the latest change. IIUC, it means an expression like linked_project:_all goes through the else branch of the isAllIndices check? While expressions like *:_all or _all with project routing linked_project still go through the if branch. The later is functionally equivalent to linked_project:_all and it would great if they follow the same path. Maybe we just need to resolve the project routing before invoking rewriteIndexExpression? If we take this path, I think we should also rename the isAllIndices variable to something like containsLocalAllIndices?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've switched back to using splitIndexName again, and extended the shouldExcludeLocalResolution check to check if localExpression is set, and this seems to work (including the REST test). Does this align with what you were thinking?

I could also take a look at moving the condition earlier to see if we can skip the redundant local expansion as well.

Copy link
Member

Choose a reason for hiding this comment

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

That works for me as well. We can have separate PR to address the TODO for skipping redundant local expansion.

);
}

public void testResolveIndexWithRemotePrefix() {
Copy link
Member

Choose a reason for hiding this comment

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

all the tests would pass

Do you mean all tests in this test class? I am surprised unless all existing tests are effectively resolving to all accessible indices. Is that the case? Also, I assume tests in other places, e.g. the serverless REST test, should fail?

@elasticsearchmachine elasticsearchmachine added the serverless-linked Added by automation, don't add manually label Oct 30, 2025
Copy link
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

var unprefixed = crossProjectModeDecider.resolvesCrossProject(replaceable)
? RemoteClusterAware.splitIndexName(expr)[1]
: expr;
return unprefixed != null ? IndexNameExpressionResolver.splitSelectorExpression(unprefixed).v1() : null;
Copy link
Member

Choose a reason for hiding this comment

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

Nit: I think unprefixed cannot be null?

@richard-dennehy richard-dennehy added the auto-merge-without-approval Automatically merge pull request when CI checks pass (NB doesn't wait for reviews!) label Nov 6, 2025
@elasticsearchmachine elasticsearchmachine merged commit 774cf6a into elastic:main Nov 6, 2025
40 checks passed
@richard-dennehy richard-dennehy deleted the remote-project-prefixed-all-expressions branch November 6, 2025 10:47
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
szybia added a commit to szybia/elasticsearch that referenced this pull request Nov 6, 2025
…-json

* upstream/main:
  Mute org.elasticsearch.xpack.inference.action.filter.ShardBulkInferenceActionFilterBasicLicenseIT testLicenseInvalidForInference {p0=false} elastic#137691
  Mute org.elasticsearch.xpack.inference.action.filter.ShardBulkInferenceActionFilterBasicLicenseIT testLicenseInvalidForInference {p0=true} elastic#137690
  [LTR] Fix feature display order when using explain. (elastic#137671)
  Remove extra RemoteClusterService instances in unit test (elastic#137647)
  Fix `ComponentTemplatesFileSettingsIT.testSettingsApplied` (elastic#137669)
  Consolidates troubleshooting content into the "Returning semantic field embeddings in _source" section (elastic#137233)
  Update bundled JDK to 25.0.1 (elastic#137640)
  resolve indices for prefixed _all expressions (elastic#137330)
  ESQL: Add TopN support for exponential histograms (elastic#137313)
  allows field caps to be cross project (elastic#137530)
  ESQL: Add exponential histogram percentile function (elastic#137553)
  Wait for nodes to have downloaded databases in `GeoIpDownloaderIT` (elastic#137636)
  Tighten on when THROTTLE decision can be returned (elastic#136794)
  Mute org.elasticsearch.xpack.esql.qa.single_node.GenerativeMetricsIT test elastic#137655
  Add a test for two little known conditional processor paths (elastic#137645)
  Extract a common ORIGIN constant (elastic#137612)
  Remove early phase failure in batched (elastic#136889)
  Returning correct index mode from get data streams api (elastic#137646)
  [ML] Manage AD results indices (elastic#136065)
szybia added a commit to szybia/elasticsearch that referenced this pull request Nov 6, 2025
…-json

* upstream/main:
  Mute org.elasticsearch.xpack.inference.action.filter.ShardBulkInferenceActionFilterBasicLicenseIT testLicenseInvalidForInference {p0=false} elastic#137691
  Mute org.elasticsearch.xpack.inference.action.filter.ShardBulkInferenceActionFilterBasicLicenseIT testLicenseInvalidForInference {p0=true} elastic#137690
  [LTR] Fix feature display order when using explain. (elastic#137671)
  Remove extra RemoteClusterService instances in unit test (elastic#137647)
  Fix `ComponentTemplatesFileSettingsIT.testSettingsApplied` (elastic#137669)
  Consolidates troubleshooting content into the "Returning semantic field embeddings in _source" section (elastic#137233)
  Update bundled JDK to 25.0.1 (elastic#137640)
  resolve indices for prefixed _all expressions (elastic#137330)
  ESQL: Add TopN support for exponential histograms (elastic#137313)
  allows field caps to be cross project (elastic#137530)
  ESQL: Add exponential histogram percentile function (elastic#137553)
  Wait for nodes to have downloaded databases in `GeoIpDownloaderIT` (elastic#137636)
  Tighten on when THROTTLE decision can be returned (elastic#136794)
  Mute org.elasticsearch.xpack.esql.qa.single_node.GenerativeMetricsIT test elastic#137655
  Add a test for two little known conditional processor paths (elastic#137645)
  Extract a common ORIGIN constant (elastic#137612)
  Remove early phase failure in batched (elastic#136889)
  Returning correct index mode from get data streams api (elastic#137646)
  [ML] Manage AD results indices (elastic#136065)
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

auto-merge-without-approval Automatically merge pull request when CI checks pass (NB doesn't wait for reviews!) >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.

3 participants