diff --git a/build.gradle b/build.gradle index 00c003fc77..c7a129d471 100644 --- a/build.gradle +++ b/build.gradle @@ -394,7 +394,7 @@ opensearchplugin { name 'opensearch-security' description 'Provide access control related features for OpenSearch' classname 'org.opensearch.security.OpenSearchSecurityPlugin' - extendedPlugins = ['workload-management;optional=true', 'rule-framework'] + extendedPlugins = ['workload-management;optional=true', 'rule-framework', 'opensearch-dashboards'] } // This requires an additional Jar not published as part of build-tools @@ -688,6 +688,7 @@ dependencies { implementation "com.github.seancfoley:ipaddress:5.5.1" compileOnly "org.opensearch.plugin:workload-management-wlm-spi:${opensearch_version}" compileOnly "org.opensearch.plugin:autotagging-commons-spi:${opensearch_version}" + compileOnly "org.opensearch.plugin:opensearch-dashboards:${opensearch_version}" // Action privileges: check tables and compact collections implementation 'com.selectivem.collections:special-collections-complete:1.4.0' diff --git a/src/main/java/org/opensearch/security/configuration/PrivilegesInterceptorImpl.java b/src/main/java/org/opensearch/security/configuration/PrivilegesInterceptorImpl.java index e362c7a8eb..c9e632cace 100644 --- a/src/main/java/org/opensearch/security/configuration/PrivilegesInterceptorImpl.java +++ b/src/main/java/org/opensearch/security/configuration/PrivilegesInterceptorImpl.java @@ -46,6 +46,7 @@ import org.opensearch.cluster.metadata.IndexMetadata; import org.opensearch.cluster.metadata.IndexNameExpressionResolver; import org.opensearch.cluster.service.ClusterService; +import org.opensearch.dashboards.action.WriteAdvancedSettingsRequest; import org.opensearch.security.privileges.DashboardsMultiTenancyConfiguration; import org.opensearch.security.privileges.DocumentAllowList; import org.opensearch.security.privileges.PrivilegesEvaluationContext; @@ -141,7 +142,7 @@ public ReplaceResult replaceDashboardsIndex( && resolveToDashboardsIndexOrAlias(requestedResolved, dashboardsIndexName); final boolean isTraceEnabled = log.isTraceEnabled(); - TenantPrivileges.ActionType actionType = getActionTypeForAction(action); + TenantPrivileges.ActionType actionType = getActionTypeForAction(action, request); if (requestedTenant == null || requestedTenant.length() == 0) { if (isTraceEnabled) { @@ -232,7 +233,14 @@ private void applyDocumentAllowList(String indexName) { documentAllowList.applyTo(threadPool.getThreadContext()); } - static TenantPrivileges.ActionType getActionTypeForAction(String action) { + static TenantPrivileges.ActionType getActionTypeForAction(String action, ActionRequest request) { + if (request instanceof WriteAdvancedSettingsRequest wasa) { + if (wasa.isCreateOperation()) { + return TenantPrivileges.ActionType.READ; + } else { + return TenantPrivileges.ActionType.ADMIN; + } + } if (READ_ONLY_ALLOWED_ACTIONS.contains(action)) { return TenantPrivileges.ActionType.READ; } else { diff --git a/src/main/java/org/opensearch/security/privileges/DocumentAllowList.java b/src/main/java/org/opensearch/security/privileges/DocumentAllowList.java index 6e41857737..6684decf61 100644 --- a/src/main/java/org/opensearch/security/privileges/DocumentAllowList.java +++ b/src/main/java/org/opensearch/security/privileges/DocumentAllowList.java @@ -64,7 +64,7 @@ public boolean isEmpty() { } public void applyTo(ThreadContext threadContext) { - if (!isEmpty()) { + if (!isEmpty() && threadContext.getHeader(ConfigConstants.OPENDISTRO_SECURITY_DOC_ALLOWLIST_HEADER) != null) { threadContext.putHeader(ConfigConstants.OPENDISTRO_SECURITY_DOC_ALLOWLIST_HEADER, toString()); } } diff --git a/src/main/java/org/opensearch/security/privileges/TenantPrivileges.java b/src/main/java/org/opensearch/security/privileges/TenantPrivileges.java index 9320abfb45..9924ee1f9e 100644 --- a/src/main/java/org/opensearch/security/privileges/TenantPrivileges.java +++ b/src/main/java/org/opensearch/security/privileges/TenantPrivileges.java @@ -50,7 +50,8 @@ public class TenantPrivileges { */ public enum ActionType { READ, - WRITE; + WRITE, + ADMIN; } public static final TenantPrivileges EMPTY = new TenantPrivileges( @@ -61,6 +62,7 @@ public enum ActionType { private static final List READ = ImmutableList.of(ActionType.READ); private static final List READ_WRITE = ImmutableList.of(ActionType.READ, ActionType.WRITE); + private static final List READ_WRITE_ADMIN = ImmutableList.of(ActionType.READ, ActionType.WRITE, ActionType.ADMIN); private static final Logger log = LogManager.getLogger(TenantPrivileges.class); @@ -245,7 +247,9 @@ public Map tenantMap(PrivilegesEvaluationContext context) { static List resolveActionType(Collection allowedActions, FlattenedActionGroups actionGroups) { ImmutableSet permissions = actionGroups.resolve(allowedActions); - if (permissions.contains("kibana:saved_objects/*/write")) { + if (permissions.contains("osd:admin/advanced_settings/write")) { + return READ_WRITE_ADMIN; + } else if (permissions.contains("kibana:saved_objects/*/write")) { return READ_WRITE; } else { return READ; diff --git a/src/main/resources/static_config/static_action_groups.yml b/src/main/resources/static_config/static_action_groups.yml index e1d3e0aece..6d7588a9f8 100644 --- a/src/main/resources/static_config/static_action_groups.yml +++ b/src/main/resources/static_config/static_action_groups.yml @@ -8,14 +8,26 @@ kibana_all_write: static: true allowed_actions: - "kibana:saved_objects/*/write" + - "osd:admin/advanced_settings/get" + - "osd:admin/advanced_settings/write" type: "kibana" - description: "Allow writing in all OpenSearch Dashboards apps" + description: "Allow writing in all OpenSearch Dashboards apps including advanced settings" +kibana_only_write: + reserved: true + hidden: false + static: true + allowed_actions: + - "kibana:saved_objects/*/write" + - "osd:admin/advanced_settings/get" + type: "kibana" + description: "Allow writing in OpenSearch Dashboards apps except config (advanced settings)" kibana_all_read: reserved: true hidden: false static: true allowed_actions: - "kibana:saved_objects/*/read" + - "osd:admin/advanced_settings/get" type: "kibana" description: "Allow reading in all OpenSearch Dashboards apps" cluster_all: diff --git a/tools/install_demo_configuration.sh b/tools/install_demo_configuration.sh index d3a3ae8f75..e28414416a 100755 --- a/tools/install_demo_configuration.sh +++ b/tools/install_demo_configuration.sh @@ -61,4 +61,4 @@ if [ ! -x "$JAVA" ]; then exit 1 fi -"$JAVA" -Dorg.apache.logging.log4j.simplelog.StatusLogger.level=OFF -cp "$DIR/../*:$DIR/../../../lib/*:$DIR/../deps/*" org.opensearch.security.tools.democonfig.Installer "$DIR" "$@" 2>/dev/null +"$JAVA" -Dorg.apache.logging.log4j.simplelog.StatusLogger.level=OFF -cp "$DIR/../*:$OPENSEARCH_HOME/lib/*:$OPENSEARCH_HOME/modules/opensearch-dashboards/*" org.opensearch.security.tools.democonfig.Installer "$DIR" "$@" 2>/dev/null