diff --git a/CHANGELOG.md b/CHANGELOG.md index f5622a177ee6c..8ca282068ecb6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - New `phone` & `phone-search` analyzer + tokenizer ([#15915](https://github.com/opensearch-project/OpenSearch/pull/15915)) - Add _list/shards API as paginated alternate to _cat/shards ([#14641](https://github.com/opensearch-project/OpenSearch/pull/14641)) - Latency and Memory allocation improvements to Multi Term Aggregation queries ([#14993](https://github.com/opensearch-project/OpenSearch/pull/14993)) +- Add resource-level access control and sharing ([#16030](https://github.com/opensearch-project/OpenSearch/pull/16030)) ### Dependencies - Bump `com.azure:azure-identity` from 1.13.0 to 1.13.2 ([#15578](https://github.com/opensearch-project/OpenSearch/pull/15578)) diff --git a/server/src/main/java/org/opensearch/accesscontrol/resources/CreatedBy.java b/server/src/main/java/org/opensearch/accesscontrol/resources/CreatedBy.java new file mode 100644 index 0000000000000..d5c521e6c20f3 --- /dev/null +++ b/server/src/main/java/org/opensearch/accesscontrol/resources/CreatedBy.java @@ -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(); + } +} diff --git a/server/src/main/java/org/opensearch/accesscontrol/resources/EntityType.java b/server/src/main/java/org/opensearch/accesscontrol/resources/EntityType.java new file mode 100644 index 0000000000000..435172f4e5097 --- /dev/null +++ b/server/src/main/java/org/opensearch/accesscontrol/resources/EntityType.java @@ -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, +} diff --git a/server/src/main/java/org/opensearch/accesscontrol/resources/ResourceAccessScope.java b/server/src/main/java/org/opensearch/accesscontrol/resources/ResourceAccessScope.java new file mode 100644 index 0000000000000..463936625522c --- /dev/null +++ b/server/src/main/java/org/opensearch/accesscontrol/resources/ResourceAccessScope.java @@ -0,0 +1,21 @@ +/* + * 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 interface defines the two basic access scopes for resource-access. + * Each plugin must implement their own scopes and manage them + * These access scopes will then be used to verify the type of access being requested. + * + * @opensearch.experimental + */ +public interface ResourceAccessScope { + String READ_ONLY = "read_only"; + String READ_WRITE = "read_write"; +} diff --git a/server/src/main/java/org/opensearch/accesscontrol/resources/ResourceService.java b/server/src/main/java/org/opensearch/accesscontrol/resources/ResourceService.java new file mode 100644 index 0000000000000..1a5fd9c8d8701 --- /dev/null +++ b/server/src/main/java/org/opensearch/accesscontrol/resources/ResourceService.java @@ -0,0 +1,62 @@ +/* + * 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.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 resourcePlugins; + + public ResourceService(final List resourceACPlugins, List 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 listResourcePlugins() { + return resourcePlugins; + } +} diff --git a/server/src/main/java/org/opensearch/accesscontrol/resources/ResourceSharing.java b/server/src/main/java/org/opensearch/accesscontrol/resources/ResourceSharing.java new file mode 100644 index 0000000000000..f594bc790953b --- /dev/null +++ b/server/src/main/java/org/opensearch/accesscontrol/resources/ResourceSharing.java @@ -0,0 +1,116 @@ +/* + * 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 { + builder.startObject().field("source_idx", sourceIdx).field("resource_id", resourceId).field("created_by"); + createdBy.toXContent(builder, params); + if (shareWith != null && !shareWith.getSharedWithScopes().isEmpty()) { + builder.field("share_with"); + shareWith.toXContent(builder, params); + } + return builder.endObject(); + } +} diff --git a/server/src/main/java/org/opensearch/accesscontrol/resources/ShareWith.java b/server/src/main/java/org/opensearch/accesscontrol/resources/ShareWith.java new file mode 100644 index 0000000000000..e996933494dde --- /dev/null +++ b/server/src/main/java/org/opensearch/accesscontrol/resources/ShareWith.java @@ -0,0 +1,74 @@ +/* + * 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.common.io.stream.NamedWriteable; +import org.opensearch.core.common.io.stream.StreamOutput; +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 and at what scope. + * Here is a sample of what this would look like: + * "share_with": { + * "read_only": { + * "users": [], + * "roles": [], + * "backend_roles": [] + * }, + * "read_write": { + * "users": [], + * "roles": [], + * "backend_roles": [] + * } + * } + * + * @opensearch.experimental + */ +public class ShareWith implements ToXContentFragment, NamedWriteable { + + private final List sharedWithScopes; + + public ShareWith(List sharedWithScopes) { + this.sharedWithScopes = sharedWithScopes; + } + + public List getSharedWithScopes() { + return sharedWithScopes; + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + builder.startObject(); + + for (SharedWithScope scope : sharedWithScopes) { + scope.toXContent(builder, params); + } + + return builder.endObject(); + } + + @Override + public String getWriteableName() { + return "share_with"; + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + out.writeList(sharedWithScopes); + } + + @Override + public String toString() { + return "ShareWith " + sharedWithScopes; + } +} diff --git a/server/src/main/java/org/opensearch/accesscontrol/resources/SharedWithScope.java b/server/src/main/java/org/opensearch/accesscontrol/resources/SharedWithScope.java new file mode 100644 index 0000000000000..a471dc5300e58 --- /dev/null +++ b/server/src/main/java/org/opensearch/accesscontrol/resources/SharedWithScope.java @@ -0,0 +1,144 @@ +/* + * 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.common.io.stream.NamedWriteable; +import org.opensearch.core.common.io.stream.StreamOutput; +import org.opensearch.core.xcontent.ToXContentFragment; +import org.opensearch.core.xcontent.XContentBuilder; + +import java.io.IOException; +import java.util.List; + +/** + * Defines the scope and who this scope is shared with + * + * @opensearch.experimental + */ +public class SharedWithScope implements ToXContentFragment, NamedWriteable { + + private final String scope; + + private final SharedWithPerScope sharedWithPerScope; + + public SharedWithScope(String scope, SharedWithPerScope sharedWithPerScope) { + this.scope = scope; + this.sharedWithPerScope = sharedWithPerScope; + } + + public String getScope() { + return scope; + } + + public SharedWithPerScope getSharedWithPerScope() { + return sharedWithPerScope; + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + builder.field(scope); + builder.startObject(); + + sharedWithPerScope.toXContent(builder, params); + + return builder.endObject(); + } + + @Override + public String toString() { + return "{" + scope + ": " + sharedWithPerScope + '}'; + } + + @Override + public String getWriteableName() { + return "shared_with_scope"; + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + out.writeString(scope); + out.writeNamedWriteable(sharedWithPerScope); + } + + /** + * This class defines who a resource is shared_with for a particular scope + * + * @opensearch.experimental + */ + public static class SharedWithPerScope implements ToXContentFragment, NamedWriteable { + private List users; + + private List roles; + + private List backendRoles; + + public SharedWithPerScope(List users, List roles, List backendRoles) { + this.users = users; + this.roles = roles; + this.backendRoles = backendRoles; + } + + public List getUsers() { + return users; + } + + public void setUsers(List users) { + this.users = users; + } + + public List getRoles() { + return roles; + } + + public void setRoles(List roles) { + this.roles = roles; + } + + public List getBackendRoles() { + return backendRoles; + } + + public void setBackendRoles(List backendRoles) { + this.backendRoles = backendRoles; + } + + @Override + public String toString() { + return "{" + "users=" + users + ", roles=" + roles + ", backendRoles=" + backendRoles + '}'; + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + writeFieldOrEmptyArray(builder, "users", users); + writeFieldOrEmptyArray(builder, "roles", roles); + writeFieldOrEmptyArray(builder, "backend_roles", backendRoles); + return builder; + } + + private void writeFieldOrEmptyArray(XContentBuilder builder, String fieldName, List values) throws IOException { + if (values != null) { + builder.field(fieldName, values); + } else { + builder.array(fieldName); + } + } + + @Override + public String getWriteableName() { + return "shared_with_per_scope"; + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + out.writeStringArray(users.toArray(new String[0])); + out.writeStringArray(roles.toArray(new String[0])); + out.writeStringArray(backendRoles.toArray(new String[0])); + } + } +} diff --git a/server/src/main/java/org/opensearch/accesscontrol/resources/package-info.java b/server/src/main/java/org/opensearch/accesscontrol/resources/package-info.java new file mode 100644 index 0000000000000..b8ad5237a60ca --- /dev/null +++ b/server/src/main/java/org/opensearch/accesscontrol/resources/package-info.java @@ -0,0 +1,12 @@ +/* + * 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. + */ + +/** + * This package defines all classes required for Resource Sharing and Access Control + */ +package org.opensearch.accesscontrol.resources; diff --git a/server/src/main/java/org/opensearch/node/Node.java b/server/src/main/java/org/opensearch/node/Node.java index 584d95b9ff6b5..84249b96e2641 100644 --- a/server/src/main/java/org/opensearch/node/Node.java +++ b/server/src/main/java/org/opensearch/node/Node.java @@ -41,6 +41,7 @@ import org.opensearch.OpenSearchParseException; import org.opensearch.OpenSearchTimeoutException; import org.opensearch.Version; +import org.opensearch.accesscontrol.resources.ResourceService; import org.opensearch.action.ActionModule; import org.opensearch.action.ActionModule.DynamicActionRegistry; import org.opensearch.action.ActionType; @@ -213,6 +214,8 @@ import org.opensearch.plugins.Plugin; import org.opensearch.plugins.PluginsService; import org.opensearch.plugins.RepositoryPlugin; +import org.opensearch.plugins.ResourceAccessControlPlugin; +import org.opensearch.plugins.ResourcePlugin; import org.opensearch.plugins.ScriptPlugin; import org.opensearch.plugins.SearchPipelinePlugin; import org.opensearch.plugins.SearchPlugin; @@ -1089,6 +1092,12 @@ protected Node( ); modules.add(actionModule); + final List resourceAccessControlPlugins = pluginsService.filterPlugins( + ResourceAccessControlPlugin.class + ); + final List resourcePlugins = pluginsService.filterPlugins(ResourcePlugin.class); + ResourceService resourceService = new ResourceService(resourceAccessControlPlugins, resourcePlugins); + final RestController restController = actionModule.getRestController(); final NodeResourceUsageTracker nodeResourceUsageTracker = new NodeResourceUsageTracker( @@ -1491,6 +1500,7 @@ protected Node( b.bind(ResourceUsageCollectorService.class).toInstance(resourceUsageCollectorService); b.bind(SystemIndices.class).toInstance(systemIndices); b.bind(IdentityService.class).toInstance(identityService); + b.bind(ResourceService.class).toInstance(resourceService); b.bind(Tracer.class).toInstance(tracer); b.bind(SearchRequestStats.class).toInstance(searchRequestStats); b.bind(SearchRequestSlowLog.class).toInstance(searchRequestSlowLog); diff --git a/server/src/main/java/org/opensearch/plugins/NoOpResourceAccessControlPlugin.java b/server/src/main/java/org/opensearch/plugins/NoOpResourceAccessControlPlugin.java new file mode 100644 index 0000000000000..ad67ecc6e9ef1 --- /dev/null +++ b/server/src/main/java/org/opensearch/plugins/NoOpResourceAccessControlPlugin.java @@ -0,0 +1,88 @@ +/* + * 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.plugins; + +import org.opensearch.accesscontrol.resources.EntityType; +import org.opensearch.accesscontrol.resources.ResourceSharing; +import org.opensearch.accesscontrol.resources.ShareWith; + +import java.util.List; +import java.util.Map; + +/** + * This plugin class defines a no-op implementation of Resource Plugin. + * + * @opensearch.experimental + */ +public class NoOpResourceAccessControlPlugin implements ResourceAccessControlPlugin { + + /** + * Returns an empty list since security plugin is not defined. + * This method alone doesn't determine permissions. + * + * @return empty list + */ + @Override + public List listAccessibleResourcesInPlugin(String systemIndexName) { + // returns an empty list since security plugin is disabled + return List.of(); + } + + /** + * @param resourceId the resource on which access is to be checked + * @param systemIndexName where the resource exists + * @param scope the type of access being requested + * @return true + */ + @Override + public boolean hasPermission(String resourceId, String systemIndexName, String scope) { + return true; + } + + /** + * @param resourceId if of the resource to be updated + * @param systemIndexName index where this resource is defined + * @param shareWith a map that contains entries of entities with whom this resource should be shared with + * @return null since security plugin is disabled in the cluster + */ + @Override + public ResourceSharing shareWith(String resourceId, String systemIndexName, ShareWith shareWith) { + return null; + } + + /** + * @param resourceId if of the resource to be updated + * @param systemIndexName index where this resource is defined + * @param revokeAccess a map that contains entries of entities whose access should be revoked + * @return null since security plugin is disabled in the cluster + */ + @Override + public ResourceSharing revokeAccess(String resourceId, String systemIndexName, Map> revokeAccess) { + return null; + } + + /** + * @param resourceId if of the resource to be updated + * @param systemIndexName index where this resource is defined + * @return false since security plugin is disabled + */ + @Override + public boolean deleteResourceSharingRecord(String resourceId, String systemIndexName) { + return false; + } + + /** + * @return false since security plugin is disabled + */ + @Override + public boolean deleteAllResourceSharingRecordsForCurrentUser() { + return false; + } + +} diff --git a/server/src/main/java/org/opensearch/plugins/ResourceAccessControlPlugin.java b/server/src/main/java/org/opensearch/plugins/ResourceAccessControlPlugin.java new file mode 100644 index 0000000000000..379fee4be090b --- /dev/null +++ b/server/src/main/java/org/opensearch/plugins/ResourceAccessControlPlugin.java @@ -0,0 +1,84 @@ +/* + * 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.plugins; + +import org.opensearch.accesscontrol.resources.EntityType; +import org.opensearch.accesscontrol.resources.ResourceSharing; +import org.opensearch.accesscontrol.resources.ShareWith; + +import java.util.List; +import java.util.Map; + +/** + * This interface determines presence of security plugin in the cluster. + * If yes, security plugin will be used for resource access authorization + * User information is fetched from thread context by security plugin. + * In clusters, where security plugin is disabled these requests will be pass-through via a No-op implementation. + * There are 3 scope of sharing for a resource: Private, Restricted, Public. To learn more visit ... + * If security plugin is disabled, all resources will be considered public by default. + * TODO: add documentation around "how to use" + * + * @opensearch.experimental + */ +public interface ResourceAccessControlPlugin { + + /** + * Returns all accessible resources for current user for a given system . + * + * @return list of {@link ResourceSharing} items accessible by current user. + */ + List listAccessibleResourcesInPlugin(String systemIndex); + + /** + * Checks whether current user has permission to given resource. + * + * @param resourceId the resource on which access is to be checked + * @param systemIndexName where the resource exists + * @param scope the scope being requested + * @return true if current user has access, false otherwise + */ + boolean hasPermission(String resourceId, String systemIndexName, String scope); + + /** + * Adds an entity to the share-with. Resource needs to be in restricted mode. + * Creates a resource sharing record if one doesn't exist. + * @param resourceId id of the resource to be updated + * @param systemIndexName index where this resource is defined + * @param shareWith an object that contains entries of entities with whom the resource should be shared with + * @return updated resource sharing record + */ + ResourceSharing shareWith(String resourceId, String systemIndexName, ShareWith shareWith); + + /** + * Revokes given permission to a resource + * + * @param resourceId if of the resource to be updated + * @param systemIndexName index where this resource is defined + * @param revokeAccess a map that contains entries of entities whose access should be revoked + * @return the updated ResourceSharing record + */ + ResourceSharing revokeAccess(String resourceId, String systemIndexName, Map> revokeAccess); + + /** + * Deletes an entry from .resource_sharing index + * @param resourceId if of the resource to be updated + * @param systemIndexName index where this resource is defined + * @return true if resource record was deleted, false otherwise + */ + boolean deleteResourceSharingRecord(String resourceId, String systemIndexName); + + /** + * TODO check if this method is needed + * Deletes all entries from .resource_sharing index where current user is the creator of the resource + * @return true if resource record was deleted, false otherwise + */ + boolean deleteAllResourceSharingRecordsForCurrentUser(); + + // TODO: Check whether methods for bulk updates are required +} diff --git a/server/src/main/java/org/opensearch/plugins/ResourcePlugin.java b/server/src/main/java/org/opensearch/plugins/ResourcePlugin.java new file mode 100644 index 0000000000000..4fbbbf35fc367 --- /dev/null +++ b/server/src/main/java/org/opensearch/plugins/ResourcePlugin.java @@ -0,0 +1,29 @@ +/* + * 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.plugins; + +/** + * This interface should be implemented by all the plugins that define one or more resources. + * + * @opensearch.experimental + */ +public interface ResourcePlugin { + + /** + * Type of the resource + * @return a string containing the type of the resource + */ + String getResourceType(); + + /** + * The index where resource meta-data is stored + * @return the name of the parent index where resource meta-data is stored + */ + String getResourceIndex(); +}