Skip to content

Commit

Permalink
Add ILM-specific security privileges (#36493)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
talevy committed Dec 13, 2018
1 parent 7c3dcec commit 89469aa
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -315,9 +315,11 @@ public static class ClusterPrivilegeName {
public static final String MANAGE_PIPELINE = "manage_pipeline";
public static final String MANAGE_CCR = "manage_ccr";
public static final String READ_CCR = "read_ccr";
public static final String MANAGE_ILM = "manage_ilm";
public static final String READ_ILM = "read_ilm";
public static final String[] ALL_ARRAY = new String[] { NONE, ALL, MONITOR, MONITOR_ML, MONITOR_WATCHER, MONITOR_ROLLUP, MANAGE,
MANAGE_ML, MANAGE_WATCHER, MANAGE_ROLLUP, MANAGE_INDEX_TEMPLATES, MANAGE_INGEST_PIPELINES, TRANSPORT_CLIENT,
MANAGE_SECURITY, MANAGE_SAML, MANAGE_TOKEN, MANAGE_PIPELINE, MANAGE_CCR, READ_CCR };
MANAGE_SECURITY, MANAGE_SAML, MANAGE_TOKEN, MANAGE_PIPELINE, MANAGE_CCR, READ_CCR, MANAGE_ILM, READ_ILM };
}

/**
Expand All @@ -338,8 +340,9 @@ public static class IndexPrivilegeName {
public static final String CREATE_INDEX = "create_index";
public static final String VIEW_INDEX_METADATA = "view_index_metadata";
public static final String MANAGE_FOLLOW_INDEX = "manage_follow_index";
public static final String MANAGE_ILM = "manage_ilm";
public static final String[] ALL_ARRAY = new String[] { NONE, ALL, READ, READ_CROSS, CREATE, INDEX, DELETE, WRITE, MONITOR, MANAGE,
DELETE_INDEX, CREATE_INDEX, VIEW_INDEX_METADATA, MANAGE_FOLLOW_INDEX };
DELETE_INDEX, CREATE_INDEX, VIEW_INDEX_METADATA, MANAGE_FOLLOW_INDEX, MANAGE_ILM };
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
import org.elasticsearch.action.admin.cluster.state.ClusterStateAction;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.collect.MapBuilder;
import org.elasticsearch.xpack.core.indexlifecycle.action.GetLifecycleAction;
import org.elasticsearch.xpack.core.indexlifecycle.action.GetStatusAction;
import org.elasticsearch.xpack.core.security.action.token.InvalidateTokenAction;
import org.elasticsearch.xpack.core.security.action.token.RefreshTokenAction;
import org.elasticsearch.xpack.core.security.action.user.HasPrivilegesAction;
Expand Down Expand Up @@ -47,6 +49,8 @@ public final class ClusterPrivilege extends Privilege {
private static final Automaton MANAGE_CCR_AUTOMATON =
patterns("cluster:admin/xpack/ccr/*", ClusterStateAction.NAME, HasPrivilegesAction.NAME);
private static final Automaton READ_CCR_AUTOMATON = patterns(ClusterStateAction.NAME, HasPrivilegesAction.NAME);
private static final Automaton MANAGE_ILM_AUTOMATON = patterns("cluster:admin/ilm/*");
private static final Automaton READ_ILM_AUTOMATON = patterns(GetLifecycleAction.NAME, GetStatusAction.NAME);

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

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

Expand All @@ -92,6 +98,8 @@ public final class ClusterPrivilege extends Privilege {
.put("manage_rollup", MANAGE_ROLLUP)
.put("manage_ccr", MANAGE_CCR)
.put("read_ccr", READ_CCR)
.put("manage_ilm", MANAGE_ILM)
.put("read_ilm", READ_ILM)
.immutableMap();

private static final ConcurrentHashMap<Set<String>, ClusterPrivilege> CACHE = new ConcurrentHashMap<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.elasticsearch.common.collect.MapBuilder;
import org.elasticsearch.xpack.core.ccr.action.PutFollowAction;
import org.elasticsearch.xpack.core.ccr.action.UnfollowAction;
import org.elasticsearch.xpack.core.indexlifecycle.action.ExplainLifecycleAction;
import org.elasticsearch.xpack.core.security.support.Automatons;

import java.util.Arrays;
Expand Down Expand Up @@ -57,9 +58,11 @@ public final class IndexPrivilege extends Privilege {
private static final Automaton DELETE_INDEX_AUTOMATON = patterns(DeleteIndexAction.NAME);
private static final Automaton VIEW_METADATA_AUTOMATON = patterns(GetAliasesAction.NAME, AliasesExistAction.NAME,
GetIndexAction.NAME, IndicesExistsAction.NAME, GetFieldMappingsAction.NAME + "*", GetMappingsAction.NAME,
ClusterSearchShardsAction.NAME, TypesExistsAction.NAME, ValidateQueryAction.NAME + "*", GetSettingsAction.NAME);
ClusterSearchShardsAction.NAME, TypesExistsAction.NAME, ValidateQueryAction.NAME + "*", GetSettingsAction.NAME,
ExplainLifecycleAction.NAME);
private static final Automaton MANAGE_FOLLOW_INDEX_AUTOMATON = patterns(PutFollowAction.NAME, UnfollowAction.NAME,
CloseIndexAction.NAME);
private static final Automaton MANAGE_ILM_AUTOMATON = patterns("indices:admin/ilm/*");

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

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

public static final Predicate<String> ACTION_MATCHER = ALL.predicate();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,4 +138,57 @@ public void testManageCcrPrivilege() {
assertThat(predicate.test("cluster:admin/xpack/whatever"), is(false));
}

public void testIlmPrivileges() {
{
Predicate<String> predicate = ClusterPrivilege.MANAGE_ILM.predicate();
// check cluster actions
assertThat(predicate.test("cluster:admin/ilm/delete"), is(true));
assertThat(predicate.test("cluster:admin/ilm/_move/post"), is(true));
assertThat(predicate.test("cluster:admin/ilm/put"), is(true));
assertThat(predicate.test("cluster:admin/ilm/start"), is(true));
assertThat(predicate.test("cluster:admin/ilm/stop"), is(true));
assertThat(predicate.test("cluster:admin/ilm/brand_new_api"), is(true));
assertThat(predicate.test("cluster:admin/ilm/get"), is(true));
assertThat(predicate.test("cluster:admin/ilm/operation_mode/get"), is(true));
// check non-ilm action
assertThat(predicate.test("cluster:admin/whatever"), is(false));
}

{
Predicate<String> predicate = ClusterPrivilege.READ_ILM.predicate();
// check cluster actions
assertThat(predicate.test("cluster:admin/ilm/delete"), is(false));
assertThat(predicate.test("cluster:admin/ilm/_move/post"), is(false));
assertThat(predicate.test("cluster:admin/ilm/put"), is(false));
assertThat(predicate.test("cluster:admin/ilm/start"), is(false));
assertThat(predicate.test("cluster:admin/ilm/stop"), is(false));
assertThat(predicate.test("cluster:admin/ilm/brand_new_api"), is(false));
assertThat(predicate.test("cluster:admin/ilm/get"), is(true));
assertThat(predicate.test("cluster:admin/ilm/operation_mode/get"), is(true));
// check non-ilm action
assertThat(predicate.test("cluster:admin/whatever"), is(false));
}

{
Predicate<String> predicate = IndexPrivilege.MANAGE_ILM.predicate();
// check indices actions
assertThat(predicate.test("indices:admin/ilm/retry"), is(true));
assertThat(predicate.test("indices:admin/ilm/remove_policy"), is(true));
assertThat(predicate.test("indices:admin/ilm/brand_new_api"), is(true));
assertThat(predicate.test("indices:admin/ilm/explain"), is(true));
// check non-ilm action
assertThat(predicate.test("indices:admin/whatever"), is(false));
}

{
Predicate<String> predicate = IndexPrivilege.VIEW_METADATA.predicate();
// check indices actions
assertThat(predicate.test("indices:admin/ilm/retry"), is(false));
assertThat(predicate.test("indices:admin/ilm/remove_policy"), is(false));
assertThat(predicate.test("indices:admin/ilm/brand_new_api"), is(false));
assertThat(predicate.test("indices:admin/ilm/explain"), is(true));
// check non-ilm action
assertThat(predicate.test("indices:admin/whatever"), is(false));
}
}
}
5 changes: 4 additions & 1 deletion x-pack/plugin/ilm/qa/with-security/roles.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
ilm:
cluster:
- monitor
- manage
- manage_ilm
indices:
- names: [ 'view-only-*' ]
privileges:
- view_index_metadata
- names: [ 'ilm-*' ]
privileges:
- monitor
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,13 @@ public void testCanManageIndexWithNoPermissions() throws Exception {
});
}

public void testCanViewExplainOnUnmanagedIndex() throws Exception {
createIndexAsAdmin("view-only-ilm", indexSettingsWithPolicy, "");
Request request = new Request("GET", "/view-only-ilm/_ilm/explain");
// test_ilm user has permissions to view
assertOK(client().performRequest(request));
}

private void createNewSingletonPolicy(String policy, String phaseName, LifecycleAction action) throws IOException {
Phase phase = new Phase(phaseName, TimeValue.ZERO, singletonMap(action.getWriteableName(), action));
LifecyclePolicy lifecyclePolicy = new LifecyclePolicy(policy, singletonMap(phase.getName(), phase));
Expand Down

0 comments on commit 89469aa

Please sign in to comment.