Skip to content

Commit 1e57062

Browse files
authored
Allow read template with cluster monitor privilege (#82046)
All three template types (legacy templates, composable index templates and component templates) are stored in cluster state metadata (in fields "templates", "index_template" and "component_template"). This cluster state is readable (via GET /_cluster/state) for users who have the monitor privilege at the cluster level. However, calling the explicit read endpoints for these templates required the manage_index_templates privilege. This change grants access to the template specific retrieval APIs for all users (or API Keys) with the cluster monitor privilege so that they can make use of these fit-for-purpose APIs instead of parsing data directly from cluster metadata Relates: elastic/beats#29554 Relates: #78832
1 parent 57ac810 commit 1e57062

File tree

4 files changed

+33
-2
lines changed

4 files changed

+33
-2
lines changed

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/privilege/ClusterPrivilegeResolver.java

+9-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515
import org.elasticsearch.action.admin.cluster.snapshots.get.GetSnapshotsAction;
1616
import org.elasticsearch.action.admin.cluster.snapshots.status.SnapshotsStatusAction;
1717
import org.elasticsearch.action.admin.cluster.state.ClusterStateAction;
18+
import org.elasticsearch.action.admin.indices.template.get.GetComponentTemplateAction;
19+
import org.elasticsearch.action.admin.indices.template.get.GetComposableIndexTemplateAction;
20+
import org.elasticsearch.action.admin.indices.template.get.GetIndexTemplatesAction;
1821
import org.elasticsearch.action.ingest.GetPipelineAction;
1922
import org.elasticsearch.action.ingest.SimulatePipelineAction;
2023
import org.elasticsearch.common.Strings;
@@ -64,7 +67,12 @@ public class ClusterPrivilegeResolver {
6467
private static final Set<String> MANAGE_API_KEY_PATTERN = Set.of("cluster:admin/xpack/security/api_key/*");
6568
private static final Set<String> MANAGE_SERVICE_ACCOUNT_PATTERN = Set.of("cluster:admin/xpack/security/service_account/*");
6669
private static final Set<String> GRANT_API_KEY_PATTERN = Set.of(GrantApiKeyAction.NAME + "*");
67-
private static final Set<String> MONITOR_PATTERN = Set.of("cluster:monitor/*");
70+
private static final Set<String> MONITOR_PATTERN = Set.of(
71+
"cluster:monitor/*",
72+
GetIndexTemplatesAction.NAME,
73+
GetComponentTemplateAction.NAME,
74+
GetComposableIndexTemplateAction.NAME
75+
);
6876
private static final Set<String> MONITOR_ML_PATTERN = Set.of("cluster:monitor/xpack/ml/*");
6977
private static final Set<String> MONITOR_TEXT_STRUCTURE_PATTERN = Set.of("cluster:monitor/text_structure/*");
7078
private static final Set<String> MONITOR_TRANSFORM_PATTERN = Set.of("cluster:monitor/data_frame/*", "cluster:monitor/transform/*");

x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authz/privilege/ClusterPrivilegeTests.java

+15
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,31 @@
88
package org.elasticsearch.xpack.core.security.authz.privilege;
99

1010
import org.elasticsearch.action.ActionType;
11+
import org.elasticsearch.action.admin.indices.template.get.GetComponentTemplateAction;
12+
import org.elasticsearch.action.admin.indices.template.get.GetComposableIndexTemplateAction;
13+
import org.elasticsearch.action.admin.indices.template.get.GetIndexTemplatesAction;
1114
import org.elasticsearch.test.ESTestCase;
1215
import org.elasticsearch.xpack.core.enrich.action.EnrichStatsAction;
1316
import org.elasticsearch.xpack.core.security.authz.permission.ClusterPermission;
1417

18+
import java.util.List;
19+
1520
public class ClusterPrivilegeTests extends ESTestCase {
1621

1722
public void testMonitorPrivilegeWillGrantActions() {
1823
assertGranted(ClusterPrivilegeResolver.MONITOR, EnrichStatsAction.INSTANCE);
1924
}
2025

26+
public void testMonitorPrivilegeGrantsGetTemplateActions() {
27+
for (var action : List.of(
28+
GetComponentTemplateAction.INSTANCE,
29+
GetComposableIndexTemplateAction.INSTANCE,
30+
GetIndexTemplatesAction.INSTANCE
31+
)) {
32+
assertGranted(ClusterPrivilegeResolver.MONITOR, action);
33+
}
34+
}
35+
2136
public static void assertGranted(ClusterPrivilege clusterPrivilege, ActionType<?> actionType) {
2237
assertTrue(clusterPrivilege.buildPermission(ClusterPermission.builder()).build().check(actionType.name(), null, null));
2338
}

x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authz/store/ReservedRolesStoreTests.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -1204,7 +1204,7 @@ public void testRemoteMonitoringCollectorRole() {
12041204
assertThat(remoteMonitoringCollectorRole.cluster().check(ClusterHealthAction.NAME, request, authentication), is(true));
12051205
assertThat(remoteMonitoringCollectorRole.cluster().check(ClusterStateAction.NAME, request, authentication), is(true));
12061206
assertThat(remoteMonitoringCollectorRole.cluster().check(ClusterStatsAction.NAME, request, authentication), is(true));
1207-
assertThat(remoteMonitoringCollectorRole.cluster().check(GetIndexTemplatesAction.NAME, request, authentication), is(false));
1207+
assertThat(remoteMonitoringCollectorRole.cluster().check(GetIndexTemplatesAction.NAME, request, authentication), is(true));
12081208
assertThat(remoteMonitoringCollectorRole.cluster().check(PutIndexTemplateAction.NAME, request, authentication), is(false));
12091209
assertThat(remoteMonitoringCollectorRole.cluster().check(DeleteIndexTemplateAction.NAME, request, authentication), is(false));
12101210
assertThat(remoteMonitoringCollectorRole.cluster().check(ClusterRerouteAction.NAME, request, authentication), is(false));

x-pack/plugin/security/src/internalClusterTest/java/org/elasticsearch/integration/ClusterPrivilegeIntegrationTests.java

+8
Original file line numberDiff line numberDiff line change
@@ -127,9 +127,17 @@ public void testThatClusterPrivilegesWorkAsExpectedViaHttp() throws Exception {
127127
assertAccessIsAllowed("user_b", "GET", "/_nodes/stats");
128128
assertAccessIsAllowed("user_b", "GET", "/_nodes/hot_threads");
129129
assertAccessIsAllowed("user_b", "GET", "/_nodes/infos");
130+
// monitoring allows template retrieval (because it's implied by having read access to cluster state
131+
assertAccessIsAllowed("user_b", "GET", "/_cat/templates/" + (randomBoolean() ? "" : randomAlphaOfLengthBetween(2, 8)));
132+
assertAccessIsAllowed("user_b", "GET", "/_template/");
133+
assertAccessIsAllowed("user_b", "GET", "/_index_template/");
134+
assertAccessIsAllowed("user_b", "GET", "/_component_template/");
130135
// but no admin stuff
131136
assertAccessIsDenied("user_b", "POST", "/_cluster/reroute");
132137
assertAccessIsDenied("user_b", "PUT", "/_cluster/settings", "{ \"transient\" : { \"search.default_search_timeout\": \"1m\" } }");
138+
assertAccessIsDenied("user_b", "DELETE", "/_template/" + randomAlphaOfLengthBetween(2, 8));
139+
assertAccessIsDenied("user_b", "DELETE", "/_index_template/" + randomAlphaOfLengthBetween(2, 8));
140+
assertAccessIsDenied("user_b", "DELETE", "/_component_template/" + randomAlphaOfLengthBetween(2, 8));
133141

134142
// sorry user_c, you are not allowed anything
135143
assertAccessIsDenied("user_c", "GET", "/_cluster/state");

0 commit comments

Comments
 (0)