Skip to content

Commit a5ded4b

Browse files
Introduces resource sharing model as a feature flag
Signed-off-by: Darshit Chanpura <dchanp@amazon.com>
1 parent d2a30d8 commit a5ded4b

12 files changed

+124
-28
lines changed

build.gradle

+2-1
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ dependencies {
115115
implementation "org.opensearch:opensearch:${opensearch_version}"
116116
compileOnly "org.opensearch.plugin:opensearch-scripting-painless-spi:${opensearch_version}"
117117
compileOnly "org.opensearch:opensearch-job-scheduler-spi:${job_scheduler_version}"
118+
compileOnly "org.opensearch:opensearch-resource-sharing-spi:${opensearch_build}"
118119
implementation "org.opensearch:common-utils:${common_utils_version}"
119120
implementation "org.opensearch.client:opensearch-rest-client:${opensearch_version}"
120121
compileOnly group: 'com.google.guava', name: 'guava', version:'32.1.3-jre'
@@ -205,7 +206,7 @@ opensearchplugin {
205206
name 'opensearch-anomaly-detection'
206207
description 'OpenSearch anomaly detector plugin'
207208
classname 'org.opensearch.timeseries.TimeSeriesAnalyticsPlugin'
208-
extendedPlugins = ['lang-painless', 'opensearch-job-scheduler']
209+
extendedPlugins = ['lang-painless', 'opensearch-job-scheduler', 'opensearch-security;optional=true']
209210
}
210211

211212
// Handle case where older versions of esplugin doesn't expose the joda time version it uses
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package org.opensearch.ad.constant;
2+
3+
import org.opensearch.security.spi.resources.ResourceAccessScope;
4+
5+
public enum ADResourceScope implements ResourceAccessScope<ADResourceScope> {
6+
AD_READ_ACCESS("ad_read_access"),
7+
AD_FULL_ACCESS("ad_full_access");
8+
9+
private final String scopeName;
10+
11+
ADResourceScope(String scopeName) {
12+
this.scopeName = scopeName;
13+
}
14+
15+
@Override
16+
public String value() {
17+
return scopeName;
18+
}
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package org.opensearch.ad.constant;
2+
3+
public class ConfigConstants {
4+
public static final String OPENSEARCH_RESOURCE_SHARING_ENABLED = "plugins.security.resource_sharing.enabled";
5+
public static final Boolean OPENSEARCH_RESOURCE_SHARING_ENABLED_DEFAULT = true;
6+
}

src/main/java/org/opensearch/ad/transport/IndexAnomalyDetectorTransportAction.java

+12-4
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.opensearch.action.support.ActionFilters;
2828
import org.opensearch.action.support.HandledTransportAction;
2929
import org.opensearch.action.support.WriteRequest;
30+
import org.opensearch.ad.constant.ConfigConstants;
3031
import org.opensearch.ad.indices.ADIndexManagement;
3132
import org.opensearch.ad.model.AnomalyDetector;
3233
import org.opensearch.ad.rest.handler.IndexAnomalyDetectorActionHandler;
@@ -64,6 +65,7 @@ public class IndexAnomalyDetectorTransportAction extends HandledTransportAction<
6465
private volatile Boolean filterByEnabled;
6566
private final SearchFeatureDao searchFeatureDao;
6667
private final Settings settings;
68+
private final boolean resourceSharingEnabled;
6769

6870
@Inject
6971
public IndexAnomalyDetectorTransportAction(
@@ -90,6 +92,8 @@ public IndexAnomalyDetectorTransportAction(
9092
filterByEnabled = AnomalyDetectorSettings.AD_FILTER_BY_BACKEND_ROLES.get(settings);
9193
clusterService.getClusterSettings().addSettingsUpdateConsumer(AD_FILTER_BY_BACKEND_ROLES, it -> filterByEnabled = it);
9294
this.settings = settings;
95+
this.resourceSharingEnabled = settings
96+
.getAsBoolean(ConfigConstants.OPENSEARCH_RESOURCE_SHARING_ENABLED, ConfigConstants.OPENSEARCH_RESOURCE_SHARING_ENABLED_DEFAULT);
9397
}
9498

9599
@Override
@@ -115,9 +119,10 @@ private void resolveUserAndExecute(
115119
Consumer<AnomalyDetector> function
116120
) {
117121
try {
118-
// Check if user has backend roles
119-
// When filter by is enabled, block users creating/updating detectors who do not have backend roles.
120-
if (filterByEnabled) {
122+
// If resource sharing flag is enabled then access evaluation will be performed at DLS level
123+
if (!resourceSharingEnabled && filterByEnabled) {
124+
// Check if user has backend roles
125+
// When filter by is enabled, block users creating/updating detectors who do not have backend roles.
121126
String error = checkFilterByBackendRoles(requestedUser);
122127
if (error != null) {
123128
listener.onFailure(new TimeSeriesException(error));
@@ -140,7 +145,8 @@ private void resolveUserAndExecute(
140145
clusterService,
141146
xContentRegistry,
142147
filterByBackendRole,
143-
AnomalyDetector.class
148+
AnomalyDetector.class,
149+
resourceSharingEnabled
144150
);
145151
} else {
146152
// Create Detector. No need to get current detector.
@@ -175,6 +181,8 @@ protected void adExecute(
175181
checkIndicesAndExecute(detector.getIndices(), () -> {
176182
// Don't replace detector's user when update detector
177183
// Github issue: https://github.com/opensearch-project/anomaly-detection/issues/124
184+
// TODO this and similar code should be updated to remove reference to a user
185+
178186
User detectorUser = currentDetector == null ? user : currentDetector.getUser();
179187
IndexAnomalyDetectorActionHandler indexAnomalyDetectorActionHandler = new IndexAnomalyDetectorActionHandler(
180188
clusterService,

src/main/java/org/opensearch/ad/transport/PreviewAnomalyDetectorTransportAction.java

+6-1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import org.opensearch.action.support.HandledTransportAction;
3535
import org.opensearch.ad.AnomalyDetectorRunner;
3636
import org.opensearch.ad.constant.ADCommonMessages;
37+
import org.opensearch.ad.constant.ConfigConstants;
3738
import org.opensearch.ad.model.AnomalyDetector;
3839
import org.opensearch.ad.model.AnomalyResult;
3940
import org.opensearch.ad.settings.AnomalyDetectorSettings;
@@ -70,6 +71,7 @@ public class PreviewAnomalyDetectorTransportAction extends
7071
private volatile Boolean filterByEnabled;
7172
private final CircuitBreakerService adCircuitBreakerService;
7273
private Semaphore lock;
74+
private final boolean resourceSharingEnabled;
7375

7476
@Inject
7577
public PreviewAnomalyDetectorTransportAction(
@@ -93,6 +95,8 @@ public PreviewAnomalyDetectorTransportAction(
9395
clusterService.getClusterSettings().addSettingsUpdateConsumer(AD_FILTER_BY_BACKEND_ROLES, it -> filterByEnabled = it);
9496
this.adCircuitBreakerService = adCircuitBreakerService;
9597
this.lock = new Semaphore(MAX_CONCURRENT_PREVIEW.get(settings), true);
98+
this.resourceSharingEnabled = settings
99+
.getAsBoolean(ConfigConstants.OPENSEARCH_RESOURCE_SHARING_ENABLED, ConfigConstants.OPENSEARCH_RESOURCE_SHARING_ENABLED_DEFAULT);
96100
clusterService.getClusterSettings().addSettingsUpdateConsumer(MAX_CONCURRENT_PREVIEW, it -> { lock = new Semaphore(it); });
97101
}
98102

@@ -115,7 +119,8 @@ protected void doExecute(
115119
client,
116120
clusterService,
117121
xContentRegistry,
118-
AnomalyDetector.class
122+
AnomalyDetector.class,
123+
resourceSharingEnabled
119124
);
120125
} catch (Exception e) {
121126
logger.error(e);

src/main/java/org/opensearch/forecast/transport/ForecastRunOnceTransportAction.java

+6-1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.opensearch.action.search.SearchRequest;
2626
import org.opensearch.action.support.ActionFilters;
2727
import org.opensearch.action.support.HandledTransportAction;
28+
import org.opensearch.ad.constant.ConfigConstants;
2829
import org.opensearch.client.Client;
2930
import org.opensearch.cluster.metadata.IndexNameExpressionResolver;
3031
import org.opensearch.cluster.service.ClusterService;
@@ -97,6 +98,7 @@ public class ForecastRunOnceTransportAction extends HandledTransportAction<Forec
9798
private final FeatureManager featureManager;
9899
private final ForecastStats forecastStats;
99100
private volatile Boolean filterByEnabled;
101+
private final boolean resourceSharingEnabled;
100102

101103
protected volatile Integer maxSingleStreamForecasters;
102104
protected volatile Integer maxHCForecasters;
@@ -147,6 +149,8 @@ public ForecastRunOnceTransportAction(
147149
this.maxHCForecasters = MAX_HC_FORECASTERS.get(settings);
148150
this.maxForecastFeatures = MAX_FORECAST_FEATURES;
149151
this.maxCategoricalFields = ForecastNumericSetting.maxCategoricalFields();
152+
this.resourceSharingEnabled = settings
153+
.getAsBoolean(ConfigConstants.OPENSEARCH_RESOURCE_SHARING_ENABLED, ConfigConstants.OPENSEARCH_RESOURCE_SHARING_ENABLED_DEFAULT);
150154
clusterService.getClusterSettings().addSettingsUpdateConsumer(MAX_SINGLE_STREAM_FORECASTERS, it -> maxSingleStreamForecasters = it);
151155
clusterService.getClusterSettings().addSettingsUpdateConsumer(MAX_HC_FORECASTERS, it -> maxHCForecasters = it);
152156
}
@@ -166,7 +170,8 @@ protected void doExecute(Task task, ForecastResultRequest request, ActionListene
166170
client,
167171
clusterService,
168172
xContentRegistry,
169-
Forecaster.class
173+
Forecaster.class,
174+
resourceSharingEnabled
170175
);
171176
} catch (Exception e) {
172177
LOG.error(e);

src/main/java/org/opensearch/forecast/transport/IndexForecasterTransportAction.java

+10-4
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import org.opensearch.action.support.ActionFilters;
2929
import org.opensearch.action.support.HandledTransportAction;
3030
import org.opensearch.action.support.WriteRequest;
31+
import org.opensearch.ad.constant.ConfigConstants;
3132
import org.opensearch.client.Client;
3233
import org.opensearch.cluster.service.ClusterService;
3334
import org.opensearch.common.inject.Inject;
@@ -63,6 +64,7 @@ public class IndexForecasterTransportAction extends HandledTransportAction<Index
6364
private final SearchFeatureDao searchFeatureDao;
6465
private final ForecastTaskManager taskManager;
6566
private final Settings settings;
67+
private final boolean resourceSharingEnabled;
6668

6769
@Inject
6870
public IndexForecasterTransportAction(
@@ -89,6 +91,8 @@ public IndexForecasterTransportAction(
8991
this.searchFeatureDao = searchFeatureDao;
9092
this.taskManager = taskManager;
9193
this.settings = settings;
94+
this.resourceSharingEnabled = settings
95+
.getAsBoolean(ConfigConstants.OPENSEARCH_RESOURCE_SHARING_ENABLED, ConfigConstants.OPENSEARCH_RESOURCE_SHARING_ENABLED_DEFAULT);
9296
}
9397

9498
@Override
@@ -125,9 +129,10 @@ private void resolveUserAndExecute(
125129
// this case, so we can keep current forecaster's user data.
126130
boolean filterByBackendRole = requestedUser == null ? false : filterByEnabled;
127131

128-
// Check if user has backend roles
129-
// When filter by is enabled, block users creating/updating detectors who do not have backend roles.
130-
if (filterByEnabled) {
132+
// If resource sharing flag is enabled then access evaluation will be performed at DLS level
133+
if (!resourceSharingEnabled && filterByEnabled) {
134+
// Check if user has backend roles
135+
// When filter by is enabled, block users creating/updating detectors who do not have backend roles.
131136
String error = checkFilterByBackendRoles(requestedUser);
132137
if (error != null) {
133138
listener.onFailure(new IllegalArgumentException(error));
@@ -146,7 +151,8 @@ private void resolveUserAndExecute(
146151
clusterService,
147152
xContentRegistry,
148153
filterByBackendRole,
149-
Forecaster.class
154+
Forecaster.class,
155+
resourceSharingEnabled
150156
);
151157
} else {
152158
// Create Detector. No need to get current detector.

src/main/java/org/opensearch/timeseries/TimeSeriesAnalyticsPlugin.java

+18-1
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,7 @@
275275
import org.opensearch.rest.RestController;
276276
import org.opensearch.rest.RestHandler;
277277
import org.opensearch.script.ScriptService;
278+
import org.opensearch.security.spi.resources.ResourceSharingExtension;
278279
import org.opensearch.threadpool.ExecutorBuilder;
279280
import org.opensearch.threadpool.ScalingExecutorBuilder;
280281
import org.opensearch.threadpool.ThreadPool;
@@ -327,7 +328,13 @@
327328
/**
328329
* Entry point of time series analytics plugin.
329330
*/
330-
public class TimeSeriesAnalyticsPlugin extends Plugin implements ActionPlugin, ScriptPlugin, SystemIndexPlugin, JobSchedulerExtension {
331+
public class TimeSeriesAnalyticsPlugin extends Plugin
332+
implements
333+
ActionPlugin,
334+
ScriptPlugin,
335+
SystemIndexPlugin,
336+
JobSchedulerExtension,
337+
ResourceSharingExtension {
331338

332339
private static final Logger LOG = LogManager.getLogger(TimeSeriesAnalyticsPlugin.class);
333340

@@ -1758,4 +1765,14 @@ public void close() {
17581765
}
17591766
}
17601767
}
1768+
1769+
@Override
1770+
public String getResourceType() {
1771+
return "detectors";
1772+
}
1773+
1774+
@Override
1775+
public String getResourceIndex() {
1776+
return CommonName.CONFIG_INDEX;
1777+
}
17611778
}

src/main/java/org/opensearch/timeseries/transport/BaseDeleteConfigTransportAction.java

+6-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.opensearch.action.support.ActionFilters;
2525
import org.opensearch.action.support.HandledTransportAction;
2626
import org.opensearch.action.support.WriteRequest;
27+
import org.opensearch.ad.constant.ConfigConstants;
2728
import org.opensearch.ad.model.ADTask;
2829
import org.opensearch.client.Client;
2930
import org.opensearch.cluster.service.ClusterService;
@@ -69,6 +70,7 @@ public abstract class BaseDeleteConfigTransportAction<TaskCacheManagerType exten
6970
private final String stateIndex;
7071
private final Class<ConfigType> configTypeClass;
7172
private final List<TaskTypeEnum> batchTaskTypes;
73+
private final boolean resourceSharingEnabled;
7274

7375
public BaseDeleteConfigTransportAction(
7476
TransportService transportService,
@@ -100,6 +102,8 @@ public BaseDeleteConfigTransportAction(
100102
this.stateIndex = stateIndex;
101103
this.configTypeClass = configTypeClass;
102104
this.batchTaskTypes = historicalTaskTypes;
105+
this.resourceSharingEnabled = settings
106+
.getAsBoolean(ConfigConstants.OPENSEARCH_RESOURCE_SHARING_ENABLED, ConfigConstants.OPENSEARCH_RESOURCE_SHARING_ENABLED_DEFAULT);
103107
}
104108

105109
@Override
@@ -142,7 +146,8 @@ protected void doExecute(Task task, DeleteConfigRequest request, ActionListener<
142146
client,
143147
clusterService,
144148
xContentRegistry,
145-
configTypeClass
149+
configTypeClass,
150+
resourceSharingEnabled
146151
);
147152
} catch (Exception e) {
148153
LOG.error(e);

src/main/java/org/opensearch/timeseries/transport/BaseGetConfigTransportAction.java

+6-1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import org.opensearch.action.get.MultiGetResponse;
3232
import org.opensearch.action.support.ActionFilters;
3333
import org.opensearch.action.support.HandledTransportAction;
34+
import org.opensearch.ad.constant.ConfigConstants;
3435
import org.opensearch.client.Client;
3536
import org.opensearch.cluster.service.ClusterService;
3637
import org.opensearch.common.CheckedConsumer;
@@ -101,6 +102,7 @@ public abstract class BaseGetConfigTransportAction<GetConfigResponseType extends
101102
private final String singleStreamHistoricalTaskname;
102103
private final String hcHistoricalTaskName;
103104
private final TaskProfileRunnerType taskProfileRunner;
105+
private final boolean resourceSharingEnabled;
104106

105107
public BaseGetConfigTransportAction(
106108
TransportService transportService,
@@ -154,6 +156,8 @@ public BaseGetConfigTransportAction(
154156
this.hcHistoricalTaskName = hcHistoricalTaskName;
155157
this.singleStreamHistoricalTaskname = singleStreamHistoricalTaskname;
156158
this.taskProfileRunner = taskProfileRunner;
159+
this.resourceSharingEnabled = settings
160+
.getAsBoolean(ConfigConstants.OPENSEARCH_RESOURCE_SHARING_ENABLED, ConfigConstants.OPENSEARCH_RESOURCE_SHARING_ENABLED_DEFAULT);
157161
}
158162

159163
@Override
@@ -172,7 +176,8 @@ public void doExecute(Task task, ActionRequest request, ActionListener<GetConfig
172176
client,
173177
clusterService,
174178
xContentRegistry,
175-
configTypeClass
179+
configTypeClass,
180+
resourceSharingEnabled
176181
);
177182
} catch (Exception e) {
178183
LOG.error(e);

src/main/java/org/opensearch/timeseries/transport/BaseJobTransportAction.java

+6-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import org.opensearch.action.ActionType;
1414
import org.opensearch.action.support.ActionFilters;
1515
import org.opensearch.action.support.HandledTransportAction;
16+
import org.opensearch.ad.constant.ConfigConstants;
1617
import org.opensearch.client.Client;
1718
import org.opensearch.cluster.service.ClusterService;
1819
import org.opensearch.common.settings.Setting;
@@ -53,6 +54,7 @@ public abstract class BaseJobTransportAction<IndexType extends Enum<IndexType> &
5354
private final String failtoStopMsg;
5455
private final Class<? extends Config> configClass;
5556
private final IndexJobActionHandlerType indexJobActionHandlerType;
57+
private final boolean resourceSharingEnabled;
5658

5759
public BaseJobTransportAction(
5860
TransportService transportService,
@@ -82,6 +84,8 @@ public BaseJobTransportAction(
8284
this.failtoStopMsg = failtoStopMsg;
8385
this.configClass = configClass;
8486
this.indexJobActionHandlerType = indexJobActionHandlerType;
87+
this.resourceSharingEnabled = settings
88+
.getAsBoolean(ConfigConstants.OPENSEARCH_RESOURCE_SHARING_ENABLED, ConfigConstants.OPENSEARCH_RESOURCE_SHARING_ENABLED_DEFAULT);
8589
}
8690

8791
@Override
@@ -106,7 +110,8 @@ protected void doExecute(Task task, JobRequest request, ActionListener<JobRespon
106110
client,
107111
clusterService,
108112
xContentRegistry,
109-
configClass
113+
configClass,
114+
resourceSharingEnabled
110115
);
111116
} catch (Exception e) {
112117
logger.error(e);

0 commit comments

Comments
 (0)