Skip to content

Commit 5da9175

Browse files
AntonShuvaevalbertzaharovits
authored andcommitted
Add 'monitor_snapshot' cluster privilege (#50489)
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: Anton Shuvaev <[email protected]>
1 parent 6d3d3e4 commit 5da9175

File tree

5 files changed

+39
-4
lines changed

5 files changed

+39
-4
lines changed

x-pack/docs/en/rest-api/security/get-builtin-privileges.asciidoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ A successful call returns an object with "cluster" and "index" fields.
8787
"monitor_data_frame_transforms",
8888
"monitor_ml",
8989
"monitor_rollup",
90+
"monitor_snapshot",
9091
"monitor_transform",
9192
"monitor_watcher",
9293
"none",

x-pack/docs/en/security/authorization/privileges.asciidoc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ settings update, rerouting, or managing users and roles.
1616
Privileges to create snapshots for existing repositories. Can also list and view
1717
details on existing repositories and snapshots.
1818

19+
`monitor_snapshot`::
20+
Privileges to list and view details on existing repositories and snapshots.
21+
1922
`manage`::
2023
Builds on `monitor` and adds cluster operations that change values in the cluster.
2124
This includes snapshotting, updating settings, and rerouting. It also includes

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ public class ClusterPrivilegeResolver {
6666
Set.of("cluster:admin/xpack/ccr/*", ClusterStateAction.NAME, HasPrivilegesAction.NAME);
6767
private static final Set<String> CREATE_SNAPSHOT_PATTERN = Set.of(CreateSnapshotAction.NAME, SnapshotsStatusAction.NAME + "*",
6868
GetSnapshotsAction.NAME, SnapshotsStatusAction.NAME, GetRepositoriesAction.NAME);
69+
private static final Set<String> MONITOR_SNAPSHOT_PATTERN = Set.of(SnapshotsStatusAction.NAME + "*", GetSnapshotsAction.NAME,
70+
SnapshotsStatusAction.NAME, GetRepositoriesAction.NAME);
6971
private static final Set<String> READ_CCR_PATTERN = Set.of(ClusterStateAction.NAME, HasPrivilegesAction.NAME);
7072
private static final Set<String> MANAGE_ILM_PATTERN = Set.of("cluster:admin/ilm/*");
7173
private static final Set<String> READ_ILM_PATTERN = Set.of(GetLifecycleAction.NAME, GetStatusAction.NAME);
@@ -109,6 +111,7 @@ public class ClusterPrivilegeResolver {
109111
public static final NamedClusterPrivilege MANAGE_CCR = new ActionClusterPrivilege("manage_ccr", MANAGE_CCR_PATTERN);
110112
public static final NamedClusterPrivilege READ_CCR = new ActionClusterPrivilege("read_ccr", READ_CCR_PATTERN);
111113
public static final NamedClusterPrivilege CREATE_SNAPSHOT = new ActionClusterPrivilege("create_snapshot", CREATE_SNAPSHOT_PATTERN);
114+
public static final NamedClusterPrivilege MONITOR_SNAPSHOT = new ActionClusterPrivilege("monitor_snapshot", MONITOR_SNAPSHOT_PATTERN);
112115
public static final NamedClusterPrivilege MANAGE_ILM = new ActionClusterPrivilege("manage_ilm", MANAGE_ILM_PATTERN);
113116
public static final NamedClusterPrivilege READ_ILM = new ActionClusterPrivilege("read_ilm", READ_ILM_PATTERN);
114117
public static final NamedClusterPrivilege MANAGE_SLM = new ActionClusterPrivilege("manage_slm", MANAGE_SLM_PATTERN);
@@ -146,6 +149,7 @@ public class ClusterPrivilegeResolver {
146149
MANAGE_CCR,
147150
READ_CCR,
148151
CREATE_SNAPSHOT,
152+
MONITOR_SNAPSHOT,
149153
MANAGE_ILM,
150154
READ_ILM,
151155
MANAGE_SLM,

x-pack/plugin/security/src/test/java/org/elasticsearch/integration/ClusterPrivilegeTests.java

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,17 @@ public class ClusterPrivilegeTests extends AbstractPrivilegeTestCase {
3636
" - names: 'someindex'\n" +
3737
" privileges: [ all ]\n" +
3838
"role_d:\n" +
39-
" cluster: [ create_snapshot ]\n";
39+
" cluster: [ create_snapshot ]\n" +
40+
"\n" +
41+
"role_e:\n" +
42+
" cluster: [ monitor_snapshot]\n";
4043

4144
private static final String USERS_ROLES =
4245
"role_a:user_a\n" +
4346
"role_b:user_b\n" +
4447
"role_c:user_c\n" +
45-
"role_d:user_d\n";
48+
"role_d:user_d\n" +
49+
"role_e:user_e\n";
4650

4751
private static Path repositoryLocation;
4852

@@ -81,7 +85,8 @@ protected String configUsers() {
8185
"user_a:" + usersPasswdHashed + "\n" +
8286
"user_b:" + usersPasswdHashed + "\n" +
8387
"user_c:" + usersPasswdHashed + "\n" +
84-
"user_d:" + usersPasswdHashed + "\n";
88+
"user_d:" + usersPasswdHashed + "\n" +
89+
"user_e:" + usersPasswdHashed + "\n";
8590
}
8691

8792
@Override
@@ -139,6 +144,19 @@ public void testThatClusterPrivilegesWorkAsExpectedViaHttp() throws Exception {
139144
assertAccessIsDenied("user_d", "GET", "/_nodes/infos");
140145
assertAccessIsDenied("user_d", "POST", "/_cluster/reroute");
141146
assertAccessIsDenied("user_d", "PUT", "/_cluster/settings", "{ \"transient\" : { \"search.default_search_timeout\": \"1m\" } }");
147+
148+
// user_e can view repos and snapshots on existing repos, everything else is DENIED
149+
assertAccessIsDenied("user_e", "GET", "/_cluster/state");
150+
assertAccessIsDenied("user_e", "GET", "/_cluster/health");
151+
assertAccessIsDenied("user_e", "GET", "/_cluster/settings");
152+
assertAccessIsDenied("user_e", "GET", "/_cluster/stats");
153+
assertAccessIsDenied("user_e", "GET", "/_cluster/pending_tasks");
154+
assertAccessIsDenied("user_e", "GET", "/_nodes/stats");
155+
assertAccessIsDenied("user_e", "GET", "/_nodes/hot_threads");
156+
assertAccessIsDenied("user_e", "GET", "/_nodes/infos");
157+
assertAccessIsDenied("user_e", "POST", "/_cluster/reroute");
158+
assertAccessIsDenied("user_e", "PUT", "/_cluster/settings", "{ \"transient\" : { \"search.default_search_timeout\": \"1m\" } }");
159+
142160
}
143161

144162
public void testThatSnapshotAndRestore() throws Exception {
@@ -147,6 +165,7 @@ public void testThatSnapshotAndRestore() throws Exception {
147165
assertAccessIsDenied("user_b", "PUT", "/_snapshot/my-repo", repoJson);
148166
assertAccessIsDenied("user_c", "PUT", "/_snapshot/my-repo", repoJson);
149167
assertAccessIsDenied("user_d", "PUT", "/_snapshot/my-repo", repoJson);
168+
assertAccessIsDenied("user_e", "PUT", "/_snapshot/my-repo", repoJson);
150169
assertAccessIsAllowed("user_a", "PUT", "/_snapshot/my-repo", repoJson);
151170

152171
Request createBar = new Request("PUT", "/someindex/_doc/1");
@@ -155,16 +174,19 @@ public void testThatSnapshotAndRestore() throws Exception {
155174
assertAccessIsDenied("user_a", createBar);
156175
assertAccessIsDenied("user_b", createBar);
157176
assertAccessIsDenied("user_d", createBar);
177+
assertAccessIsDenied("user_e", createBar);
158178
assertAccessIsAllowed("user_c", createBar);
159179

160180
assertAccessIsDenied("user_b", "PUT", "/_snapshot/my-repo/my-snapshot", "{ \"indices\": \"someindex\" }");
161181
assertAccessIsDenied("user_c", "PUT", "/_snapshot/my-repo/my-snapshot", "{ \"indices\": \"someindex\" }");
182+
assertAccessIsDenied("user_e", "PUT", "/_snapshot/my-repo/my-snapshot", "{ \"indices\": \"someindex\" }");
162183
assertAccessIsAllowed("user_a", "PUT", "/_snapshot/my-repo/my-snapshot", "{ \"indices\": \"someindex\" }");
163184

164185
assertAccessIsDenied("user_b", "GET", "/_snapshot/my-repo/my-snapshot/_status");
165186
assertAccessIsDenied("user_c", "GET", "/_snapshot/my-repo/my-snapshot/_status");
166187
assertAccessIsAllowed("user_a", "GET", "/_snapshot/my-repo/my-snapshot/_status");
167188
assertAccessIsAllowed("user_d", "GET", "/_snapshot/my-repo/my-snapshot/_status");
189+
assertAccessIsAllowed("user_e", "GET", "/_snapshot/my-repo/my-snapshot/_status");
168190

169191
// This snapshot needs to be finished in order to be restored
170192
waitForSnapshotToFinish("my-repo", "my-snapshot");
@@ -175,28 +197,33 @@ public void testThatSnapshotAndRestore() throws Exception {
175197
assertAccessIsDenied("user_a", "DELETE", "/someindex");
176198
assertAccessIsDenied("user_b", "DELETE", "/someindex");
177199
assertAccessIsDenied("user_d", "DELETE", "/someindex");
200+
assertAccessIsDenied("user_e", "DELETE", "/someindex");
178201
assertAccessIsAllowed("user_c", "DELETE", "/someindex");
179202

180203
Request restoreSnapshotRequest = new Request("POST", "/_snapshot/my-repo/my-snapshot/_restore");
181204
restoreSnapshotRequest.addParameter("wait_for_completion", "true");
182205
assertAccessIsDenied("user_b", restoreSnapshotRequest);
183206
assertAccessIsDenied("user_c", restoreSnapshotRequest);
184207
assertAccessIsDenied("user_d", restoreSnapshotRequest);
208+
assertAccessIsDenied("user_e", restoreSnapshotRequest);
185209
assertAccessIsAllowed("user_a", restoreSnapshotRequest);
186210

187211
assertAccessIsDenied("user_a", "GET", "/someindex/_doc/1");
188212
assertAccessIsDenied("user_b", "GET", "/someindex/_doc/1");
189213
assertAccessIsDenied("user_d", "GET", "/someindex/_doc/1");
214+
assertAccessIsDenied("user_e", "GET", "/someindex/_doc/1");
190215
assertAccessIsAllowed("user_c", "GET", "/someindex/_doc/1");
191216

192217
assertAccessIsDenied("user_b", "DELETE", "/_snapshot/my-repo/my-snapshot");
193218
assertAccessIsDenied("user_c", "DELETE", "/_snapshot/my-repo/my-snapshot");
194219
assertAccessIsDenied("user_d", "DELETE", "/_snapshot/my-repo/my-snapshot");
220+
assertAccessIsDenied("user_e", "DELETE", "/_snapshot/my-repo/my-snapshot");
195221
assertAccessIsAllowed("user_a", "DELETE", "/_snapshot/my-repo/my-snapshot");
196222

197223
assertAccessIsDenied("user_b", "DELETE", "/_snapshot/my-repo");
198224
assertAccessIsDenied("user_c", "DELETE", "/_snapshot/my-repo");
199225
assertAccessIsDenied("user_d", "DELETE", "/_snapshot/my-repo");
226+
assertAccessIsDenied("user_e", "DELETE", "/_snapshot/my-repo");
200227
assertAccessIsAllowed("user_a", "DELETE", "/_snapshot/my-repo");
201228
}
202229

x-pack/plugin/src/test/resources/rest-api-spec/test/privileges/11_builtin.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,5 @@ setup:
1515
# This is fragile - it needs to be updated every time we add a new cluster/index privilege
1616
# I would much prefer we could just check that specific entries are in the array, but we don't have
1717
# an assertion for that
18-
- length: { "cluster" : 33 }
18+
- length: { "cluster" : 34 }
1919
- length: { "index" : 17 }

0 commit comments

Comments
 (0)