Add 'monitor_snapshot' cluster privilege (#50489) (#50647)

This adds a new cluster privilege `monitor_snapshot` which is a restricted
version of `create_snapshot`, granting the same privileges to view
snapshot and repository info and status but not granting the actual
privilege to create a snapshot.

Co-authored-by: j-bean <anton.shuvaev91@gmail.com>
This commit is contained in:
Albert Zaharovits 2020-01-06 13:15:55 +02:00 committed by GitHub
parent 0f2d26bdca
commit 9ae3cd2a78
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 39 additions and 4 deletions

View File

@ -87,6 +87,7 @@ A successful call returns an object with "cluster" and "index" fields.
"monitor_data_frame_transforms",
"monitor_ml",
"monitor_rollup",
"monitor_snapshot",
"monitor_transform",
"monitor_watcher",
"none",

View File

@ -16,6 +16,9 @@ settings update, rerouting, or managing users and roles.
Privileges to create snapshots for existing repositories. Can also list and view
details on existing repositories and snapshots.
`monitor_snapshot`::
Privileges to list and view details on existing repositories and snapshots.
`manage`::
Builds on `monitor` and adds cluster operations that change values in the cluster.
This includes snapshotting, updating settings, and rerouting. It also includes

View File

@ -75,6 +75,8 @@ public class ClusterPrivilegeResolver {
private static final Set<String> CREATE_SNAPSHOT_PATTERN = Collections.unmodifiableSet(
Sets.newHashSet(CreateSnapshotAction.NAME, SnapshotsStatusAction.NAME + "*",
GetSnapshotsAction.NAME, SnapshotsStatusAction.NAME, GetRepositoriesAction.NAME));
private static final Set<String> MONITOR_SNAPSHOT_PATTERN = Collections.unmodifiableSet(Sets.newHashSet(
SnapshotsStatusAction.NAME + "*", GetSnapshotsAction.NAME, SnapshotsStatusAction.NAME, GetRepositoriesAction.NAME));
private static final Set<String> READ_CCR_PATTERN = Collections.unmodifiableSet(Sets.newHashSet(ClusterStateAction.NAME,
HasPrivilegesAction.NAME));
private static final Set<String> MANAGE_ILM_PATTERN = Collections.singleton("cluster:admin/ilm/*");
@ -121,6 +123,7 @@ public class ClusterPrivilegeResolver {
public static final NamedClusterPrivilege MANAGE_CCR = new ActionClusterPrivilege("manage_ccr", MANAGE_CCR_PATTERN);
public static final NamedClusterPrivilege READ_CCR = new ActionClusterPrivilege("read_ccr", READ_CCR_PATTERN);
public static final NamedClusterPrivilege CREATE_SNAPSHOT = new ActionClusterPrivilege("create_snapshot", CREATE_SNAPSHOT_PATTERN);
public static final NamedClusterPrivilege MONITOR_SNAPSHOT = new ActionClusterPrivilege("monitor_snapshot", MONITOR_SNAPSHOT_PATTERN);
public static final NamedClusterPrivilege MANAGE_ILM = new ActionClusterPrivilege("manage_ilm", MANAGE_ILM_PATTERN);
public static final NamedClusterPrivilege READ_ILM = new ActionClusterPrivilege("read_ilm", READ_ILM_PATTERN);
public static final NamedClusterPrivilege MANAGE_SLM = new ActionClusterPrivilege("manage_slm", MANAGE_SLM_PATTERN);
@ -159,6 +162,7 @@ public class ClusterPrivilegeResolver {
MANAGE_CCR,
READ_CCR,
CREATE_SNAPSHOT,
MONITOR_SNAPSHOT,
MANAGE_ILM,
READ_ILM,
MANAGE_SLM,

View File

@ -36,13 +36,17 @@ public class ClusterPrivilegeTests extends AbstractPrivilegeTestCase {
" - names: 'someindex'\n" +
" privileges: [ all ]\n" +
"role_d:\n" +
" cluster: [ create_snapshot ]\n";
" cluster: [ create_snapshot ]\n" +
"\n" +
"role_e:\n" +
" cluster: [ monitor_snapshot]\n";
private static final String USERS_ROLES =
"role_a:user_a\n" +
"role_b:user_b\n" +
"role_c:user_c\n" +
"role_d:user_d\n";
"role_d:user_d\n" +
"role_e:user_e\n";
private static Path repositoryLocation;
@ -81,7 +85,8 @@ public class ClusterPrivilegeTests extends AbstractPrivilegeTestCase {
"user_a:" + usersPasswdHashed + "\n" +
"user_b:" + usersPasswdHashed + "\n" +
"user_c:" + usersPasswdHashed + "\n" +
"user_d:" + usersPasswdHashed + "\n";
"user_d:" + usersPasswdHashed + "\n" +
"user_e:" + usersPasswdHashed + "\n";
}
@Override
@ -139,6 +144,19 @@ public class ClusterPrivilegeTests extends AbstractPrivilegeTestCase {
assertAccessIsDenied("user_d", "GET", "/_nodes/infos");
assertAccessIsDenied("user_d", "POST", "/_cluster/reroute");
assertAccessIsDenied("user_d", "PUT", "/_cluster/settings", "{ \"transient\" : { \"search.default_search_timeout\": \"1m\" } }");
// user_e can view repos and snapshots on existing repos, everything else is DENIED
assertAccessIsDenied("user_e", "GET", "/_cluster/state");
assertAccessIsDenied("user_e", "GET", "/_cluster/health");
assertAccessIsDenied("user_e", "GET", "/_cluster/settings");
assertAccessIsDenied("user_e", "GET", "/_cluster/stats");
assertAccessIsDenied("user_e", "GET", "/_cluster/pending_tasks");
assertAccessIsDenied("user_e", "GET", "/_nodes/stats");
assertAccessIsDenied("user_e", "GET", "/_nodes/hot_threads");
assertAccessIsDenied("user_e", "GET", "/_nodes/infos");
assertAccessIsDenied("user_e", "POST", "/_cluster/reroute");
assertAccessIsDenied("user_e", "PUT", "/_cluster/settings", "{ \"transient\" : { \"search.default_search_timeout\": \"1m\" } }");
}
public void testThatSnapshotAndRestore() throws Exception {
@ -147,6 +165,7 @@ public class ClusterPrivilegeTests extends AbstractPrivilegeTestCase {
assertAccessIsDenied("user_b", "PUT", "/_snapshot/my-repo", repoJson);
assertAccessIsDenied("user_c", "PUT", "/_snapshot/my-repo", repoJson);
assertAccessIsDenied("user_d", "PUT", "/_snapshot/my-repo", repoJson);
assertAccessIsDenied("user_e", "PUT", "/_snapshot/my-repo", repoJson);
assertAccessIsAllowed("user_a", "PUT", "/_snapshot/my-repo", repoJson);
Request createBar = new Request("PUT", "/someindex/bar/1");
@ -155,16 +174,19 @@ public class ClusterPrivilegeTests extends AbstractPrivilegeTestCase {
assertAccessIsDenied("user_a", createBar);
assertAccessIsDenied("user_b", createBar);
assertAccessIsDenied("user_d", createBar);
assertAccessIsDenied("user_e", createBar);
assertAccessIsAllowed("user_c", createBar);
assertAccessIsDenied("user_b", "PUT", "/_snapshot/my-repo/my-snapshot", "{ \"indices\": \"someindex\" }");
assertAccessIsDenied("user_c", "PUT", "/_snapshot/my-repo/my-snapshot", "{ \"indices\": \"someindex\" }");
assertAccessIsDenied("user_e", "PUT", "/_snapshot/my-repo/my-snapshot", "{ \"indices\": \"someindex\" }");
assertAccessIsAllowed("user_a", "PUT", "/_snapshot/my-repo/my-snapshot", "{ \"indices\": \"someindex\" }");
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");
assertAccessIsAllowed("user_e", "GET", "/_snapshot/my-repo/my-snapshot/_status");
// This snapshot needs to be finished in order to be restored
waitForSnapshotToFinish("my-repo", "my-snapshot");
@ -175,6 +197,7 @@ public class ClusterPrivilegeTests extends AbstractPrivilegeTestCase {
assertAccessIsDenied("user_a", "DELETE", "/someindex");
assertAccessIsDenied("user_b", "DELETE", "/someindex");
assertAccessIsDenied("user_d", "DELETE", "/someindex");
assertAccessIsDenied("user_e", "DELETE", "/someindex");
assertAccessIsAllowed("user_c", "DELETE", "/someindex");
Request restoreSnapshotRequest = new Request("POST", "/_snapshot/my-repo/my-snapshot/_restore");
@ -182,21 +205,25 @@ public class ClusterPrivilegeTests extends AbstractPrivilegeTestCase {
assertAccessIsDenied("user_b", restoreSnapshotRequest);
assertAccessIsDenied("user_c", restoreSnapshotRequest);
assertAccessIsDenied("user_d", restoreSnapshotRequest);
assertAccessIsDenied("user_e", 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");
assertAccessIsDenied("user_e", "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");
assertAccessIsDenied("user_e", "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");
assertAccessIsDenied("user_e", "DELETE", "/_snapshot/my-repo");
assertAccessIsAllowed("user_a", "DELETE", "/_snapshot/my-repo");
}

View File

@ -15,5 +15,5 @@ setup:
# This is fragile - it needs to be updated every time we add a new cluster/index privilege
# I would much prefer we could just check that specific entries are in the array, but we don't have
# an assertion for that
- length: { "cluster" : 33 }
- length: { "cluster" : 34 }
- length: { "index" : 17 }