Skip to content

Commit 89469aa

Browse files
committed
Add ILM-specific security privileges (#36493)
* add read_ilm cluster privilege Although managing ILM policies is best done using the "manage" cluster privilege, it is useful to have read-only views. * adds `read_ilm` cluster privilege for viewing policies and status * adds Explain API to the `view_index_metadata` index privilege * add manage_ilm privileges
1 parent 7c3dcec commit 89469aa

File tree

6 files changed

+83
-4
lines changed

6 files changed

+83
-4
lines changed

client/rest-high-level/src/main/java/org/elasticsearch/client/security/user/privileges/Role.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -315,9 +315,11 @@ public static class ClusterPrivilegeName {
315315
public static final String MANAGE_PIPELINE = "manage_pipeline";
316316
public static final String MANAGE_CCR = "manage_ccr";
317317
public static final String READ_CCR = "read_ccr";
318+
public static final String MANAGE_ILM = "manage_ilm";
319+
public static final String READ_ILM = "read_ilm";
318320
public static final String[] ALL_ARRAY = new String[] { NONE, ALL, MONITOR, MONITOR_ML, MONITOR_WATCHER, MONITOR_ROLLUP, MANAGE,
319321
MANAGE_ML, MANAGE_WATCHER, MANAGE_ROLLUP, MANAGE_INDEX_TEMPLATES, MANAGE_INGEST_PIPELINES, TRANSPORT_CLIENT,
320-
MANAGE_SECURITY, MANAGE_SAML, MANAGE_TOKEN, MANAGE_PIPELINE, MANAGE_CCR, READ_CCR };
322+
MANAGE_SECURITY, MANAGE_SAML, MANAGE_TOKEN, MANAGE_PIPELINE, MANAGE_CCR, READ_CCR, MANAGE_ILM, READ_ILM };
321323
}
322324

323325
/**
@@ -338,8 +340,9 @@ public static class IndexPrivilegeName {
338340
public static final String CREATE_INDEX = "create_index";
339341
public static final String VIEW_INDEX_METADATA = "view_index_metadata";
340342
public static final String MANAGE_FOLLOW_INDEX = "manage_follow_index";
343+
public static final String MANAGE_ILM = "manage_ilm";
341344
public static final String[] ALL_ARRAY = new String[] { NONE, ALL, READ, READ_CROSS, CREATE, INDEX, DELETE, WRITE, MONITOR, MANAGE,
342-
DELETE_INDEX, CREATE_INDEX, VIEW_INDEX_METADATA, MANAGE_FOLLOW_INDEX };
345+
DELETE_INDEX, CREATE_INDEX, VIEW_INDEX_METADATA, MANAGE_FOLLOW_INDEX, MANAGE_ILM };
343346
}
344347

345348
}

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
import org.elasticsearch.action.admin.cluster.state.ClusterStateAction;
1010
import org.elasticsearch.common.Strings;
1111
import org.elasticsearch.common.collect.MapBuilder;
12+
import org.elasticsearch.xpack.core.indexlifecycle.action.GetLifecycleAction;
13+
import org.elasticsearch.xpack.core.indexlifecycle.action.GetStatusAction;
1214
import org.elasticsearch.xpack.core.security.action.token.InvalidateTokenAction;
1315
import org.elasticsearch.xpack.core.security.action.token.RefreshTokenAction;
1416
import org.elasticsearch.xpack.core.security.action.user.HasPrivilegesAction;
@@ -47,6 +49,8 @@ public final class ClusterPrivilege extends Privilege {
4749
private static final Automaton MANAGE_CCR_AUTOMATON =
4850
patterns("cluster:admin/xpack/ccr/*", ClusterStateAction.NAME, HasPrivilegesAction.NAME);
4951
private static final Automaton READ_CCR_AUTOMATON = patterns(ClusterStateAction.NAME, HasPrivilegesAction.NAME);
52+
private static final Automaton MANAGE_ILM_AUTOMATON = patterns("cluster:admin/ilm/*");
53+
private static final Automaton READ_ILM_AUTOMATON = patterns(GetLifecycleAction.NAME, GetStatusAction.NAME);
5054

5155
public static final ClusterPrivilege NONE = new ClusterPrivilege("none", Automatons.EMPTY);
5256
public static final ClusterPrivilege ALL = new ClusterPrivilege("all", ALL_CLUSTER_AUTOMATON);
@@ -69,6 +73,8 @@ public final class ClusterPrivilege extends Privilege {
6973
public static final ClusterPrivilege MANAGE_PIPELINE = new ClusterPrivilege("manage_pipeline", "cluster:admin/ingest/pipeline/*");
7074
public static final ClusterPrivilege MANAGE_CCR = new ClusterPrivilege("manage_ccr", MANAGE_CCR_AUTOMATON);
7175
public static final ClusterPrivilege READ_CCR = new ClusterPrivilege("read_ccr", READ_CCR_AUTOMATON);
76+
public static final ClusterPrivilege MANAGE_ILM = new ClusterPrivilege("manage_ilm", MANAGE_ILM_AUTOMATON);
77+
public static final ClusterPrivilege READ_ILM = new ClusterPrivilege("read_ilm", READ_ILM_AUTOMATON);
7278

7379
public static final Predicate<String> ACTION_MATCHER = ClusterPrivilege.ALL.predicate();
7480

@@ -92,6 +98,8 @@ public final class ClusterPrivilege extends Privilege {
9298
.put("manage_rollup", MANAGE_ROLLUP)
9399
.put("manage_ccr", MANAGE_CCR)
94100
.put("read_ccr", READ_CCR)
101+
.put("manage_ilm", MANAGE_ILM)
102+
.put("read_ilm", READ_ILM)
95103
.immutableMap();
96104

97105
private static final ConcurrentHashMap<Set<String>, ClusterPrivilege> CACHE = new ConcurrentHashMap<>();

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.elasticsearch.common.collect.MapBuilder;
2525
import org.elasticsearch.xpack.core.ccr.action.PutFollowAction;
2626
import org.elasticsearch.xpack.core.ccr.action.UnfollowAction;
27+
import org.elasticsearch.xpack.core.indexlifecycle.action.ExplainLifecycleAction;
2728
import org.elasticsearch.xpack.core.security.support.Automatons;
2829

2930
import java.util.Arrays;
@@ -57,9 +58,11 @@ public final class IndexPrivilege extends Privilege {
5758
private static final Automaton DELETE_INDEX_AUTOMATON = patterns(DeleteIndexAction.NAME);
5859
private static final Automaton VIEW_METADATA_AUTOMATON = patterns(GetAliasesAction.NAME, AliasesExistAction.NAME,
5960
GetIndexAction.NAME, IndicesExistsAction.NAME, GetFieldMappingsAction.NAME + "*", GetMappingsAction.NAME,
60-
ClusterSearchShardsAction.NAME, TypesExistsAction.NAME, ValidateQueryAction.NAME + "*", GetSettingsAction.NAME);
61+
ClusterSearchShardsAction.NAME, TypesExistsAction.NAME, ValidateQueryAction.NAME + "*", GetSettingsAction.NAME,
62+
ExplainLifecycleAction.NAME);
6163
private static final Automaton MANAGE_FOLLOW_INDEX_AUTOMATON = patterns(PutFollowAction.NAME, UnfollowAction.NAME,
6264
CloseIndexAction.NAME);
65+
private static final Automaton MANAGE_ILM_AUTOMATON = patterns("indices:admin/ilm/*");
6366

6467
public static final IndexPrivilege NONE = new IndexPrivilege("none", Automatons.EMPTY);
6568
public static final IndexPrivilege ALL = new IndexPrivilege("all", ALL_AUTOMATON);
@@ -75,6 +78,7 @@ public final class IndexPrivilege extends Privilege {
7578
public static final IndexPrivilege CREATE_INDEX = new IndexPrivilege("create_index", CREATE_INDEX_AUTOMATON);
7679
public static final IndexPrivilege VIEW_METADATA = new IndexPrivilege("view_index_metadata", VIEW_METADATA_AUTOMATON);
7780
public static final IndexPrivilege MANAGE_FOLLOW_INDEX = new IndexPrivilege("manage_follow_index", MANAGE_FOLLOW_INDEX_AUTOMATON);
81+
public static final IndexPrivilege MANAGE_ILM = new IndexPrivilege("manage_ilm", MANAGE_ILM_AUTOMATON);
7882

7983
private static final Map<String, IndexPrivilege> VALUES = MapBuilder.<String, IndexPrivilege>newMapBuilder()
8084
.put("none", NONE)
@@ -91,6 +95,7 @@ public final class IndexPrivilege extends Privilege {
9195
.put("view_index_metadata", VIEW_METADATA)
9296
.put("read_cross_cluster", READ_CROSS_CLUSTER)
9397
.put("manage_follow_index", MANAGE_FOLLOW_INDEX)
98+
.put("manage_ilm", MANAGE_ILM)
9499
.immutableMap();
95100

96101
public static final Predicate<String> ACTION_MATCHER = ALL.predicate();

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

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,4 +138,57 @@ public void testManageCcrPrivilege() {
138138
assertThat(predicate.test("cluster:admin/xpack/whatever"), is(false));
139139
}
140140

141+
public void testIlmPrivileges() {
142+
{
143+
Predicate<String> predicate = ClusterPrivilege.MANAGE_ILM.predicate();
144+
// check cluster actions
145+
assertThat(predicate.test("cluster:admin/ilm/delete"), is(true));
146+
assertThat(predicate.test("cluster:admin/ilm/_move/post"), is(true));
147+
assertThat(predicate.test("cluster:admin/ilm/put"), is(true));
148+
assertThat(predicate.test("cluster:admin/ilm/start"), is(true));
149+
assertThat(predicate.test("cluster:admin/ilm/stop"), is(true));
150+
assertThat(predicate.test("cluster:admin/ilm/brand_new_api"), is(true));
151+
assertThat(predicate.test("cluster:admin/ilm/get"), is(true));
152+
assertThat(predicate.test("cluster:admin/ilm/operation_mode/get"), is(true));
153+
// check non-ilm action
154+
assertThat(predicate.test("cluster:admin/whatever"), is(false));
155+
}
156+
157+
{
158+
Predicate<String> predicate = ClusterPrivilege.READ_ILM.predicate();
159+
// check cluster actions
160+
assertThat(predicate.test("cluster:admin/ilm/delete"), is(false));
161+
assertThat(predicate.test("cluster:admin/ilm/_move/post"), is(false));
162+
assertThat(predicate.test("cluster:admin/ilm/put"), is(false));
163+
assertThat(predicate.test("cluster:admin/ilm/start"), is(false));
164+
assertThat(predicate.test("cluster:admin/ilm/stop"), is(false));
165+
assertThat(predicate.test("cluster:admin/ilm/brand_new_api"), is(false));
166+
assertThat(predicate.test("cluster:admin/ilm/get"), is(true));
167+
assertThat(predicate.test("cluster:admin/ilm/operation_mode/get"), is(true));
168+
// check non-ilm action
169+
assertThat(predicate.test("cluster:admin/whatever"), is(false));
170+
}
171+
172+
{
173+
Predicate<String> predicate = IndexPrivilege.MANAGE_ILM.predicate();
174+
// check indices actions
175+
assertThat(predicate.test("indices:admin/ilm/retry"), is(true));
176+
assertThat(predicate.test("indices:admin/ilm/remove_policy"), is(true));
177+
assertThat(predicate.test("indices:admin/ilm/brand_new_api"), is(true));
178+
assertThat(predicate.test("indices:admin/ilm/explain"), is(true));
179+
// check non-ilm action
180+
assertThat(predicate.test("indices:admin/whatever"), is(false));
181+
}
182+
183+
{
184+
Predicate<String> predicate = IndexPrivilege.VIEW_METADATA.predicate();
185+
// check indices actions
186+
assertThat(predicate.test("indices:admin/ilm/retry"), is(false));
187+
assertThat(predicate.test("indices:admin/ilm/remove_policy"), is(false));
188+
assertThat(predicate.test("indices:admin/ilm/brand_new_api"), is(false));
189+
assertThat(predicate.test("indices:admin/ilm/explain"), is(true));
190+
// check non-ilm action
191+
assertThat(predicate.test("indices:admin/whatever"), is(false));
192+
}
193+
}
141194
}

x-pack/plugin/ilm/qa/with-security/roles.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
ilm:
22
cluster:
33
- monitor
4-
- manage
4+
- manage_ilm
55
indices:
6+
- names: [ 'view-only-*' ]
7+
privileges:
8+
- view_index_metadata
69
- names: [ 'ilm-*' ]
710
privileges:
811
- monitor

x-pack/plugin/ilm/qa/with-security/src/test/java/org/elasticsearch/xpack/security/PermissionsIT.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,13 @@ public void testCanManageIndexWithNoPermissions() throws Exception {
119119
});
120120
}
121121

122+
public void testCanViewExplainOnUnmanagedIndex() throws Exception {
123+
createIndexAsAdmin("view-only-ilm", indexSettingsWithPolicy, "");
124+
Request request = new Request("GET", "/view-only-ilm/_ilm/explain");
125+
// test_ilm user has permissions to view
126+
assertOK(client().performRequest(request));
127+
}
128+
122129
private void createNewSingletonPolicy(String policy, String phaseName, LifecycleAction action) throws IOException {
123130
Phase phase = new Phase(phaseName, TimeValue.ZERO, singletonMap(action.getWriteableName(), action));
124131
LifecyclePolicy lifecyclePolicy = new LifecyclePolicy(policy, singletonMap(phase.getName(), phase));

0 commit comments

Comments
 (0)