Skip to content

Commit 1776a4f

Browse files
authored
Add new predefined reserved roles (#71710) (#71904)
This change adds two new reserved roles in Elasticsearch, viewer and editor Solutions will use these roles in order to provide,out of the box, a role for full access to data and configuration with no access to cluster management(editor) and a role for read only access to data again with no access to cluster management (viewer).
1 parent 2257f8c commit 1776a4f

File tree

3 files changed

+171
-1
lines changed

3 files changed

+171
-1
lines changed

client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/SecurityDocumentationIT.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -689,7 +689,7 @@ public void testGetRoles() throws Exception {
689689
List<Role> roles = response.getRoles();
690690
assertNotNull(response);
691691
// 29 system roles plus the three we created
692-
assertThat(roles.size(), equalTo(29 + 3));
692+
assertThat(roles.size(), equalTo(31 + 3));
693693
}
694694

695695
{

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/store/ReservedRolesStore.java

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,9 +336,60 @@ private static Map<String, RoleDescriptor> initializeReservedRoles() {
336336
.indices(".enrich-*")
337337
.privileges("manage", "read", "write")
338338
.build() }, null, MetadataUtils.DEFAULT_RESERVED_METADATA))
339+
.put("viewer", buildViewerRoleDescriptor())
340+
.put("editor", buildEditorRoleDescriptor())
339341
.immutableMap();
340342
}
341343

344+
private static RoleDescriptor buildViewerRoleDescriptor() {
345+
return new RoleDescriptor(
346+
"viewer",
347+
new String[] {},
348+
new RoleDescriptor.IndicesPrivileges[] {
349+
// Stack
350+
RoleDescriptor.IndicesPrivileges.builder()
351+
.indices("/~(([.]|ilm-history-).*)/")
352+
.privileges("read", "view_index_metadata").build(),
353+
// Security
354+
RoleDescriptor.IndicesPrivileges.builder().indices(".siem-signals-*").privileges("read", "view_index_metadata").build() },
355+
new RoleDescriptor.ApplicationResourcePrivileges[] {
356+
RoleDescriptor.ApplicationResourcePrivileges.builder()
357+
.application("kibana-.kibana")
358+
.resources("*")
359+
.privileges("read").build() },
360+
null,
361+
null,
362+
MetadataUtils.DEFAULT_RESERVED_METADATA,
363+
null);
364+
}
365+
366+
private static RoleDescriptor buildEditorRoleDescriptor() {
367+
return new RoleDescriptor("editor",
368+
new String[] {},
369+
new RoleDescriptor.IndicesPrivileges[] {
370+
// Stack
371+
RoleDescriptor.IndicesPrivileges.builder()
372+
.indices("/~(([.]|ilm-history-).*)/")
373+
.privileges("read", "view_index_metadata").build(),
374+
// Observability
375+
RoleDescriptor.IndicesPrivileges.builder()
376+
.indices("observability-annotations")
377+
.privileges("read", "view_index_metadata", "write").build(),
378+
// Security
379+
RoleDescriptor.IndicesPrivileges.builder()
380+
.indices(".siem-signals-*", ".lists-*", ".items-*")
381+
.privileges("read", "view_index_metadata", "write", "maintenance").build() },
382+
new RoleDescriptor.ApplicationResourcePrivileges[] {
383+
RoleDescriptor.ApplicationResourcePrivileges.builder()
384+
.application("kibana-.kibana")
385+
.resources("*")
386+
.privileges("all").build() },
387+
null,
388+
null,
389+
MetadataUtils.DEFAULT_RESERVED_METADATA,
390+
null);
391+
}
392+
342393
private static RoleDescriptor kibanaAdminUser(String name, Map<String, Object> metadata) {
343394
return new RoleDescriptor(name, null, null,
344395
new RoleDescriptor.ApplicationResourcePrivileges[] {

x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authz/store/ReservedRolesStoreTests.java

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,8 @@ public void testIsReserved() {
233233
assertThat(ReservedRolesStore.isReserved("snapshot_user"), is(true));
234234
assertThat(ReservedRolesStore.isReserved("code_admin"), is(false));
235235
assertThat(ReservedRolesStore.isReserved("code_user"), is(false));
236+
assertThat(ReservedRolesStore.isReserved("viewer"), is(true));
237+
assertThat(ReservedRolesStore.isReserved("editor"), is(true));
236238
}
237239

238240
public void testSnapshotUserRole() {
@@ -1666,6 +1668,123 @@ public void testWatcherUserRole() {
16661668
assertNoAccessAllowed(role, RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2));
16671669
}
16681670

1671+
public void testPredefinedViewerRole() {
1672+
final TransportRequest request = mock(TransportRequest.class);
1673+
final Authentication authentication = mock(Authentication.class);
1674+
1675+
RoleDescriptor roleDescriptor = new ReservedRolesStore().roleDescriptor("viewer");
1676+
assertNotNull(roleDescriptor);
1677+
assertThat(roleDescriptor.getMetadata(), hasEntry("_reserved", true));
1678+
1679+
Role role = Role.builder(roleDescriptor, null).build();
1680+
// No cluster privileges
1681+
assertThat(role.cluster().check(ClusterHealthAction.NAME, request, authentication), is(false));
1682+
assertThat(role.cluster().check(ClusterStateAction.NAME, request, authentication), is(false));
1683+
assertThat(role.cluster().check(ClusterStatsAction.NAME, request, authentication), is(false));
1684+
assertThat(role.cluster().check(PutIndexTemplateAction.NAME, request, authentication), is(false));
1685+
assertThat(role.cluster().check(ClusterRerouteAction.NAME, request, authentication), is(false));
1686+
assertThat(role.cluster().check(ClusterUpdateSettingsAction.NAME, request, authentication), is(false));
1687+
assertThat(role.cluster().check(MonitoringBulkAction.NAME, request, authentication), is(false));
1688+
assertThat(role.cluster().check(DelegatePkiAuthenticationAction.NAME, request, authentication), is(false));
1689+
// Check index privileges
1690+
assertOnlyReadAllowed(role, "observability-annotations");
1691+
assertOnlyReadAllowed(role, "logs-" + randomIntBetween(0, 5));
1692+
assertOnlyReadAllowed(role, "metrics-" + randomIntBetween(0, 5));
1693+
assertOnlyReadAllowed(role, "synthetics-" + randomIntBetween(0, 5));
1694+
assertOnlyReadAllowed(role, "apm-" + randomIntBetween(0, 5));
1695+
assertOnlyReadAllowed(role, "traces-apm." + randomIntBetween(0, 5));
1696+
assertOnlyReadAllowed(role, "filebeat-" + randomIntBetween(0, 5));
1697+
assertOnlyReadAllowed(role, "metricbeat-" + randomIntBetween(0, 5));
1698+
assertOnlyReadAllowed(role, "heardbeat-" + randomIntBetween(0, 5));
1699+
assertOnlyReadAllowed(role, "kibana_sample_data_-" + randomIntBetween(0, 5));
1700+
assertOnlyReadAllowed(role, ".siem-signals-" + randomIntBetween(0, 5));
1701+
assertOnlyReadAllowed(role, "apm-" + randomIntBetween(0, 5) + "-transaction-" + randomIntBetween(0, 5));
1702+
assertOnlyReadAllowed(role, "logs-" + randomIntBetween(0, 5));
1703+
assertOnlyReadAllowed(role, "auditbeat-" + randomIntBetween(0, 5));
1704+
assertOnlyReadAllowed(role, "filebeat-" + randomIntBetween(0, 5));
1705+
assertOnlyReadAllowed(role, "packetbeat-" + randomIntBetween(0, 5));
1706+
assertOnlyReadAllowed(role, "winlogbeat-" + randomIntBetween(0, 5));
1707+
assertOnlyReadAllowed(role, "endgame-" + randomIntBetween(0, 5));
1708+
assertOnlyReadAllowed(role, randomAlphaOfLength(5));
1709+
1710+
assertNoAccessAllowed(role, RestrictedIndicesNames.RESTRICTED_NAMES);
1711+
assertNoAccessAllowed(role, "." + randomAlphaOfLengthBetween(6, 10));
1712+
assertNoAccessAllowed(role, "ilm-history-" + randomIntBetween(0, 5));
1713+
// Check application privileges
1714+
assertThat(role.application().grants(new ApplicationPrivilege("kibana-.kibana", "kibana-read", "read"), "*"), is(true));
1715+
assertThat(role.application().grants(new ApplicationPrivilege("kibana-.kibana", "kibana-all", "all"), "*"), is(false));
1716+
1717+
assertThat(role.runAs().check(randomAlphaOfLengthBetween(1, 20)), is(false));
1718+
}
1719+
1720+
public void testPredefinedEditorRole() {
1721+
final TransportRequest request = mock(TransportRequest.class);
1722+
final Authentication authentication = mock(Authentication.class);
1723+
1724+
RoleDescriptor roleDescriptor = new ReservedRolesStore().roleDescriptor("editor");
1725+
assertNotNull(roleDescriptor);
1726+
assertThat(roleDescriptor.getMetadata(), hasEntry("_reserved", true));
1727+
1728+
Role role = Role.builder(roleDescriptor, null).build();
1729+
1730+
// No cluster privileges
1731+
assertThat(role.cluster().check(ClusterHealthAction.NAME, request, authentication), is(false));
1732+
assertThat(role.cluster().check(ClusterStateAction.NAME, request, authentication), is(false));
1733+
assertThat(role.cluster().check(ClusterStatsAction.NAME, request, authentication), is(false));
1734+
assertThat(role.cluster().check(PutIndexTemplateAction.NAME, request, authentication), is(false));
1735+
assertThat(role.cluster().check(ClusterRerouteAction.NAME, request, authentication), is(false));
1736+
assertThat(role.cluster().check(ClusterUpdateSettingsAction.NAME, request, authentication), is(false));
1737+
assertThat(role.cluster().check(MonitoringBulkAction.NAME, request, authentication), is(false));
1738+
assertThat(role.cluster().check(DelegatePkiAuthenticationAction.NAME, request, authentication), is(false));
1739+
1740+
// Check index privileges
1741+
assertOnlyReadAllowed(role, "logs-" + randomIntBetween(0, 5));
1742+
assertOnlyReadAllowed(role, "metrics-" + randomIntBetween(0, 5));
1743+
assertOnlyReadAllowed(role, "synthetics-" + randomIntBetween(0, 5));
1744+
assertOnlyReadAllowed(role, "apm-" + randomIntBetween(0, 5));
1745+
assertOnlyReadAllowed(role, "traces-apm." + randomIntBetween(0, 5));
1746+
assertOnlyReadAllowed(role, "filebeat-" + randomIntBetween(0, 5));
1747+
assertOnlyReadAllowed(role, "metricbeat-" + randomIntBetween(0, 5));
1748+
assertOnlyReadAllowed(role, "heardbeat-" + randomIntBetween(0, 5));
1749+
assertOnlyReadAllowed(role, "kibana_sample_data_-" + randomIntBetween(0, 5));
1750+
assertOnlyReadAllowed(role, "apm-" + randomIntBetween(0, 5) + "-transaction-" + randomIntBetween(0, 5));
1751+
assertOnlyReadAllowed(role, "logs-" + randomIntBetween(0, 5));
1752+
assertOnlyReadAllowed(role, "auditbeat-" + randomIntBetween(0, 5));
1753+
assertOnlyReadAllowed(role, "filebeat-" + randomIntBetween(0, 5));
1754+
assertOnlyReadAllowed(role, "packetbeat-" + randomIntBetween(0, 5));
1755+
assertOnlyReadAllowed(role, "winlogbeat-" + randomIntBetween(0, 5));
1756+
assertOnlyReadAllowed(role, "endgame-" + randomIntBetween(0, 5));
1757+
assertOnlyReadAllowed(role, randomAlphaOfLength(5));
1758+
1759+
assertReadWriteDocsAndMaintenanceButNotDeleteIndexAllowed(role, ".siem-signals-" + randomIntBetween(0, 5));
1760+
assertReadWriteDocsAndMaintenanceButNotDeleteIndexAllowed(role, ".lists-" + randomIntBetween(0, 5));
1761+
assertReadWriteDocsAndMaintenanceButNotDeleteIndexAllowed(role, ".items-" + randomIntBetween(0, 5));
1762+
assertReadWriteDocsButNotDeleteIndexAllowed(role, "observability-annotations");
1763+
1764+
assertNoAccessAllowed(role, RestrictedIndicesNames.RESTRICTED_NAMES);
1765+
assertNoAccessAllowed(role, "." + randomAlphaOfLengthBetween(6, 10));
1766+
assertNoAccessAllowed(role, "ilm-history-" + randomIntBetween(0, 5));
1767+
1768+
// Check application privileges
1769+
assertThat(role.application().grants(new ApplicationPrivilege("kibana-.kibana", "kibana-all", "all"), "*"), is(true));
1770+
1771+
assertThat(role.runAs().check(randomAlphaOfLengthBetween(1, 20)), is(false));
1772+
}
1773+
1774+
private void assertReadWriteDocsAndMaintenanceButNotDeleteIndexAllowed(Role role, String index) {
1775+
assertThat(role.indices().allowedIndicesMatcher(DeleteIndexAction.NAME).test(mockIndexAbstraction(index)), is(false));
1776+
assertThat(role.indices().allowedIndicesMatcher(SearchAction.NAME).test(mockIndexAbstraction(index)), is(true));
1777+
assertThat(role.indices().allowedIndicesMatcher(GetAction.NAME).test(mockIndexAbstraction(index)), is(true));
1778+
assertThat(role.indices().allowedIndicesMatcher(IndexAction.NAME).test(mockIndexAbstraction(index)), is(true));
1779+
assertThat(role.indices().allowedIndicesMatcher(UpdateAction.NAME).test(mockIndexAbstraction(index)), is(true));
1780+
assertThat(role.indices().allowedIndicesMatcher(DeleteAction.NAME).test(mockIndexAbstraction(index)), is(true));
1781+
assertThat(role.indices().allowedIndicesMatcher(BulkAction.NAME).test(mockIndexAbstraction(index)), is(true));
1782+
assertThat(role.indices().allowedIndicesMatcher("indices:admin/refresh*").test(mockIndexAbstraction(index)), is(true));
1783+
assertThat(role.indices().allowedIndicesMatcher("indices:admin/flush*").test(mockIndexAbstraction(index)), is(true));
1784+
assertThat(role.indices().allowedIndicesMatcher("indices:admin/synced_flush").test(mockIndexAbstraction(index)), is(true));
1785+
assertThat(role.indices().allowedIndicesMatcher("indices:admin/forcemerge*").test(mockIndexAbstraction(index)), is(true));
1786+
}
1787+
16691788
private void assertReadWriteDocsButNotDeleteIndexAllowed(Role role, String index) {
16701789
assertThat(role.indices().allowedIndicesMatcher(DeleteIndexAction.NAME).test(mockIndexAbstraction(index)), is(false));
16711790
assertThat(role.indices().allowedIndicesMatcher(SearchAction.NAME).test(mockIndexAbstraction(index)), is(true));

0 commit comments

Comments
 (0)