Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -638,8 +638,8 @@ public void testGetRoles() throws Exception {

List<Role> roles = response.getRoles();
assertNotNull(response);
// 23 system roles plus the three we created
assertThat(roles.size(), equalTo(26));
// 24 system roles plus the three we created
assertThat(roles.size(), equalTo(27));
}

{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
package org.elasticsearch.xpack.core.security.authz.privilege;

import org.apache.lucene.util.automaton.Automaton;
import org.elasticsearch.action.admin.cluster.repositories.get.GetRepositoriesAction;
import org.elasticsearch.action.admin.cluster.snapshots.create.CreateSnapshotAction;
import org.elasticsearch.action.admin.cluster.snapshots.get.GetSnapshotsAction;
import org.elasticsearch.action.admin.cluster.snapshots.status.SnapshotsStatusAction;
import org.elasticsearch.action.admin.cluster.state.ClusterStateAction;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.collect.MapBuilder;
Expand Down Expand Up @@ -48,6 +52,8 @@ public final class ClusterPrivilege extends Privilege {
private static final Automaton MANAGE_ROLLUP_AUTOMATON = patterns("cluster:admin/xpack/rollup/*", "cluster:monitor/xpack/rollup/*");
private static final Automaton MANAGE_CCR_AUTOMATON =
patterns("cluster:admin/xpack/ccr/*", ClusterStateAction.NAME, HasPrivilegesAction.NAME);
private static final Automaton CREATE_SNAPSHOT_AUTOMATON = patterns(CreateSnapshotAction.NAME, SnapshotsStatusAction.NAME + "*",
GetSnapshotsAction.NAME, SnapshotsStatusAction.NAME, GetRepositoriesAction.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);
Expand All @@ -73,6 +79,7 @@ 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 CREATE_SNAPSHOT = new ClusterPrivilege("create_snapshot", CREATE_SNAPSHOT_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);

Expand All @@ -98,6 +105,7 @@ public final class ClusterPrivilege extends Privilege {
.put("manage_rollup", MANAGE_ROLLUP)
.put("manage_ccr", MANAGE_CCR)
.put("read_ccr", READ_CCR)
.put("create_snapshot", CREATE_SNAPSHOT)
.put("manage_ilm", MANAGE_ILM)
.put("read_ilm", READ_ILM)
.immutableMap();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ public final class IndexPrivilege extends Privilege {
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);
public static final IndexPrivilege NONE = new IndexPrivilege("none", Automatons.EMPTY);
public static final IndexPrivilege ALL = new IndexPrivilege("all", ALL_AUTOMATON);
public static final IndexPrivilege READ = new IndexPrivilege("read", READ_AUTOMATON);
public static final IndexPrivilege READ_CROSS_CLUSTER = new IndexPrivilege("read_cross_cluster", READ_CROSS_CLUSTER_AUTOMATON);
public static final IndexPrivilege CREATE = new IndexPrivilege("create", CREATE_AUTOMATON);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
package org.elasticsearch.xpack.core.security.authz.store;

import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.admin.cluster.repositories.get.GetRepositoriesAction;
import org.elasticsearch.common.collect.MapBuilder;
import org.elasticsearch.xpack.core.monitoring.action.MonitoringBulkAction;
import org.elasticsearch.xpack.core.security.authz.RoleDescriptor;
Expand Down Expand Up @@ -179,6 +180,12 @@ private static Map<String, RoleDescriptor> initializeReservedRoles() {
RoleDescriptor.IndicesPrivileges.builder()
.indices(".code-*").privileges("read").build()
}, null, MetadataUtils.DEFAULT_RESERVED_METADATA))
.put("snapshot_user", new RoleDescriptor("snapshot_user", new String[] { "create_snapshot", GetRepositoriesAction.NAME },
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you add this reserved role to the documentation?

new RoleDescriptor.IndicesPrivileges[] { RoleDescriptor.IndicesPrivileges.builder()
.indices("*")
.privileges("view_index_metadata")
.allowRestrictedIndices(true)
.build() }, null, null, null, MetadataUtils.DEFAULT_RESERVED_METADATA, null))
.immutableMap();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,13 @@

import org.elasticsearch.Version;
import org.elasticsearch.action.admin.cluster.health.ClusterHealthAction;
import org.elasticsearch.action.admin.cluster.repositories.get.GetRepositoriesAction;
import org.elasticsearch.action.admin.cluster.repositories.put.PutRepositoryAction;
import org.elasticsearch.action.admin.cluster.reroute.ClusterRerouteAction;
import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsAction;
import org.elasticsearch.action.admin.cluster.snapshots.create.CreateSnapshotAction;
import org.elasticsearch.action.admin.cluster.snapshots.get.GetSnapshotsAction;
import org.elasticsearch.action.admin.cluster.snapshots.status.SnapshotsStatusAction;
import org.elasticsearch.action.admin.cluster.state.ClusterStateAction;
import org.elasticsearch.action.admin.cluster.stats.ClusterStatsAction;
import org.elasticsearch.action.admin.indices.create.CreateIndexAction;
Expand Down Expand Up @@ -173,9 +178,54 @@ public void testIsReserved() {
assertThat(ReservedRolesStore.isReserved(APMSystemUser.ROLE_NAME), is(true));
assertThat(ReservedRolesStore.isReserved(RemoteMonitoringUser.COLLECTION_ROLE_NAME), is(true));
assertThat(ReservedRolesStore.isReserved(RemoteMonitoringUser.INDEXING_ROLE_NAME), is(true));
assertThat(ReservedRolesStore.isReserved("snapshot_user"), is(true));
assertThat(ReservedRolesStore.isReserved("code_admin"), is(true));
assertThat(ReservedRolesStore.isReserved("code_user"), is(true));
}

public void testSnapshotUserRole() {
final TransportRequest request = mock(TransportRequest.class);

RoleDescriptor roleDescriptor = new ReservedRolesStore().roleDescriptor("snapshot_user");
assertNotNull(roleDescriptor);
assertThat(roleDescriptor.getMetadata(), hasEntry("_reserved", true));

Role snapshotUserRole = Role.builder(roleDescriptor, null).build();
assertThat(snapshotUserRole.cluster().check(GetRepositoriesAction.NAME, request), is(true));
assertThat(snapshotUserRole.cluster().check(CreateSnapshotAction.NAME, request), is(true));
assertThat(snapshotUserRole.cluster().check(SnapshotsStatusAction.NAME, request), is(true));
assertThat(snapshotUserRole.cluster().check(GetSnapshotsAction.NAME, request), is(true));

assertThat(snapshotUserRole.cluster().check(PutRepositoryAction.NAME, request), is(false));
assertThat(snapshotUserRole.cluster().check(GetIndexTemplatesAction.NAME, request), is(false));
assertThat(snapshotUserRole.cluster().check(DeleteIndexTemplateAction.NAME, request), is(false));
assertThat(snapshotUserRole.cluster().check(PutPipelineAction.NAME, request), is(false));
assertThat(snapshotUserRole.cluster().check(GetPipelineAction.NAME, request), is(false));
assertThat(snapshotUserRole.cluster().check(DeletePipelineAction.NAME, request), is(false));
assertThat(snapshotUserRole.cluster().check(ClusterRerouteAction.NAME, request), is(false));
assertThat(snapshotUserRole.cluster().check(ClusterUpdateSettingsAction.NAME, request), is(false));
assertThat(snapshotUserRole.cluster().check(MonitoringBulkAction.NAME, request), is(false));
assertThat(snapshotUserRole.cluster().check(GetWatchAction.NAME, request), is(false));
assertThat(snapshotUserRole.cluster().check(PutWatchAction.NAME, request), is(false));
assertThat(snapshotUserRole.cluster().check(DeleteWatchAction.NAME, request), is(false));
assertThat(snapshotUserRole.cluster().check(ExecuteWatchAction.NAME, request), is(false));
assertThat(snapshotUserRole.cluster().check(AckWatchAction.NAME, request), is(false));
assertThat(snapshotUserRole.cluster().check(ActivateWatchAction.NAME, request), is(false));
assertThat(snapshotUserRole.cluster().check(WatcherServiceAction.NAME, request), is(false));

assertThat(snapshotUserRole.indices().allowedIndicesMatcher(IndexAction.NAME).test(randomAlphaOfLengthBetween(8, 24)), is(false));
assertThat(snapshotUserRole.indices().allowedIndicesMatcher("indices:foo").test(randomAlphaOfLengthBetween(8, 24)), is(false));
assertThat(snapshotUserRole.indices().allowedIndicesMatcher(GetAction.NAME).test(randomAlphaOfLengthBetween(8, 24)), is(false));
assertThat(snapshotUserRole.indices().allowedIndicesMatcher(GetAction.NAME).test(randomAlphaOfLengthBetween(8, 24)), is(false));

assertThat(snapshotUserRole.indices().allowedIndicesMatcher(GetIndexAction.NAME)
.test(randomAlphaOfLengthBetween(8, 24)), is(true));
assertThat(snapshotUserRole.indices().allowedIndicesMatcher(GetIndexAction.NAME)
.test(RestrictedIndicesNames.INTERNAL_SECURITY_INDEX), is(true));
assertThat(snapshotUserRole.indices().allowedIndicesMatcher(GetIndexAction.NAME)
.test(RestrictedIndicesNames.SECURITY_INDEX_NAME), is(true));

assertNoAccessAllowed(snapshotUserRole, RestrictedIndicesNames.NAMES_SET);
}

public void testIngestAdminRole() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,15 @@ public class ClusterPrivilegeTests extends AbstractPrivilegeTestCase {
"role_c:\n" +
" indices:\n" +
" - names: 'someindex'\n" +
" privileges: [ all ]\n";
" privileges: [ all ]\n" +
"role_d:\n" +
" cluster: [ create_snapshot ]\n";

private static final String USERS_ROLES =
"role_a:user_a\n" +
"role_b:user_b\n" +
"role_c:user_c\n";
"role_c:user_c\n" +
"role_d:user_d\n";

private static Path repositoryLocation;

Expand Down Expand Up @@ -75,8 +78,8 @@ protected String configUsers() {
return super.configUsers() +
"user_a:" + usersPasswdHashed + "\n" +
"user_b:" + usersPasswdHashed + "\n" +
"user_c:" + usersPasswdHashed + "\n";

"user_c:" + usersPasswdHashed + "\n" +
"user_d:" + usersPasswdHashed + "\n";
}

@Override
Expand Down Expand Up @@ -122,20 +125,34 @@ public void testThatClusterPrivilegesWorkAsExpectedViaHttp() throws Exception {
assertAccessIsDenied("user_c", "GET", "/_nodes/infos");
assertAccessIsDenied("user_c", "POST", "/_cluster/reroute");
assertAccessIsDenied("user_c", "PUT", "/_cluster/settings", "{ \"transient\" : { \"search.default_search_timeout\": \"1m\" } }");

// user_d can view repos and create and view snapshots on existings repos, everything else is DENIED
assertAccessIsDenied("user_d", "GET", "/_cluster/state");
assertAccessIsDenied("user_d", "GET", "/_cluster/health");
assertAccessIsDenied("user_d", "GET", "/_cluster/settings");
assertAccessIsDenied("user_d", "GET", "/_cluster/stats");
assertAccessIsDenied("user_d", "GET", "/_cluster/pending_tasks");
assertAccessIsDenied("user_d", "GET", "/_nodes/stats");
assertAccessIsDenied("user_d", "GET", "/_nodes/hot_threads");
assertAccessIsDenied("user_d", "GET", "/_nodes/infos");
assertAccessIsDenied("user_d", "POST", "/_cluster/reroute");
assertAccessIsDenied("user_d", "PUT", "/_cluster/settings", "{ \"transient\" : { \"search.default_search_timeout\": \"1m\" } }");
}

public void testThatSnapshotAndRestore() throws Exception {
String repoJson = Strings.toString(jsonBuilder().startObject().field("type", "fs").startObject("settings").field("location",
repositoryLocation.toString()).endObject().endObject());
assertAccessIsDenied("user_b", "PUT", "/_snapshot/my-repo", repoJson);
assertAccessIsDenied("user_c", "PUT", "/_snapshot/my-repo", repoJson);
assertAccessIsDenied("user_d", "PUT", "/_snapshot/my-repo", repoJson);
assertAccessIsAllowed("user_a", "PUT", "/_snapshot/my-repo", repoJson);

Request createBar = new Request("PUT", "/someindex/bar/1");
createBar.setJsonEntity("{ \"name\" : \"elasticsearch\" }");
createBar.addParameter("refresh", "true");
assertAccessIsDenied("user_a", createBar);
assertAccessIsDenied("user_b", createBar);
assertAccessIsDenied("user_d", createBar);
assertAccessIsAllowed("user_c", createBar);

assertAccessIsDenied("user_b", "PUT", "/_snapshot/my-repo/my-snapshot", "{ \"indices\": \"someindex\" }");
Expand All @@ -145,30 +162,38 @@ public void testThatSnapshotAndRestore() throws Exception {
assertAccessIsDenied("user_b", "GET", "/_snapshot/my-repo/my-snapshot/_status");
assertAccessIsDenied("user_c", "GET", "/_snapshot/my-repo/my-snapshot/_status");
assertAccessIsAllowed("user_a", "GET", "/_snapshot/my-repo/my-snapshot/_status");
assertAccessIsAllowed("user_d", "GET", "/_snapshot/my-repo/my-snapshot/_status");

// This snapshot needs to be finished in order to be restored
waitForSnapshotToFinish("my-repo", "my-snapshot");
// user_d can create snapshots, but not concurrently
assertAccessIsAllowed("user_d", "PUT", "/_snapshot/my-repo/my-snapshot-d", "{ \"indices\": \"someindex\" }");

assertAccessIsDenied("user_a", "DELETE", "/someindex");
assertAccessIsDenied("user_b", "DELETE", "/someindex");
assertAccessIsDenied("user_d", "DELETE", "/someindex");
assertAccessIsAllowed("user_c", "DELETE", "/someindex");

Request restoreSnapshotRequest = new Request("POST", "/_snapshot/my-repo/my-snapshot/_restore");
restoreSnapshotRequest.addParameter("wait_for_completion", "true");
assertAccessIsDenied("user_b", restoreSnapshotRequest);
assertAccessIsDenied("user_c", restoreSnapshotRequest);
assertAccessIsDenied("user_d", restoreSnapshotRequest);
assertAccessIsAllowed("user_a", restoreSnapshotRequest);

assertAccessIsDenied("user_a", "GET", "/someindex/bar/1");
assertAccessIsDenied("user_b", "GET", "/someindex/bar/1");
assertAccessIsDenied("user_d", "GET", "/someindex/bar/1");
assertAccessIsAllowed("user_c", "GET", "/someindex/bar/1");

assertAccessIsDenied("user_b", "DELETE", "/_snapshot/my-repo/my-snapshot");
assertAccessIsDenied("user_c", "DELETE", "/_snapshot/my-repo/my-snapshot");
assertAccessIsDenied("user_d", "DELETE", "/_snapshot/my-repo/my-snapshot");
assertAccessIsAllowed("user_a", "DELETE", "/_snapshot/my-repo/my-snapshot");

assertAccessIsDenied("user_b", "DELETE", "/_snapshot/my-repo");
assertAccessIsDenied("user_c", "DELETE", "/_snapshot/my-repo");
assertAccessIsDenied("user_d", "DELETE", "/_snapshot/my-repo");
assertAccessIsAllowed("user_a", "DELETE", "/_snapshot/my-repo");
}

Expand Down
Loading