Skip to content
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

[Feature] Introduces Centralized Resource Access Control and Sharing #5016

Draft
wants to merge 88 commits into
base: main
Choose a base branch
from

Conversation

DarshitChanpura
Copy link
Member

@DarshitChanpura DarshitChanpura commented Jan 10, 2025

Description

Introduces a new authorization mechanism to control access to resources defined by plugins.
There are 4 major components to this PR:

  1. Introduces an SPI that defines the contracts for a resource sharing plugin as well as Resource Access Control plugin.
  2. Introduces 4 new APIs that expose resource-sharing and access verification capabilities.
  3. Modifies DLS to implicitly check for resource-access for requesting user if incoming request is for a resource
  4. Adds a sample resource plugin with tests to demonstrate the usage of this new feature.
  5. Adds a feature flag to toggle the feature. Feature is enabled by default.
  • Category : New feature
  • Why these changes are required?
    • At present, plugins have implemented in-house authorization mechanisms for a lack of centralized framework. This PR introduces a centralized way to offload resource permissions check to security plugin. Plugins will leverage the java APIs introduced in core.

Issues Resolved

Testing

  • automated and manual testing

Check List

  • New functionality includes testing
  • New functionality has been documented
  • New Roles/Permissions have a corresponding security dashboards plugin PR
  • API changes companion pull request created
  • Commits are signed per the DCO using --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.

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

codecov bot commented Jan 13, 2025

Codecov Report

Attention: Patch coverage is 9.57661% with 897 lines in your changes missing coverage. Please review.

Project coverage is 68.85%. Comparing base (16c9332) to head (e1e876f).
Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
...ecurity/resources/ResourceSharingIndexHandler.java 3.00% 258 Missing ⚠️
...arch/security/resources/ResourceAccessHandler.java 9.60% 113 Missing ⚠️
...opensearch/security/resources/ResourceSharing.java 0.00% 68 Missing ⚠️
...opensearch/security/resources/SharedWithScope.java 0.00% 57 Missing ⚠️
...a/org/opensearch/security/resources/CreatedBy.java 0.00% 26 Missing ⚠️
...a/org/opensearch/security/resources/ShareWith.java 0.00% 25 Missing ⚠️
...s/access/list/ListAccessibleResourcesResponse.java 0.00% 23 Missing ⚠️
...ces/access/revoke/RevokeResourceAccessRequest.java 0.00% 23 Missing ⚠️
...es/access/TransportVerifyResourceAccessAction.java 0.00% 22 Missing ⚠️
.../opensearch/security/OpenSearchSecurityPlugin.java 52.27% 18 Missing and 3 partials ⚠️
... and 26 more
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #5016      +/-   ##
==========================================
- Coverage   71.45%   68.85%   -2.61%     
==========================================
  Files         334      367      +33     
  Lines       22556    23536     +980     
  Branches     3589     3680      +91     
==========================================
+ Hits        16118    16205      +87     
- Misses       4644     5525     +881     
- Partials     1794     1806      +12     
Files with missing lines Coverage Δ
.../org/opensearch/security/auth/BackendRegistry.java 78.32% <100.00%> (+0.27%) ⬆️
...org/opensearch/security/filter/SecurityFilter.java 66.03% <100.00%> (-0.32%) ⬇️
...rch/security/privileges/dlsfls/DlsRestriction.java 94.59% <100.00%> (ø)
...security/privileges/dlsfls/DocumentPrivileges.java 100.00% <100.00%> (ø)
...a/org/opensearch/security/resources/Recipient.java 100.00% <100.00%> (ø)
...g/opensearch/security/support/ConfigConstants.java 95.23% <ø> (ø)
...g/opensearch/security/resources/RecipientType.java 60.00% <60.00%> (ø)
...rces/ResourceSharingIndexManagementRepository.java 70.00% <70.00%> (ø)
...ces/access/list/ListAccessibleResourcesAction.java 0.00% <0.00%> (ø)
...rces/access/revoke/RevokeResourceAccessAction.java 0.00% <0.00%> (ø)
... and 32 more

... and 6 files with indirect coverage changes

/**
* Marker interface for all resources
*/
public abstract class Resource implements NamedWriteable, ToXContentFragment {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why is this an abstract class instead of an interface? With an abstract class, the implementer cannot extend other classes for their resources.

Copy link
Member Author

Choose a reason for hiding this comment

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

The idea is that a Resource must only extend this class. The reason why it is abstract is that I want to enforce a constructor of type Resource(StreamInput in) be created.

@@ -383,6 +384,7 @@ public class SearchOperationTest {
new AuditConfiguration(true).compliance(new AuditCompliance().enabled(true))
.filters(new AuditFilters().enabledRest(true).enabledTransport(true))
)
.nodeSettings(Map.of(OPENSEARCH_RESOURCE_SHARING_ENABLED, false))
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why is this necessary here?

Copy link
Member Author

Choose a reason for hiding this comment

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

The feature is enabled by default. Which means that the resource sharing index will be created which caused shouldGetFieldCapabilitiesForAllIndexes_positive to fail on containsExactlyIndices assertion. The other option to not adding this flag is to add that assertion. However, for the sake of this test, since it is not resource-sharing related, I added a flag to disable it.

@@ -224,6 +224,7 @@ public boolean authenticate(final SecurityRequestChannel request) {
if (adminDns.isAdminDN(sslPrincipal)) {
// PKI authenticated REST call
threadContext.putTransient(ConfigConstants.OPENDISTRO_SECURITY_USER, new User(sslPrincipal));
threadContext.putPersistent(ConfigConstants.OPENDISTRO_SECURITY_USER, new User(sslPrincipal));
Copy link
Collaborator

Choose a reason for hiding this comment

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

How is this change related to resource sharing?

Copy link
Member Author

Choose a reason for hiding this comment

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

Since writing to a resource index maybe a stashed operation, we might lose the context of the requested user. To prevent that we store the user as a persistent header which will then be retrieved while fetching current user's resources, verifying access or creating a resource.

Copy link
Member Author

Choose a reason for hiding this comment

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

In long term we do intend to change this to a persistent header and remove transient completely.


searchRequest.source(searchSourceBuilder);

SearchResponse searchResponse = client.search(searchRequest).actionGet();
Copy link
Collaborator

Choose a reason for hiding this comment

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

Sync operations in low level OpenSearch code are bound to make issues. As soon this is executed on a transport thread, this will fail.

Copy link
Member Author

Choose a reason for hiding this comment

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

Could you explain a bit more in detail?

if (this.isResourceSharingEnabled
&& !Strings.isNullOrEmpty(indexName)
&& OpenSearchSecurityPlugin.getResourceIndices().contains(indexName)) {
resourceIds = this.resourceAccessHandler.getAccessibleResourceIdsForCurrentUser(indexName);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Under the hood, this makes a sync index operation.

We are here in an extremely low level operation. I am pretty sure that this will not work, even if it would be an async operation (which it cannot be due to the API constraints).

Copy link
Member Author

Choose a reason for hiding this comment

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

Could you explain a bit more in detail?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants