-
Notifications
You must be signed in to change notification settings - Fork 81
Updates search handler to consume resource authz and updates resource authz related tests #1546
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
base: main
Are you sure you want to change the base?
Updates search handler to consume resource authz and updates resource authz related tests #1546
Conversation
Signed-off-by: Darshit Chanpura <[email protected]>
Signed-off-by: Darshit Chanpura <[email protected]>
a084db8
to
5ea6079
Compare
Signed-off-by: Darshit Chanpura <[email protected]>
Signed-off-by: Darshit Chanpura <[email protected]>
Signed-off-by: Darshit Chanpura <[email protected]>
Signed-off-by: Darshit Chanpura <[email protected]>
…ld in config xcontent parser for validate requests and correct jvm debugger args Signed-off-by: Darshit Chanpura <[email protected]>
Signed-off-by: Darshit Chanpura <[email protected]>
This reverts commit fe6aae8. Signed-off-by: Darshit Chanpura <[email protected]>
de3cae6
to
7596e9b
Compare
Signed-off-by: Darshit Chanpura <[email protected]>
Signed-off-by: Darshit Chanpura <[email protected]>
Signed-off-by: Darshit Chanpura <[email protected]>
Signed-off-by: Darshit Chanpura <[email protected]>
Signed-off-by: Darshit Chanpura <[email protected]>
@@ -465,6 +465,11 @@ public static AnomalyDetector parse( | |||
parser.nextToken(); | |||
|
|||
switch (fieldName) { | |||
case ID_FIELD: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
needed for access control on Validate method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would there be a privilege escalation when one user writes someone else's id in the request body?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No they cannot, all resource related requests are first checked for permission here, before proceeding to execute it:
https://github.com/opensearch-project/security/blob/main/src/main/java/org/opensearch/security/privileges/ResourceAccessEvaluator.java#L67
@@ -145,4 +147,13 @@ public ActionRequestValidationException validate() { | |||
return null; | |||
} | |||
|
|||
@Override | |||
public String index() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this handles the Update scenario.
), | ||
new Object[] {}, | ||
(fallbackArgs) -> resolveUserAndExecute( | ||
() -> indexDetector(user, detectorId, method, listener, detector -> adExecute(request, user, detector, context, listener)), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
most of these changes around verifyResourceAccessAndProcessRequest
are code cleanup.
* @param actionListener action listerner | ||
*/ | ||
public void search(SearchRequest request, ActionListener<SearchResponse> actionListener) { | ||
public void search(SearchRequest request, Pair<String, String> pair, ActionListener<SearchResponse> actionListener) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please review this. This change currently modifies all searchHandler.search
calls to pass the index name and id field of the config. However, the search calls that are made from tasks and results indices are not covered by resource-authz. Only AD and forecast config index are, since those two are registered as protected indices.
logger.debug("Filtering result by accessible resources"); | ||
ResourceSharingClient resourceSharingClient = ResourceSharingClientAccessor.getInstance().getResourceSharingClient(); | ||
SearchSourceBuilder searchSourceBuilder = searchRequest.source(); | ||
resourceSharingClient.getAccessibleResourceIds(pair.getLeft(), ActionListener.wrap(configIds -> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
makes as call to get accessible Id and then adds a filter to current search query to only search from those ids.
// case 5: given a forecaster Id, read access user can | ||
if (isResourceSharingFeatureEnabled()) { | ||
// not look up forecaster configuration for full-client's forecaster | ||
exception = expectThrows( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
user won't have access by default.
@@ -1471,6 +1627,309 @@ public void testFilterBy() throws IOException { | |||
} | |||
} | |||
|
|||
public void testResourceSharing() throws IOException { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
adds test specifically for resource sharing feature
}, notNullValue()); | ||
} | ||
|
||
private void waitForRevokeNonVisibility(String detId, RestClient client) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
to test that resource is no longer visible.
String oceanUser = "ocean"; | ||
RestClient oceanClient; | ||
|
||
private void waitForSharingVisibility(String detId, RestClient client) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
to test that resource is visible.
.assertTrue( | ||
exception.getMessage().contains("Filter by backend roles is enabled and User dog does not have backend roles configured") | ||
); | ||
if (isResourceSharingFeatureEnabled()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
covers resource sharing feature enabled scenario.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
read until src/main/java/org/opensearch/ad/transport/IndexAnomalyDetectorRequest.java
@@ -70,19 +79,46 @@ public void delete(DeleteByQueryRequest request, ActionListener<BulkByScrollResp | |||
} | |||
|
|||
private void validateRole(DeleteByQueryRequest request, User user, ActionListener<BulkByScrollResponse> listener) { | |||
if (user == null || !filterEnabled) { | |||
if (user == null || !(filterEnabled || shouldUseResourceAuthz)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you update comment as you add a new condition?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done.
ParseUtils.addUserBackendRolesFilter(user, request.getSearchRequest().source()); | ||
// Security is enabled and resource sharing access control is enabled | ||
if (shouldUseResourceAuthz) { | ||
// verify if new authz should be added on result index, if soo replace the null |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
soo -> so
@@ -465,6 +465,11 @@ public static AnomalyDetector parse( | |||
parser.nextToken(); | |||
|
|||
switch (fieldName) { | |||
case ID_FIELD: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would there be a privilege escalation when one user writes someone else's id in the request body?
try { | ||
ParseUtils.addUserBackendRolesFilter(user, request.getSearchRequest().source()); | ||
// Security is enabled and resource sharing access control is enabled | ||
if (shouldUseResourceAuthz) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if both shouldUseResourceAuthz and filterEnabled are true? In your current code, would that increase a user's privilege as you only check shouldUseResourceAuthz? This can happen in an old cluster when backend role filtering is enabled.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we don't intend for mixed cluster usage. If both are enabled, resource-authz takes precedence. At that point, cluster-admin is expected to have migrated resources from old sharing model to the new one.
if (shouldUseResourceAuthz) { | ||
// verify if new authz should be added on result index, if soo replace the null | ||
addAccessibleConfigsFilterAndDelete(ADIndex.RESULT.getIndexName(), request.getSearchRequest(), listener); | ||
return; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is using a terms filter (ideally via terms lookup) directly inside Delete-By-Query is better than a separate “fetch IDs → inject into DBQ” step? Terms filter keeps authorization and deletion in a single request, eliminating the read-then-delete” race where ACLs/ownership can change between calls. DBQ will return version conflict error during race condition (see https://discuss.elastic.co/t/concurrent-delete-by-query-and-indexing/68868/2
). Also, writing a single DBQ evaluates the latest ACLs at request time and enforces least-privilege by intersecting resource-based authz with any backend-role filter in the same bool query—so enabling both cannot widen access. It also removes a network round trip, reduces latency and error surface, and keeps the request small—no 1,000-ID terms array bloating the query body—while avoiding large in-memory ID lists in the transport layer. The control flow becomes linear (assemble filters → run one DBQ), easier to read, test, and maintain, and if no resources are accessible the filter simply matches none (fail-closed).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
before I answer this is ADResult Index going to be a protected index? if so we should mark is as such in TimeSeriesResourceSharingExtension.
…cally, adds resource-action-groups yml for sharing and pluginClient for search Signed-off-by: Darshit Chanpura <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CI is expected to fail until opensearch-project/security#5597 is merged.
SearchWrapper for resource-sharing requests is now being handled DLS style and will be available once this PR merges: opensearch-project/security#5600
@@ -465,6 +465,11 @@ public static AnomalyDetector parse( | |||
parser.nextToken(); | |||
|
|||
switch (fieldName) { | |||
case ID_FIELD: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No they cannot, all resource related requests are first checked for permission here, before proceeding to execute it:
https://github.com/opensearch-project/security/blob/main/src/main/java/org/opensearch/security/privileges/ResourceAccessEvaluator.java#L67
@@ -70,19 +79,46 @@ public void delete(DeleteByQueryRequest request, ActionListener<BulkByScrollResp | |||
} | |||
|
|||
private void validateRole(DeleteByQueryRequest request, User user, ActionListener<BulkByScrollResponse> listener) { | |||
if (user == null || !filterEnabled) { | |||
if (user == null || !(filterEnabled || shouldUseResourceAuthz)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done.
try { | ||
ParseUtils.addUserBackendRolesFilter(user, request.getSearchRequest().source()); | ||
// Security is enabled and resource sharing access control is enabled | ||
if (shouldUseResourceAuthz) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we don't intend for mixed cluster usage. If both are enabled, resource-authz takes precedence. At that point, cluster-admin is expected to have migrated resources from old sharing model to the new one.
if (shouldUseResourceAuthz) { | ||
// verify if new authz should be added on result index, if soo replace the null | ||
addAccessibleConfigsFilterAndDelete(ADIndex.RESULT.getIndexName(), request.getSearchRequest(), listener); | ||
return; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
before I answer this is ADResult Index going to be a protected index? if so we should mark is as such in TimeSeriesResourceSharingExtension.
Settings settings, | ||
ClusterService clusterService, | ||
Client client, | ||
PluginClient pluginClient, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PluginClient acts as a wrapper for search and security plugin will apply DLS automatically through it for resource-sharing requests
@@ -0,0 +1,31 @@ | |||
# no internal actions are included here | |||
resource_types: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please review this, as these are the action-groups that will be displayed on dashboard page for resource-access-management.
Signed-off-by: Darshit Chanpura <[email protected]>
Signed-off-by: Darshit Chanpura <[email protected]>
434ca83
to
8b3fd6e
Compare
Signed-off-by: Darshit Chanpura <[email protected]>
Description
[Describe what this change achieves]
Related Issues
Resolves #[Issue number to be closed when this PR is merged]
Check List
--signoff
.By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
For more information on following Developer Certificate of Origin and signing off your commits, please check here.