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

[DRAFT] [Feature]Introduces ability to control access to and share resources #16030

Draft
wants to merge 27 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
909a85b
Adds a new plugin type named ResourcePlugin and relevant base classes
DarshitChanpura Aug 27, 2024
66a849c
Adds a No-op implementation of ResourcePlugin
DarshitChanpura Aug 27, 2024
08cdcb3
Merge remote-tracking branch 'upstream/main' into resource-permissions
DarshitChanpura Aug 30, 2024
d7169e4
Adds a way to configure security plugin for resource access-control
DarshitChanpura Aug 30, 2024
58ae851
Fixes compilation errors and changes debug log-level to info for Reso…
DarshitChanpura Aug 30, 2024
fd00243
Replace plugin count check with isEmpty
DarshitChanpura Aug 30, 2024
ef8a0b7
Adds package-info
DarshitChanpura Aug 30, 2024
e98cb61
Renames a bunch of files
DarshitChanpura Aug 30, 2024
96f09b0
Changes method signatures to be inline with their usage
DarshitChanpura Aug 30, 2024
c86dfc9
Adds new method for deleting by entity
DarshitChanpura Aug 30, 2024
7c6ec2a
Adds abstract method definitions for ResourcePlugin interface
DarshitChanpura Sep 3, 2024
c04762e
Merge remote-tracking branch 'upstream/main' into resource-permissions
DarshitChanpura Sep 3, 2024
f95a67f
Adds toXContent implementations
DarshitChanpura Sep 6, 2024
8b8fffd
Merge remote-tracking branch 'upstream/main' into resource-permissions
DarshitChanpura Sep 6, 2024
7e7cd0a
Modifies some method names and comments
DarshitChanpura Sep 10, 2024
e1a1b62
Merge remote-tracking branch 'upstream/main' into resource-permissions
DarshitChanpura Oct 2, 2024
23fcfba
Fixes license
DarshitChanpura Oct 2, 2024
fba48ab
Adds changelog entry
DarshitChanpura Oct 2, 2024
9cb8d0e
Adds a notion of scope
DarshitChanpura Oct 2, 2024
848234e
Modifies sharedwith to accomodate scope
DarshitChanpura Oct 4, 2024
eaf0c6e
Adds missing JavaDoc
DarshitChanpura Oct 4, 2024
6a6e6f7
Merge remote-tracking branch 'upstream/main' into resource-permissions
DarshitChanpura Oct 4, 2024
566913a
Adds NamedWriteable capability and removes un-needed method
DarshitChanpura Oct 4, 2024
b4f876f
Merge remote-tracking branch 'upstream/main' into resource-permissions
DarshitChanpura Oct 10, 2024
9baac32
Updates toXContent implementations
DarshitChanpura Oct 10, 2024
0eb47ac
Fix toString implementation
DarshitChanpura Oct 10, 2024
e313071
Allows the ability to list resource permissions
DarshitChanpura Oct 15, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*/

package org.opensearch.accesscontrol.resources;

import org.opensearch.core.xcontent.ToXContentFragment;
import org.opensearch.core.xcontent.XContentBuilder;

import java.io.IOException;

/**
* This class contains information on the creator of a resource.
* Creator can either be a user or a backend_role.
*
* @opensearch.experimental
*/
public class CreatedBy implements ToXContentFragment {

private String user;

private String backendRole;

public CreatedBy(String user, String backendRole) {
this.user = user;
this.backendRole = backendRole;
}

public String getBackendRole() {
return backendRole;
}

public void setBackendRole(String backendRole) {
this.backendRole = backendRole;
}

public String getUser() {
return user;
}

public void setUser(String user) {
this.user = user;
}

@Override
public String toString() {
return "CreatedBy {" + "user='" + user + '\'' + ", backendRole='" + backendRole + '\'' + '}';
}

@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
return builder.startObject().field("user", user).field("backend_role", backendRole).endObject();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*/

package org.opensearch.accesscontrol.resources;

/**
* This enum contains the type of entities a resource can be shared with.
*
* @opensearch.experimental
*/
public enum EntityType {

USERS,

ROLES,

BACKEND_ROLES,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

package org.opensearch.accesscontrol.resources;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.opensearch.OpenSearchException;
import org.opensearch.plugins.NoOpResourceAccessControlPlugin;
import org.opensearch.plugins.ResourceAccessControlPlugin;
import org.opensearch.plugins.ResourcePlugin;

import java.util.List;
import java.util.stream.Collectors;

/**
* Resource access control for OpenSearch
*
* @opensearch.experimental
* */
public class ResourceService {
private static final Logger log = LogManager.getLogger(ResourceService.class);

private final ResourceAccessControlPlugin resourceACPlugin;
private final List<ResourcePlugin> resourcePlugins;

public ResourceService(final List<ResourceAccessControlPlugin> resourceACPlugins, List<ResourcePlugin> resourcePlugins) {
this.resourcePlugins = resourcePlugins;

if (resourceACPlugins.isEmpty()) {
log.info("Security plugin disabled: Using NoOpResourceAccessControlPlugin");
resourceACPlugin = new NoOpResourceAccessControlPlugin();
} else if (resourceACPlugins.size() == 1) {
log.info("Security plugin enabled: Using OpenSearchSecurityPlugin");
resourceACPlugin = resourceACPlugins.get(0);
} else {
throw new OpenSearchException(
"Multiple resource access control plugins are not supported, found: "
+ resourceACPlugins.stream().map(Object::getClass).map(Class::getName).collect(Collectors.joining(","))
);
}
}

/**
* Gets the current ResourcePlugin to perform authorization
*/
public ResourceAccessControlPlugin getResourceAccessControlPlugin() {
return resourceACPlugin;
}

/**
* List active plugins that define resources
*/
public List<ResourcePlugin> listResourcePlugins() {
return resourcePlugins;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*/

package org.opensearch.accesscontrol.resources;

import org.opensearch.core.xcontent.ToXContentFragment;
import org.opensearch.core.xcontent.XContentBuilder;

import java.io.IOException;
import java.util.Objects;

/**
* A document in .resource_sharing index.
* Holds information about the resource (obtained from defining plugin's meta-data),
* the index which defines the resources, the creator of the resource,
* and the information on whom this resource is shared with.
*
* @opensearch.experimental
*/
public class ResourceSharing implements ToXContentFragment {

private String sourceIdx;

private String resourceId;

private CreatedBy createdBy;

private ShareWith shareWith;

public ResourceSharing(String sourceIdx, String resourceId, CreatedBy createdBy, ShareWith shareWith) {
this.sourceIdx = sourceIdx;
this.resourceId = resourceId;
this.createdBy = createdBy;
this.shareWith = shareWith;
}

public String getSourceIdx() {
return sourceIdx;
}

public void setSourceIdx(String sourceIdx) {
this.sourceIdx = sourceIdx;
}

public String getResourceId() {
return resourceId;
}

public void setResourceId(String resourceId) {
this.resourceId = resourceId;
}

public CreatedBy getCreatedBy() {
return createdBy;
}

public void setCreatedBy(CreatedBy createdBy) {
this.createdBy = createdBy;
}

public ShareWith getShareWith() {
return shareWith;
}

public void setShareWith(ShareWith shareWith) {
this.shareWith = shareWith;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ResourceSharing resourceSharing = (ResourceSharing) o;
return Objects.equals(getSourceIdx(), resourceSharing.getSourceIdx())
&& Objects.equals(getResourceId(), resourceSharing.getResourceId())
&& Objects.equals(getCreatedBy(), resourceSharing.getCreatedBy())
&& Objects.equals(getShareWith(), resourceSharing.getShareWith());
}

@Override
public int hashCode() {
return Objects.hash(getSourceIdx(), getResourceId(), getCreatedBy(), getShareWith());
}

@Override
public String toString() {
return "Resource {"
+ "sourceIdx='"
+ sourceIdx
+ '\''
+ ", resourceId='"
+ resourceId
+ '\''
+ ", createdBy="
+ createdBy
+ ", sharedWith="
+ shareWith
+ '}';
}

@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
return builder.startObject()
.field("source_idx", sourceIdx)
.field("resource_id", resourceId)
.field("created_by", createdBy)
.field("share_with", shareWith)
.endObject();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*/

package org.opensearch.accesscontrol.resources;

import org.opensearch.core.xcontent.ToXContentFragment;
import org.opensearch.core.xcontent.XContentBuilder;

import java.io.IOException;
import java.util.List;

/**
* This class contains information about whom a resource is shared with.
* It could be a user-name, a role or a backend_role.
Copy link

Choose a reason for hiding this comment

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

Is it really necessary to support all three criteria (user name, roles, backend roles)? Especially back end roles can vary between auth backend (e.g. users authenticated via LDAP might have different backend roles than users authenticated via OIDC).

Such disparities can lead to confusion.

Who is supposed to specify these criteria when?

Copy link
Member

Choose a reason for hiding this comment

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

Unfortunately, backend roles is already in place amongst plugins that implement custom resource authz.

Its already in place in:

  1. ML Commons
  2. Flow Framework
  3. Anomaly Detection
  4. Alerting

I think there may be others as well (possibly Reporting?).

Backend roles would need to be supported in order for those plugins to adopt the mechanism provided by security.

Copy link

@nibix nibix Oct 3, 2024

Choose a reason for hiding this comment

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

Ah, so this has the goal of a seamless transition from the older methods used in these different plugins?

Still, from a UX point of view, having too many options for a single thing is not optimal. It requires users to make a choice which is the optimal option. Proper information on how to make the right choice might be hard to find or might even not exist.

This is actually demonstrated by the broad range of artifacts which require backend roles in their configuration.

Thus, maybe the backend role option should be marked as deprecated? Or, maybe the docs should be clearer on how to use the roles?

*
* @opensearch.experimental
*/
public class ShareWith implements ToXContentFragment {

private List<String> users;
Copy link
Member

Choose a reason for hiding this comment

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

I'm hesitant to introduce notions of roles, backend roles or user into the core. I'm wondering if Security can provide a class similar to this to plugins (similar to SPI model from JS), but not have plugins formally extending the security plugin. If a plugin extends another plugin then it means that the other plugin must be installed in a cluster before the plugin that depends on another can be installed.

With resource sharing, if the security plugin is not installed then all users will have full access to all plugin resources.

With the security plugin installed it can enforce authz on plugin resources using this new mechanism.


private List<String> roles;

private List<String> backendRoles;

public ShareWith(List<String> users, List<String> roles, List<String> backendRoles) {
this.users = users;
this.roles = roles;
this.backendRoles = backendRoles;
}

public List<String> getUsers() {
return users;
}

public void setUsers(List<String> users) {
this.users = users;
}

public List<String> getRoles() {
return roles;
}

public void setRoles(List<String> roles) {
this.roles = roles;
}

public List<String> getBackendRoles() {
return backendRoles;
}

public void setBackendRoles(List<String> backendRoles) {
this.backendRoles = backendRoles;
}

@Override
public String toString() {
return "ShareWith {" + "users=" + users + ", roles=" + roles + ", backendRoles=" + backendRoles + '}';
}

@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
return builder.startObject().field("users", users).field("roles", roles).field("backend_roles", backendRoles).endObject();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*/

/*
Copy link
Member

Choose a reason for hiding this comment

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

The License below can be removed

* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

/**
* Actions that OpenSearch can take either on the data stored on disk or on other nodes.
*/
/*
* Modifications Copyright OpenSearch Contributors. See
* GitHub history for details.
*/

/**
* This package defines all classes required for Resource Sharing and Access Control
*/
package org.opensearch.accesscontrol.resources;
Loading
Loading