Create snapshot role (#35820)
This commit introduces the `create_snapshot` cluster privilege and the `snapshot_user` role. This role is to be used by "cronable" tools that call the snapshot API periodically without recurring to the `manage` cluster privilege. The `create_snapshot` cluster privilege is much more limited compared to the `manage` privilege. The `snapshot_user` role grants the privileges to view the metadata of all indices (including restricted ones, i.e. .security). It obviously grants the create snapshot privilege but the repository has to be created using another role. In addition, it grants the privileges to (only) GET repositories and snapshots, but not create and delete them. The role does not allow to create repositories. This distinction is important because snapshotting equates to the `read` index privilege if the user has control of the snapshot destination, but this is not the case in this instance, because the role does not grant control over repository configuration.
This commit is contained in:
parent
f24dce1122
commit
66ddd8d2f7
|
@ -638,8 +638,8 @@ public class SecurityDocumentationIT extends ESRestHighLevelClientTestCase {
|
|||
|
||||
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));
|
||||
}
|
||||
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
@ -179,6 +180,12 @@ public class ReservedRolesStore implements BiConsumer<Set<String>, ActionListene
|
|||
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 },
|
||||
new RoleDescriptor.IndicesPrivileges[] { RoleDescriptor.IndicesPrivileges.builder()
|
||||
.indices("*")
|
||||
.privileges("view_index_metadata")
|
||||
.allowRestrictedIndices(true)
|
||||
.build() }, null, null, null, MetadataUtils.DEFAULT_RESERVED_METADATA, null))
|
||||
.immutableMap();
|
||||
}
|
||||
|
||||
|
|
|
@ -7,8 +7,13 @@ package org.elasticsearch.xpack.core.security.authz.store;
|
|||
|
||||
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;
|
||||
|
@ -173,9 +178,54 @@ public class ReservedRolesStoreTests extends ESTestCase {
|
|||
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() {
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
@ -75,8 +78,8 @@ public class ClusterPrivilegeTests extends AbstractPrivilegeTestCase {
|
|||
return super.configUsers() +
|
||||
"user_a:" + usersPasswdHashed + "\n" +
|
||||
"user_b:" + usersPasswdHashed + "\n" +
|
||||
"user_c:" + usersPasswdHashed + "\n";
|
||||
|
||||
"user_c:" + usersPasswdHashed + "\n" +
|
||||
"user_d:" + usersPasswdHashed + "\n";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -122,6 +125,18 @@ public class ClusterPrivilegeTests extends AbstractPrivilegeTestCase {
|
|||
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 {
|
||||
|
@ -129,6 +144,7 @@ public class ClusterPrivilegeTests extends AbstractPrivilegeTestCase {
|
|||
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");
|
||||
|
@ -136,6 +152,7 @@ public class ClusterPrivilegeTests extends AbstractPrivilegeTestCase {
|
|||
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\" }");
|
||||
|
@ -145,30 +162,38 @@ public class ClusterPrivilegeTests extends AbstractPrivilegeTestCase {
|
|||
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");
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,131 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
package org.elasticsearch.xpack.security.authz;
|
||||
|
||||
import org.elasticsearch.action.admin.cluster.repositories.get.GetRepositoriesResponse;
|
||||
import org.elasticsearch.action.admin.cluster.snapshots.create.CreateSnapshotResponse;
|
||||
import org.elasticsearch.action.admin.cluster.snapshots.get.GetSnapshotsResponse;
|
||||
import org.elasticsearch.action.admin.indices.get.GetIndexResponse;
|
||||
import org.elasticsearch.client.Client;
|
||||
import org.elasticsearch.common.settings.SecureString;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.snapshots.SnapshotState;
|
||||
import org.elasticsearch.test.NativeRealmIntegTestCase;
|
||||
import org.elasticsearch.xpack.core.security.authc.support.Hasher;
|
||||
import org.junit.Before;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Locale;
|
||||
|
||||
import static org.elasticsearch.xpack.core.security.index.RestrictedIndicesNames.INTERNAL_SECURITY_INDEX;
|
||||
import static org.elasticsearch.xpack.core.security.index.RestrictedIndicesNames.SECURITY_INDEX_NAME;
|
||||
|
||||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
|
||||
import static org.elasticsearch.xpack.core.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||
import static org.elasticsearch.test.SecurityTestsUtils.assertThrowsAuthorizationException;
|
||||
|
||||
public class SnapshotUserRoleIntegTests extends NativeRealmIntegTestCase {
|
||||
|
||||
private Client client;
|
||||
private String ordinaryIndex;
|
||||
|
||||
@Before
|
||||
public void setupClusterBeforeSnapshot() {
|
||||
logger.info("--> creating repository");
|
||||
assertAcked(client().admin().cluster().preparePutRepository("repo")
|
||||
.setType("fs")
|
||||
.setSettings(Settings.builder().put("location", randomRepoPath())));
|
||||
|
||||
logger.info("--> creating ordinary index");
|
||||
final int shards = between(1, 10);
|
||||
ordinaryIndex = randomAlphaOfLength(4).toLowerCase(Locale.ROOT);
|
||||
assertAcked(prepareCreate(ordinaryIndex, 0, Settings.builder().put("number_of_shards", shards).put("number_of_replicas", 0)));
|
||||
ensureGreen();
|
||||
|
||||
logger.info("--> creating snapshot_user user");
|
||||
final String user = "snapshot_user";
|
||||
final char[] password = new char[] {'p', 'a', 's', 's', 'w', 'o', 'r', 'd'};
|
||||
final String snapshotUserToken = basicAuthHeaderValue(user, new SecureString(password));
|
||||
client = client().filterWithHeader(Collections.singletonMap("Authorization", snapshotUserToken));
|
||||
securityClient().preparePutUser(user, password, Hasher.BCRYPT, "snapshot_user").get();
|
||||
ensureGreen(INTERNAL_SECURITY_INDEX);
|
||||
}
|
||||
|
||||
public void testSnapshotUserRoleCanSnapshotAndSeeAllIndices() {
|
||||
// view repositories
|
||||
final GetRepositoriesResponse getRepositoriesResponse = client.admin().cluster().prepareGetRepositories(randomFrom("*", "_all"))
|
||||
.get();
|
||||
assertThat(getRepositoriesResponse.repositories().size(), is(1));
|
||||
assertThat(getRepositoriesResponse.repositories().get(0).name(), is("repo"));
|
||||
// view all indices, including restricted ones
|
||||
final GetIndexResponse getIndexResponse = client.admin().indices().prepareGetIndex().setIndices(randomFrom("_all", "*")).get();
|
||||
assertThat(Arrays.asList(getIndexResponse.indices()), containsInAnyOrder(INTERNAL_SECURITY_INDEX, ordinaryIndex));
|
||||
// create snapshot that includes restricted indices
|
||||
final CreateSnapshotResponse snapshotResponse = client.admin().cluster().prepareCreateSnapshot("repo", "snap")
|
||||
.setIndices(randomFrom("_all", "*")).setWaitForCompletion(true).get();
|
||||
assertThat(snapshotResponse.getSnapshotInfo().state(), is(SnapshotState.SUCCESS));
|
||||
assertThat(snapshotResponse.getSnapshotInfo().indices(), containsInAnyOrder(INTERNAL_SECURITY_INDEX, ordinaryIndex));
|
||||
// view snapshots for repo
|
||||
final GetSnapshotsResponse getSnapshotResponse = client.admin().cluster().prepareGetSnapshots("repo").get();
|
||||
assertThat(getSnapshotResponse.getSnapshots().size(), is(1));
|
||||
assertThat(getSnapshotResponse.getSnapshots().get(0).snapshotId().getName(), is("snap"));
|
||||
assertThat(getSnapshotResponse.getSnapshots().get(0).indices(), containsInAnyOrder(INTERNAL_SECURITY_INDEX, ordinaryIndex));
|
||||
}
|
||||
|
||||
public void testSnapshotUserRoleIsReserved() {
|
||||
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
|
||||
() -> securityClient().preparePutRole("snapshot_user").get());
|
||||
assertThat(e.getMessage(), containsString("role [snapshot_user] is reserved and cannot be modified"));
|
||||
e = expectThrows(IllegalArgumentException.class,
|
||||
() -> securityClient().prepareDeleteRole("snapshot_user").get());
|
||||
assertThat(e.getMessage(), containsString("role [snapshot_user] is reserved and cannot be deleted"));
|
||||
}
|
||||
|
||||
public void testSnapshotUserRoleUnathorizedForDestructiveActions() {
|
||||
// try search all
|
||||
assertThrowsAuthorizationException(() -> client.prepareSearch(randomFrom("_all", "*")).get(), "indices:data/read/search",
|
||||
"snapshot_user");
|
||||
// try create index
|
||||
assertThrowsAuthorizationException(() -> client.admin().indices().prepareCreate(ordinaryIndex + "2").get(), "indices:admin/create",
|
||||
"snapshot_user");
|
||||
// try create another repo
|
||||
assertThrowsAuthorizationException(
|
||||
() -> client.admin().cluster().preparePutRepository("some_other_repo").setType("fs")
|
||||
.setSettings(Settings.builder().put("location", randomRepoPath())).get(),
|
||||
"cluster:admin/repository/put", "snapshot_user");
|
||||
// try delete repo
|
||||
assertThrowsAuthorizationException(() -> client.admin().cluster().prepareDeleteRepository("repo").get(),
|
||||
"cluster:admin/repository/delete", "snapshot_user");
|
||||
// try fumble with snapshots
|
||||
assertThrowsAuthorizationException(
|
||||
() -> client.admin().cluster().prepareRestoreSnapshot("repo", randomAlphaOfLength(4).toLowerCase(Locale.ROOT)).get(),
|
||||
"cluster:admin/snapshot/restore", "snapshot_user");
|
||||
assertThrowsAuthorizationException(
|
||||
() -> client.admin().cluster().prepareDeleteSnapshot("repo", randomAlphaOfLength(4).toLowerCase(Locale.ROOT)).get(),
|
||||
"cluster:admin/snapshot/delete", "snapshot_user");
|
||||
// try destructive/revealing actions on all indices
|
||||
for (final String indexToTest : Arrays.asList(INTERNAL_SECURITY_INDEX, SECURITY_INDEX_NAME, ordinaryIndex)) {
|
||||
assertThrowsAuthorizationException(() -> client.prepareSearch(indexToTest).get(), "indices:data/read/search", "snapshot_user");
|
||||
assertThrowsAuthorizationException(() -> client.prepareGet(indexToTest, "doc", "1").get(), "indices:data/read/get",
|
||||
"snapshot_user");
|
||||
assertThrowsAuthorizationException(() -> client.prepareIndex(indexToTest, "doc").setSource("term", "val").get(),
|
||||
"indices:data/write/index", "snapshot_user");
|
||||
assertThrowsAuthorizationException(() -> client.prepareUpdate(indexToTest, "doc", "1").setDoc("term", "val").get(),
|
||||
"indices:data/write/update", "snapshot_user");
|
||||
assertThrowsAuthorizationException(() -> client.prepareDelete(indexToTest, "doc", "1").get(), "indices:data/write/delete",
|
||||
"snapshot_user");
|
||||
|
||||
assertThrowsAuthorizationException(() -> client.admin().indices().prepareDelete(indexToTest).get(), "indices:admin/delete",
|
||||
"snapshot_user");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue