-
Notifications
You must be signed in to change notification settings - Fork 282
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
[DRAFT] [Feature] Introduces resource sharing and access-control #4746
base: feature/resource-permissions
Are you sure you want to change the base?
[DRAFT] [Feature] Introduces resource sharing and access-control #4746
Conversation
return services; | ||
} | ||
|
||
public static class GuiceHolder implements LifecycleComponent { |
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 GuiceHolder
pattern from the security plugin is IMHO only a hack to get access to dependencies which are available via dependency injection, but not via the createComponents()
API in the Plugin
interface. The un-hackish way to give plugins access to ResourceService
would be to add it to the param list of createComponents()
.
Resource-sharing index gets created successfully upon first cluster start:
and subsequent starts show that the index is present:
Sample Resource Plugin loaded successfully:
|
Moved sample resource plugin code to a separate PR: #4893 |
Signed-off-by: Darshit Chanpura <dchanp@amazon.com>
Signed-off-by: Darshit Chanpura <dchanp@amazon.com>
Signed-off-by: Darshit Chanpura <dchanp@amazon.com>
Signed-off-by: Darshit Chanpura <dchanp@amazon.com>
Signed-off-by: Darshit Chanpura <dchanp@amazon.com>
Signed-off-by: Darshit Chanpura <dchanp@amazon.com>
Signed-off-by: Darshit Chanpura <dchanp@amazon.com>
Signed-off-by: Darshit Chanpura <dchanp@amazon.com>
Signed-off-by: Darshit Chanpura <dchanp@amazon.com>
Signed-off-by: Darshit Chanpura <dchanp@amazon.com>
Signed-off-by: Darshit Chanpura <dchanp@amazon.com>
Signed-off-by: Darshit Chanpura <dchanp@amazon.com>
Signed-off-by: Darshit Chanpura <dchanp@amazon.com>
Signed-off-by: Darshit Chanpura <dchanp@amazon.com>
Signed-off-by: Darshit Chanpura <dchanp@amazon.com>
Signed-off-by: Darshit Chanpura <dchanp@amazon.com>
Signed-off-by: Darshit Chanpura <dchanp@amazon.com>
Signed-off-by: Darshit Chanpura <dchanp@amazon.com>
bdb5d4e
to
b019547
Compare
Signed-off-by: Darshit Chanpura <dchanp@amazon.com>
b019547
to
45b002e
Compare
Signed-off-by: Darshit Chanpura <dchanp@amazon.com>
Signed-off-by: Darshit Chanpura <dchanp@amazon.com>
Signed-off-by: Darshit Chanpura <dchanp@amazon.com>
Signed-off-by: Darshit Chanpura <dchanp@amazon.com>
Signed-off-by: Darshit Chanpura <dchanp@amazon.com>
Signed-off-by: Darshit Chanpura <dchanp@amazon.com>
Signed-off-by: Darshit Chanpura <dchanp@amazon.com>
Signed-off-by: Darshit Chanpura <dchanp@amazon.com>
Signed-off-by: Darshit Chanpura <dchanp@amazon.com>
Signed-off-by: Darshit Chanpura <dchanp@amazon.com>
Signed-off-by: Darshit Chanpura <dchanp@amazon.com>
node_modules/ | ||
package-lock.json |
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.
Why is this necessary?
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.
it was automatically added. But we don't add node_modules and package-lock since we don't have any front-end components in this project.
@@ -345,6 +345,7 @@ private <Request extends ActionRequest, Response extends ActionResponse> void ap | |||
log.info("Transport auth in passive mode and no user found. Injecting default user"); | |||
user = User.DEFAULT_TRANSPORT_USER; | |||
threadContext.putTransient(ConfigConstants.OPENDISTRO_SECURITY_USER, user); | |||
threadContext.putPersistent(ConfigConstants.OPENDISTRO_SECURITY_USER, user); |
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.
I noticed a few of these putPersistent being added. I do not know the full context, but is there any security implications with putting it in persistently? For example maybe stashing the context wouldn't work if the user is persisted into the threadcontext. Any ideas on this usage @cwperks ?
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.
I want to add the same code in #4896. I added the notion of persistent TC headers in the core a while ago with the intent that these headers are not stashable and I'd like to move to the authenticated user as a non-stashable header.
Its added here because Security is adding an IndexOperationListener on the resourceIndex and the ThreadContext has already been stashed by the sample plugin so that it can write to the resourceIndex. By adding this call here, @DarshitChanpura is guaranteed that he can read the userinfo from the TC inside the IndexOperationListener.
I believe the postIndex
hook is running within the same block as the IndexRequest to the resourceIndex.
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.
+1 to @cwperks answer. User names are particularly required when creating or listing resources. This would ensure that a user who is current context-user is always present and thus not result in null value. At some point in future, the putTransient calls will be removed completely.
public void createResourceSharingIndexIfAbsent() { | ||
// TODO check if this should be wrapped in an atomic completable future | ||
|
||
this.resourceSharingIndexHandler.createResourceSharingIndexIfAbsent(() -> 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.
Do we need this () -> 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.
it's callback functionality. Its not used currently but was added in case there were any listeners or related items are to be added.
private static final ResourceSharingIndexListener INSTANCE = new ResourceSharingIndexListener(); | ||
private ResourceSharingIndexHandler resourceSharingIndexHandler; | ||
|
||
private boolean initialized; |
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 we not use this extra boolean and just base it on the indexlistener itself?
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.
Its to ensure that ReosurceSharingIndexListener is only initialized once.
|
||
boolean success = this.resourceSharingIndexHandler.deleteResourceSharingRecord(resourceId, resourceIndex); | ||
if (success) { | ||
log.info("Successfully deleted resource sharing entries for resource {}", resourceId); |
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.
Nit. Should this be singular since there would only be one resource sharing entry for each resource?
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.
addressed.
Signed-off-by: Darshit Chanpura <dchanp@amazon.com>
@@ -2082,6 +2127,7 @@ public Collection<Class<? extends LifecycleComponent>> getGuiceServiceClasses() | |||
|
|||
final List<Class<? extends LifecycleComponent>> services = new ArrayList<>(1); | |||
services.add(GuiceHolder.class); | |||
log.info("Guice service classes loaded"); |
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.
Do we want to change this to something lower like debug?
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.
Good catch. I will remove it.
return Collections.singletonList(systemIndexDescriptor); | ||
final SystemIndexDescriptor securityIndexDescriptor = new SystemIndexDescriptor(indexPattern, "Security index"); | ||
final SystemIndexDescriptor resourceSharingIndexDescriptor = new SystemIndexDescriptor( | ||
ConfigConstants.OPENSEARCH_RESOURCE_SHARING_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.
Nit: Do we want to add a TODO to support custom resource sharing names?
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.
Not right now no. Maybe in the next iteration if there is a request for it.
String resourceIndex = resourcePlugin.getResourceIndex(); | ||
|
||
this.indicesToListen.add(resourceIndex); | ||
log.info("Preparing to listen to index: {} of plugin: {}", resourceIndex, resourcePlugin); |
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.
Same, debug?
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.
Changed it to warn. Good catch.
if (areArgumentsInvalid(resourceIndex, clazz)) { | ||
return Collections.emptySet(); | ||
} | ||
final User user = threadContext.getPersistent(ConfigConstants.OPENDISTRO_SECURITY_USER); |
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.
Why are we putting this persistently here?
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 it to access the system index within the handler?
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 is to get user which is then used when creating a resource or listing resources. Without this the values may be null.
if (adminDNs.isAdmin(user)) { | ||
return true; | ||
} |
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.
I don't know if this design decision has already been made, but at least with tenancy there is a concept of a private tenant, which can contain private work/shouldn't be accessible to other people (except for I guess super admin which can search the index directly), do we have any plans to implement a similar feature here?
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.
adminDNs is super-admin, AFAIK
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.
non-super-admin will not be able to access these resources.
LOGGER.info("User {} revoking access to resource {} for {} for scopes {} ", user.getName(), resourceId, revokeAccess, scopes); | ||
|
||
// check if user is admin, if yes the user has permission | ||
boolean isAdmin = adminDNs.isAdmin(user); |
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.
do we want to split this out into a utility function such as hasAdminLevelAcess? Maybe there are additional use cases that we want to support here, such as a "super" role, and not just based on the DN... wdyt?
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 here is specific to super-admin. All "super" roles will require user to have the resource shared with them with that scope.
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 we also add some test cases for the various handlers?
Signed-off-by: Darshit Chanpura <dchanp@amazon.com>
Signed-off-by: Darshit Chanpura <dchanp@amazon.com>
Signed-off-by: Darshit Chanpura <dchanp@amazon.com>
This is a WIP. Will flip to ready for review once test cases are added. |
Signed-off-by: Darshit Chanpura <dchanp@amazon.com>
Signed-off-by: Darshit Chanpura <dchanp@amazon.com>
companion PR: opensearch-project/OpenSearch#16030
Description
Introduces a new authorization mechanism to control access to resources defined by plugins.
This PR also introduces a sample resource plugin to show the APIs in action.
Issues Resolved
Testing
Check List
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.