Secured view: restrict_to_alias binding + DLS pre-filter scoring - #15
Open
DarshitChanpura wants to merge 3 commits into
Open
Secured view: restrict_to_alias binding + DLS pre-filter scoring#15DarshitChanpura wants to merge 3 commits into
DarshitChanpura wants to merge 3 commits into
Conversation
Adds a per-grant boolean restrict_to_alias on a role's index-permission. When set, a grant on an alias authorizes access only through the alias itself; a direct request for the alias's backing concrete index is denied. Opt-in per grant, default false, so existing alias grants are unchanged. Closes both alias->index inheritance sites (the evaluator tries the stateful path first and falls back to the static path, so both must be handled): - IndexPattern.matches(): a restrict_to_alias pattern no longer walks up from a directly-requested backing index to its parent alias/data stream. - RoleBasedActionPrivileges: a restrict_to_alias grant seeds only the alias name into the precomputed privilege map, not the backing sub-indices; the static IndexPrivileges merge AND-combines the flag across grants for the same (role, action), so a normal grant on the same pattern still reaches the backing index (union-of-privileges semantics). Requires the nextgen (v4) privilege evaluator, which preserves the alias name in the resolved indices; the legacy evaluator resolves aliases to concrete backing names before the check and cannot distinguish alias access from direct access. Verified by SecuredViewRestrictToAliasIntegrationTest (v4, 3/3) and an IndexPatternTest unit case; RoleBasedActionPrivilegesTest confirms no regression.
Adds an opt-in setting, plugins.security.dls.pre_filter_scoring (default false), that makes DLS apply the role's document filter as a pre-filter: the combined (DLS restriction + user query) is wrapped in a constant_score so BM25 collection statistics reflect only the documents the role can read, instead of being computed over the whole shard and filtered afterward. Without this, a term that occurs only in documents outside the DLS restriction affects the BM25 score of a document the role can read (its corpus-wide document frequency lowers the term's IDF), so relevance scores depend on documents the role cannot see. Pre-filtering keeps scores a function of the visible subset alone. The returned document set is unchanged; only relevance scoring is suppressed. Intended for the common case where the restricted view does not need relevance ranking. Both DLS search paths are covered: - filter-level (DlsFilterLevelActionHandler): wraps its re-issued query. - lucene-level / default ADAPTIVE (DlsFlsValveImpl): wraps the DLS-scoped query injected into the search context, where the user query was otherwise added as a scored Occur.MUST clause over whole-shard stats. The setting is dynamic: the valve registers a settings-update consumer and the filter-level handler reads the live value per request, so a runtime transient/persistent update takes effect without a node restart. Also registers the previously-unregistered plugins.security.dls.mode setting. Verified on a live 3.8.0-SNAPSHOT cluster in ADAPTIVE mode: a term confined to restricted docs scored 2.19 vs a nonexistent term's 7.14 (scores varying with non-visible data); with the flag on both score 1.0, document isolation intact. Integration test DlsPreFilterScoringIntegrationTest (2/2) asserts the filter-level path. Default off preserves existing behavior. Follow-up: constant_score suppresses ranking; ranked restricted views (real relevance over visible-only statistics) are a separate filtered-statistics effort.
Adds scoresAreVisibilityIndependent_underDfsQueryThenFetch to lock in DFS-phase coverage. dfs_query_then_fetch gathers term statistics in a separate phase before the query phase; the pre-filter constant_score wrap is applied in the query phase (onPreQueryPhase). This test asserts the DFS phase also observes the wrapped query so it does not reintroduce whole-shard statistics -- a term confined to non-visible docs must score the same as an absent term under DFS. Previously verified by hand; now guarded by a test. 3/3 green.
DarshitChanpura
force-pushed
the
feat/secured-view-e2e
branch
from
August 13, 2026 04:56
45a4bbf to
73df8f9
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds a secured view to the security plugin: a per-grant
restrict_to_aliasflag on a role's index-permission, composed with the existing DLS pre-filter
scoring bridge.
1.
restrict_to_aliasaccess binding (net-new)When set, a grant on an alias authorizes access only through the alias; a
direct request for the alias's backing concrete index is denied. Opt-in per
grant, default
false, so existing alias grants are unchanged.Closes both alias→index inheritance sites (the evaluator tries the stateful
path first and falls back to the static one, so both are handled):
IndexPattern.matches()— arestrict_to_aliaspattern no longer walks upfrom a directly-requested backing index to its parent alias/data stream.
RoleBasedActionPrivileges— arestrict_to_aliasgrant seeds only the aliasname into the precomputed privilege map, not the backing sub-indices; the
static
IndexPrivilegesmerge AND-combines the flag across grants for the same(role, action)so a normal grant on the same pattern still reaches thebacking index (union-of-privileges semantics).
Requires the nextgen (v4) privileges evaluator, which preserves the alias name
in the resolved indices; the legacy evaluator resolves aliases to concrete
backing names before the check and cannot distinguish alias access from direct
access.
2. DLS pre-filter scoring bridge
When
plugins.security.dls.pre_filter_scoringis enabled, filter-level andlucene-level DLS wrap the combined (DLS filter + user query) in a
constant_score, so relevance scores reflect only the documents the role canread. Default off; existing behavior unchanged.
Testing
SecuredViewRestrictToAliasIntegrationTest(v4, 3/3): view user reads thealias, is denied the backing index; a control user with the same grant without
the flag still reaches the backing index (no regression).
IndexPatternTestunit case on the static matcher.RoleBasedActionPrivilegesTest(8/8) — no regression.DlsPreFilterScoringIntegrationTest(3/3) for the scoring bridge, incl.dfs_query_then_fetch.