From b2b1bf44aeaaefd5804267108d5a8fc89de7984c Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Fri, 6 Sep 2019 11:17:02 -0400 Subject: [PATCH 01/11] introduce kibana_admin role; deprecate kibana_user and kibana_dashboard_only_user --- .../authz/store/ReservedRolesStore.java | 11 +++- .../core/security/support/MetadataUtils.java | 2 + .../authz/store/ReservedRolesStoreTests.java | 52 +++++++++++++++++++ 3 files changed, 63 insertions(+), 2 deletions(-) diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/store/ReservedRolesStore.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/store/ReservedRolesStore.java index 209686033534b..99169f8d4e0e0 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/store/ReservedRolesStore.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/store/ReservedRolesStore.java @@ -52,7 +52,14 @@ private static Map initializeReservedRoles() { RoleDescriptor.ApplicationResourcePrivileges.builder() .application("kibana-.kibana").resources("*").privileges("all").build() }, null, null, - MetadataUtils.DEFAULT_RESERVED_METADATA, null)) + MetadataUtils.DEPRECATED_RESERVED_METADATA, null)) + .put("kibana_admin", new RoleDescriptor("kibana_admin", null, null, + new RoleDescriptor.ApplicationResourcePrivileges[] { + RoleDescriptor.ApplicationResourcePrivileges.builder() + .application("kibana-.kibana") + .resources("*").privileges("all") + .build() }, + null, null, MetadataUtils.DEFAULT_RESERVED_METADATA, null)) .put("monitoring_user", new RoleDescriptor("monitoring_user", new String[] { "cluster:monitor/main", "cluster:monitor/xpack/info" }, new RoleDescriptor.IndicesPrivileges[] { @@ -106,7 +113,7 @@ private static Map initializeReservedRoles() { RoleDescriptor.ApplicationResourcePrivileges.builder() .application("kibana-.kibana").resources("*").privileges("read").build() }, null, null, - MetadataUtils.DEFAULT_RESERVED_METADATA, + MetadataUtils.DEPRECATED_RESERVED_METADATA, null)) .put(KibanaUser.ROLE_NAME, new RoleDescriptor(KibanaUser.ROLE_NAME, new String[] { diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/support/MetadataUtils.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/support/MetadataUtils.java index 72388a8fdbcb5..e969e109121c6 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/support/MetadataUtils.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/support/MetadataUtils.java @@ -11,7 +11,9 @@ public class MetadataUtils { public static final String RESERVED_PREFIX = "_"; public static final String RESERVED_METADATA_KEY = RESERVED_PREFIX + "reserved"; + public static final String DEPRECATED_METADATA_KEY = RESERVED_PREFIX + "deprecated"; public static final Map DEFAULT_RESERVED_METADATA = Map.of(RESERVED_METADATA_KEY, true); + public static final Map DEPRECATED_RESERVED_METADATA = Map.of(RESERVED_METADATA_KEY, true, DEPRECATED_METADATA_KEY, true); private MetadataUtils() { } diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authz/store/ReservedRolesStoreTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authz/store/ReservedRolesStoreTests.java index ecedfc0c0e95e..d1974cca0f60d 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authz/store/ReservedRolesStoreTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authz/store/ReservedRolesStoreTests.java @@ -162,6 +162,7 @@ import static org.hamcrest.Matchers.hasEntry; import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.not; import static org.mockito.Mockito.mock; /** @@ -177,6 +178,7 @@ public void testIsReserved() { assertThat(ReservedRolesStore.isReserved("foobar"), is(false)); assertThat(ReservedRolesStore.isReserved(SystemUser.ROLE_NAME), is(true)); assertThat(ReservedRolesStore.isReserved("transport_client"), is(true)); + assertThat(ReservedRolesStore.isReserved("kibana_admin"), is(true)); assertThat(ReservedRolesStore.isReserved("kibana_user"), is(true)); assertThat(ReservedRolesStore.isReserved("ingest_admin"), is(true)); assertThat(ReservedRolesStore.isReserved("monitoring_user"), is(true)); @@ -383,6 +385,54 @@ public void testKibanaSystemRole() { assertNoAccessAllowed(kibanaRole, RestrictedIndicesNames.RESTRICTED_NAMES); } + public void testKibanaAdminRole() { + final TransportRequest request = mock(TransportRequest.class); + final Authentication authentication = mock(Authentication.class); + + RoleDescriptor roleDescriptor = new ReservedRolesStore().roleDescriptor("kibana_admin"); + assertNotNull(roleDescriptor); + assertThat(roleDescriptor.getMetadata(), hasEntry("_reserved", true)); + assertThat(roleDescriptor.getMetadata(), not(hasEntry("_deprecated", true))); + + Role kibanaAdminRole = Role.builder(roleDescriptor, null).build(); + assertThat(kibanaAdminRole.cluster().check(ClusterHealthAction.NAME, request, authentication), is(false)); + assertThat(kibanaAdminRole.cluster().check(ClusterStateAction.NAME, request, authentication), is(false)); + assertThat(kibanaAdminRole.cluster().check(ClusterStatsAction.NAME, request, authentication), is(false)); + assertThat(kibanaAdminRole.cluster().check(PutIndexTemplateAction.NAME, request, authentication), is(false)); + assertThat(kibanaAdminRole.cluster().check(ClusterRerouteAction.NAME, request, authentication), is(false)); + assertThat(kibanaAdminRole.cluster().check(ClusterUpdateSettingsAction.NAME, request, authentication), + is(false)); + assertThat(kibanaAdminRole.cluster().check(MonitoringBulkAction.NAME, request, authentication), is(false)); + assertThat(kibanaAdminRole.cluster().check(DelegatePkiAuthenticationAction.NAME, request, authentication), + is(false)); + + assertThat(kibanaAdminRole.runAs().check(randomAlphaOfLengthBetween(1, 12)), is(false)); + + assertThat(kibanaAdminRole.indices().allowedIndicesMatcher(IndexAction.NAME).test("foo"), is(false)); + assertThat(kibanaAdminRole.indices().allowedIndicesMatcher(IndexAction.NAME).test(".reporting"), is(false)); + assertThat( + kibanaAdminRole.indices().allowedIndicesMatcher("indices:foo").test(randomAlphaOfLengthBetween(8, 24)), + is(false)); + + final String randomApplication = "kibana-" + randomAlphaOfLengthBetween(8, 24); + assertThat(kibanaAdminRole.application().grants(new ApplicationPrivilege(randomApplication, "app-random", "all"), + "*"), is(false)); + + final String application = "kibana-.kibana"; + assertThat(kibanaAdminRole.application().grants(new ApplicationPrivilege(application, "app-foo", "foo"), "*"), + is(false)); + assertThat(kibanaAdminRole.application().grants(new ApplicationPrivilege(application, "app-all", "all"), "*"), + is(true)); + + final String applicationWithRandomIndex = "kibana-.kibana_" + randomAlphaOfLengthBetween(8, 24); + assertThat( + kibanaAdminRole.application() + .grants(new ApplicationPrivilege(applicationWithRandomIndex, "app-random-index", "all"), "*"), + is(false)); + + assertNoAccessAllowed(kibanaAdminRole, RestrictedIndicesNames.RESTRICTED_NAMES); + } + public void testKibanaUserRole() { final TransportRequest request = mock(TransportRequest.class); final Authentication authentication = mock(Authentication.class); @@ -390,6 +440,7 @@ public void testKibanaUserRole() { RoleDescriptor roleDescriptor = new ReservedRolesStore().roleDescriptor("kibana_user"); assertNotNull(roleDescriptor); assertThat(roleDescriptor.getMetadata(), hasEntry("_reserved", true)); + assertThat(roleDescriptor.getMetadata(), hasEntry("_deprecated", true)); Role kibanaUserRole = Role.builder(roleDescriptor, null).build(); assertThat(kibanaUserRole.cluster().check(ClusterHealthAction.NAME, request, authentication), is(false)); @@ -691,6 +742,7 @@ public void testKibanaDashboardOnlyUserRole() { RoleDescriptor roleDescriptor = new ReservedRolesStore().roleDescriptor("kibana_dashboard_only_user"); assertNotNull(roleDescriptor); assertThat(roleDescriptor.getMetadata(), hasEntry("_reserved", true)); + assertThat(roleDescriptor.getMetadata(), hasEntry("_deprecated", true)); Role dashboardsOnlyUserRole = Role.builder(roleDescriptor, null).build(); assertThat(dashboardsOnlyUserRole.cluster().check(ClusterHealthAction.NAME, request, authentication), is(false)); From 65d312aa0aa7911e261de9e2a73f6296f71a1586 Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Fri, 6 Sep 2019 12:06:21 -0400 Subject: [PATCH 02/11] fix checkstyle error --- .../xpack/core/security/support/MetadataUtils.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/support/MetadataUtils.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/support/MetadataUtils.java index e969e109121c6..70e48a3f94d27 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/support/MetadataUtils.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/support/MetadataUtils.java @@ -13,7 +13,10 @@ public class MetadataUtils { public static final String RESERVED_METADATA_KEY = RESERVED_PREFIX + "reserved"; public static final String DEPRECATED_METADATA_KEY = RESERVED_PREFIX + "deprecated"; public static final Map DEFAULT_RESERVED_METADATA = Map.of(RESERVED_METADATA_KEY, true); - public static final Map DEPRECATED_RESERVED_METADATA = Map.of(RESERVED_METADATA_KEY, true, DEPRECATED_METADATA_KEY, true); + public static final Map DEPRECATED_RESERVED_METADATA = Map.of( + RESERVED_METADATA_KEY, true, + DEPRECATED_METADATA_KEY, true + ); private MetadataUtils() { } From 44a8e2eb4216b8c5319b3cbf16938ff2b7aa0d4f Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Fri, 6 Sep 2019 12:22:30 -0400 Subject: [PATCH 03/11] doc updates --- docs/reference/monitoring/configuring-filebeat.asciidoc | 2 +- x-pack/docs/en/security/authentication/oidc-guide.asciidoc | 4 ++-- x-pack/docs/en/security/authentication/saml-guide.asciidoc | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/reference/monitoring/configuring-filebeat.asciidoc b/docs/reference/monitoring/configuring-filebeat.asciidoc index fd77dc860ce8a..e1910e66a4981 100644 --- a/docs/reference/monitoring/configuring-filebeat.asciidoc +++ b/docs/reference/monitoring/configuring-filebeat.asciidoc @@ -117,7 +117,7 @@ If {security-features} are enabled, you must provide a valid user ID and password so that {filebeat} can connect to {kib}: .. Create a user on the monitoring cluster that has the -{stack-ov}/built-in-roles.html[`kibana_user` built-in role] or equivalent +{stack-ov}/built-in-roles.html[`kibana_admin` built-in role] or equivalent privileges. .. Add the `username` and `password` settings to the {es} output information in diff --git a/x-pack/docs/en/security/authentication/oidc-guide.asciidoc b/x-pack/docs/en/security/authentication/oidc-guide.asciidoc index 9a73cf072451b..58cafcba12db6 100644 --- a/x-pack/docs/en/security/authentication/oidc-guide.asciidoc +++ b/x-pack/docs/en/security/authentication/oidc-guide.asciidoc @@ -419,14 +419,14 @@ through either the NOTE: You cannot use {stack-ov}/mapping-roles.html#mapping-roles-file[role mapping files] to grant roles to users authenticating via OpenID Connect. -This is an example of a simple role mapping that grants the `kibana_user` role +This is an example of a simple role mapping that grants the `kibana_admin` role to any user who authenticates against the `oidc1` OpenID Connect realm: [source,js] -------------------------------------------------- PUT /_security/role_mapping/oidc-kibana { - "roles": [ "kibana_user" ], + "roles": [ "kibana_admin" ], "enabled": true, "rules": { "field": { "realm.name": "oidc1" } diff --git a/x-pack/docs/en/security/authentication/saml-guide.asciidoc b/x-pack/docs/en/security/authentication/saml-guide.asciidoc index 5bb02e6083d57..0f61e87dfcf6f 100644 --- a/x-pack/docs/en/security/authentication/saml-guide.asciidoc +++ b/x-pack/docs/en/security/authentication/saml-guide.asciidoc @@ -636,14 +636,14 @@ through either the NOTE: You cannot use {stack-ov}/mapping-roles.html#mapping-roles-file[role mapping files] to grant roles to users authenticating via SAML. -This is an example of a simple role mapping that grants the `kibana_user` role +This is an example of a simple role mapping that grants the `kibana_admin` role to any user who authenticates against the `saml1` realm: [source,js] -------------------------------------------------- PUT /_security/role_mapping/saml-kibana { - "roles": [ "kibana_user" ], + "roles": [ "kibana_admin" ], "enabled": true, "rules": { "field": { "realm.name": "saml1" } From 503ce9adb3bccfdfc02485b939b5f4bda4e0e991 Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Fri, 6 Sep 2019 12:57:40 -0400 Subject: [PATCH 04/11] update documentation test --- .../client/documentation/SecurityDocumentationIT.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/SecurityDocumentationIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/SecurityDocumentationIT.java index 88234f80e8fde..e1ab596c847d5 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/SecurityDocumentationIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/SecurityDocumentationIT.java @@ -681,8 +681,8 @@ public void testGetRoles() throws Exception { List roles = response.getRoles(); assertNotNull(response); - // 27 system roles plus the three we created - assertThat(roles.size(), equalTo(30)); + // 28 system roles plus the three we created + assertThat(roles.size(), equalTo(31)); } { From a0dc61088be5505d5d9ce4aacf7d97a943a4b022 Mon Sep 17 00:00:00 2001 From: Tim Vernum Date: Thu, 12 Dec 2019 16:07:10 +1100 Subject: [PATCH 05/11] Add deprecation logging for deprecated roles --- .../authz/store/ReservedRolesStore.java | 27 +-- .../core/security/support/MetadataUtils.java | 13 +- .../authz/store/CompositeRolesStore.java | 15 ++ .../authz/store/CompositeRolesStoreTests.java | 165 +++++++++++++----- 4 files changed, 164 insertions(+), 56 deletions(-) diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/store/ReservedRolesStore.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/store/ReservedRolesStore.java index 83d34df875431..a5a2a1a01e22b 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/store/ReservedRolesStore.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/store/ReservedRolesStore.java @@ -50,18 +50,9 @@ private static Map initializeReservedRoles() { .put("superuser", SUPERUSER_ROLE_DESCRIPTOR) .put("transport_client", new RoleDescriptor("transport_client", new String[] { "transport_client" }, null, null, MetadataUtils.DEFAULT_RESERVED_METADATA)) - .put("kibana_user", new RoleDescriptor("kibana_user", null, null, new RoleDescriptor.ApplicationResourcePrivileges[] { - RoleDescriptor.ApplicationResourcePrivileges.builder() - .application("kibana-.kibana").resources("*").privileges("all").build() }, - null, null, - MetadataUtils.DEPRECATED_RESERVED_METADATA, null)) - .put("kibana_admin", new RoleDescriptor("kibana_admin", null, null, - new RoleDescriptor.ApplicationResourcePrivileges[] { - RoleDescriptor.ApplicationResourcePrivileges.builder() - .application("kibana-.kibana") - .resources("*").privileges("all") - .build() }, - null, null, MetadataUtils.DEFAULT_RESERVED_METADATA, null)) + .put("kibana_admin", kibanaAdminUser("kibana_admin", MetadataUtils.DEFAULT_RESERVED_METADATA)) + .put("kibana_user", kibanaAdminUser("kibana_user", + MetadataUtils.getDeprecatedReservedMetadata("Please use the [kibana_admin] role instead"))) .put("monitoring_user", new RoleDescriptor("monitoring_user", new String[] { "cluster:monitor/main", "cluster:monitor/xpack/info", RemoteInfoAction.NAME }, new RoleDescriptor.IndicesPrivileges[] { @@ -115,7 +106,7 @@ private static Map initializeReservedRoles() { RoleDescriptor.ApplicationResourcePrivileges.builder() .application("kibana-.kibana").resources("*").privileges("read").build() }, null, null, - MetadataUtils.DEPRECATED_RESERVED_METADATA, + MetadataUtils.getDeprecatedReservedMetadata("Please use Kibana feature privileges instead"), null)) .put(KibanaUser.ROLE_NAME, new RoleDescriptor(KibanaUser.ROLE_NAME, new String[] { @@ -284,6 +275,16 @@ private static Map initializeReservedRoles() { .immutableMap(); } + private static RoleDescriptor kibanaAdminUser(String name, Map metadata) { + return new RoleDescriptor(name, null, null, + new RoleDescriptor.ApplicationResourcePrivileges[] { + RoleDescriptor.ApplicationResourcePrivileges.builder() + .application("kibana-.kibana") + .resources("*").privileges("all") + .build() }, + null, null, metadata, null); + } + public static boolean isReserved(String role) { return RESERVED_ROLES.containsKey(role) || UsernamesField.SYSTEM_ROLE.equals(role) || UsernamesField.XPACK_ROLE.equals(role); } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/support/MetadataUtils.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/support/MetadataUtils.java index 70e48a3f94d27..e85417b1d94f1 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/support/MetadataUtils.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/support/MetadataUtils.java @@ -12,11 +12,8 @@ public class MetadataUtils { public static final String RESERVED_PREFIX = "_"; public static final String RESERVED_METADATA_KEY = RESERVED_PREFIX + "reserved"; public static final String DEPRECATED_METADATA_KEY = RESERVED_PREFIX + "deprecated"; + public static final String DEPRECATED_REASON_METADATA_KEY = RESERVED_PREFIX + "deprecated_reason"; public static final Map DEFAULT_RESERVED_METADATA = Map.of(RESERVED_METADATA_KEY, true); - public static final Map DEPRECATED_RESERVED_METADATA = Map.of( - RESERVED_METADATA_KEY, true, - DEPRECATED_METADATA_KEY, true - ); private MetadataUtils() { } @@ -29,4 +26,12 @@ public static boolean containsReservedMetadata(Map metadata) { } return false; } + + public static Map getDeprecatedReservedMetadata(String reason) { + return Map.of( + RESERVED_METADATA_KEY, true, + DEPRECATED_METADATA_KEY, true, + DEPRECATED_REASON_METADATA_KEY, reason + ); + } } diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/store/CompositeRolesStore.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/store/CompositeRolesStore.java index 667b53c1c3328..6ff549cbf957a 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/store/CompositeRolesStore.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/store/CompositeRolesStore.java @@ -17,6 +17,7 @@ import org.elasticsearch.common.cache.Cache; import org.elasticsearch.common.cache.CacheBuilder; import org.elasticsearch.common.collect.Tuple; +import org.elasticsearch.common.logging.DeprecationLogger; import org.elasticsearch.common.settings.Setting; import org.elasticsearch.common.settings.Setting.Property; import org.elasticsearch.common.settings.Settings; @@ -41,6 +42,7 @@ import org.elasticsearch.xpack.core.security.authz.store.ReservedRolesStore; import org.elasticsearch.xpack.core.security.authz.store.RoleRetrievalResult; import org.elasticsearch.xpack.core.security.support.CacheIteratorHelper; +import org.elasticsearch.xpack.core.security.support.MetadataUtils; import org.elasticsearch.xpack.core.security.user.AnonymousUser; import org.elasticsearch.xpack.core.security.user.SystemUser; import org.elasticsearch.xpack.core.security.user.User; @@ -83,6 +85,7 @@ public class CompositeRolesStore { Setting.intSetting("xpack.security.authz.store.roles.negative_lookup_cache.max_size", 10000, Property.NodeScope); private static final Logger logger = LogManager.getLogger(CompositeRolesStore.class); + private final DeprecationLogger deprecationLogger = new DeprecationLogger(logger); private final FileRolesStore fileRolesStore; private final NativeRolesStore nativeRolesStore; @@ -154,6 +157,7 @@ public void roles(Set roleNames, ActionListener roleActionListener final long invalidationCounter = numInvalidation.get(); roleDescriptors(roleNames, ActionListener.wrap( rolesRetrievalResult -> { + logDeprecatedRoles(rolesRetrievalResult.roleDescriptors); final boolean missingRoles = rolesRetrievalResult.getMissingRoles().isEmpty() == false; if (missingRoles) { logger.debug(() -> new ParameterizedMessage("Could not find roles with names {}", @@ -179,6 +183,17 @@ public void roles(Set roleNames, ActionListener roleActionListener } } + void logDeprecatedRoles(Set roleDescriptors) { + roleDescriptors.stream() + .filter(rd -> Boolean.TRUE.equals(rd.getMetadata().get(MetadataUtils.DEPRECATED_METADATA_KEY))) + .forEach(rd -> { + String reason = Objects.toString( + rd.getMetadata().get(MetadataUtils.DEPRECATED_REASON_METADATA_KEY), "Please check the documentation"); + deprecationLogger.deprecatedAndMaybeLog("deprecated_role-" + rd.getName(), "The role [" + rd.getName() + + "] is deprecated and will be removed in a future version of Elasticsearch. " + reason); + }); + } + public void getRoles(User user, Authentication authentication, ActionListener roleActionListener) { // we need to special case the internal users in this method, if we apply the anonymous roles to every user including these system // user accounts then we run into the chance of a deadlock because then we need to get a role that we may be trying to get as the diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/store/CompositeRolesStoreTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/store/CompositeRolesStoreTests.java index 7da88f0231b8c..b18e7d3030d70 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/store/CompositeRolesStoreTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/store/CompositeRolesStoreTests.java @@ -15,6 +15,7 @@ import org.elasticsearch.cluster.health.ClusterHealthStatus; import org.elasticsearch.cluster.metadata.IndexMetaData; import org.elasticsearch.cluster.metadata.MetaData; +import org.elasticsearch.common.Nullable; import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.settings.Settings; @@ -52,6 +53,7 @@ import org.elasticsearch.xpack.core.security.authz.store.ReservedRolesStore; import org.elasticsearch.xpack.core.security.authz.store.RoleRetrievalResult; import org.elasticsearch.xpack.core.security.index.RestrictedIndicesNames; +import org.elasticsearch.xpack.core.security.support.MetadataUtils; import org.elasticsearch.xpack.core.security.user.AnonymousUser; import org.elasticsearch.xpack.core.security.user.SystemUser; import org.elasticsearch.xpack.core.security.user.User; @@ -63,10 +65,14 @@ import java.io.IOException; import java.time.Instant; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ExecutionException; @@ -83,6 +89,7 @@ import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.hasItem; +import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.nullValue; import static org.mockito.Matchers.any; @@ -142,21 +149,14 @@ public void testRolesWhenDlsFlsUnlicensed() throws IOException { }, null); FileRolesStore fileRolesStore = mock(FileRolesStore.class); doCallRealMethod().when(fileRolesStore).accept(any(Set.class), any(ActionListener.class)); - ReservedRolesStore reservedRolesStore = mock(ReservedRolesStore.class); - doCallRealMethod().when(reservedRolesStore).accept(any(Set.class), any(ActionListener.class)); - NativeRolesStore nativeRolesStore = mock(NativeRolesStore.class); - doCallRealMethod().when(nativeRolesStore).accept(any(Set.class), any(ActionListener.class)); when(fileRolesStore.roleDescriptors(Collections.singleton("fls"))).thenReturn(Collections.singleton(flsRole)); when(fileRolesStore.roleDescriptors(Collections.singleton("dls"))).thenReturn(Collections.singleton(dlsRole)); when(fileRolesStore.roleDescriptors(Collections.singleton("fls_dls"))).thenReturn(Collections.singleton(flsDlsRole)); when(fileRolesStore.roleDescriptors(Collections.singleton("no_fls_dls"))).thenReturn(Collections.singleton(noFlsDlsRole)); final AtomicReference> effectiveRoleDescriptors = new AtomicReference>(); - final DocumentSubsetBitsetCache documentSubsetBitsetCache = new DocumentSubsetBitsetCache(Settings.EMPTY); - CompositeRolesStore compositeRolesStore = new CompositeRolesStore(Settings.EMPTY, fileRolesStore, nativeRolesStore, - reservedRolesStore, mock(NativePrivilegeStore.class), Collections.emptyList(), - new ThreadContext(Settings.EMPTY), licenseState, cache, mock(ApiKeyService.class), documentSubsetBitsetCache, - rds -> effectiveRoleDescriptors.set(rds)); + CompositeRolesStore compositeRolesStore = buildCompositeRolesStore(Settings.EMPTY, fileRolesStore, null, + null, null, licenseState, null, null, rds -> effectiveRoleDescriptors.set(rds)); PlainActionFuture roleFuture = new PlainActionFuture<>(); compositeRolesStore.roles(Collections.singleton("fls"), roleFuture); @@ -219,20 +219,13 @@ public void testRolesWhenDlsFlsLicensed() throws IOException { }, null); FileRolesStore fileRolesStore = mock(FileRolesStore.class); doCallRealMethod().when(fileRolesStore).accept(any(Set.class), any(ActionListener.class)); - ReservedRolesStore reservedRolesStore = mock(ReservedRolesStore.class); - doCallRealMethod().when(reservedRolesStore).accept(any(Set.class), any(ActionListener.class)); - NativeRolesStore nativeRolesStore = mock(NativeRolesStore.class); - doCallRealMethod().when(nativeRolesStore).accept(any(Set.class), any(ActionListener.class)); when(fileRolesStore.roleDescriptors(Collections.singleton("fls"))).thenReturn(Collections.singleton(flsRole)); when(fileRolesStore.roleDescriptors(Collections.singleton("dls"))).thenReturn(Collections.singleton(dlsRole)); when(fileRolesStore.roleDescriptors(Collections.singleton("fls_dls"))).thenReturn(Collections.singleton(flsDlsRole)); when(fileRolesStore.roleDescriptors(Collections.singleton("no_fls_dls"))).thenReturn(Collections.singleton(noFlsDlsRole)); final AtomicReference> effectiveRoleDescriptors = new AtomicReference>(); - final DocumentSubsetBitsetCache documentSubsetBitsetCache = new DocumentSubsetBitsetCache(Settings.EMPTY); - CompositeRolesStore compositeRolesStore = new CompositeRolesStore(Settings.EMPTY, fileRolesStore, nativeRolesStore, - reservedRolesStore, mock(NativePrivilegeStore.class), Collections.emptyList(), - new ThreadContext(Settings.EMPTY), licenseState, cache, mock(ApiKeyService.class), documentSubsetBitsetCache, - rds -> effectiveRoleDescriptors.set(rds)); + CompositeRolesStore compositeRolesStore = buildCompositeRolesStore(Settings.EMPTY, fileRolesStore, null, + null, null, licenseState, null, null, rds -> effectiveRoleDescriptors.set(rds)); PlainActionFuture roleFuture = new PlainActionFuture<>(); compositeRolesStore.roles(Collections.singleton("fls"), roleFuture); @@ -265,6 +258,7 @@ public void testNegativeLookupsAreCached() { final NativeRolesStore nativeRolesStore = mock(NativeRolesStore.class); doCallRealMethod().when(nativeRolesStore).accept(any(Set.class), any(ActionListener.class)); when(fileRolesStore.roleDescriptors(anySetOf(String.class))).thenReturn(Collections.emptySet()); + doAnswer((invocationOnMock) -> { ActionListener callback = (ActionListener) invocationOnMock.getArguments()[1]; callback.onResponse(RoleRetrievalResult.success(Collections.emptySet())); @@ -280,12 +274,9 @@ public void testNegativeLookupsAreCached() { }).when(nativePrivilegeStore).getPrivileges(isA(Set.class), isA(Set.class), any(ActionListener.class)); final AtomicReference> effectiveRoleDescriptors = new AtomicReference>(); - final DocumentSubsetBitsetCache documentSubsetBitsetCache = new DocumentSubsetBitsetCache(Settings.EMPTY); - final CompositeRolesStore compositeRolesStore = - new CompositeRolesStore(SECURITY_ENABLED_SETTINGS, fileRolesStore, nativeRolesStore, reservedRolesStore, - nativePrivilegeStore, Collections.emptyList(), new ThreadContext(SECURITY_ENABLED_SETTINGS), - new XPackLicenseState(SECURITY_ENABLED_SETTINGS), cache, mock(ApiKeyService.class), - documentSubsetBitsetCache, rds -> effectiveRoleDescriptors.set(rds)); + final CompositeRolesStore compositeRolesStore = buildCompositeRolesStore(SECURITY_ENABLED_SETTINGS, + fileRolesStore, nativeRolesStore, reservedRolesStore, nativePrivilegeStore, null, null, null, + rds -> effectiveRoleDescriptors.set(rds)); verify(fileRolesStore).addListener(any(Consumer.class)); // adds a listener in ctor final String roleName = randomAlphaOfLengthBetween(1, 10); @@ -321,7 +312,7 @@ public void testNegativeLookupsAreCached() { if (getSuperuserRole && numberOfTimesToCall > 0) { // the superuser role was requested so we get the role descriptors again verify(reservedRolesStore, times(2)).accept(anySetOf(String.class), any(ActionListener.class)); - verify(nativePrivilegeStore).getPrivileges(isA(Set.class),isA(Set.class), any(ActionListener.class)); + verify(nativePrivilegeStore).getPrivileges(isA(Set.class), isA(Set.class), any(ActionListener.class)); } verifyNoMoreInteractions(fileRolesStore, reservedRolesStore, nativeRolesStore, nativePrivilegeStore); } @@ -895,11 +886,9 @@ public void testDefaultRoleUserWithoutRoles() { final ReservedRolesStore reservedRolesStore = spy(new ReservedRolesStore()); final DocumentSubsetBitsetCache documentSubsetBitsetCache = new DocumentSubsetBitsetCache(Settings.EMPTY); - final CompositeRolesStore compositeRolesStore = - new CompositeRolesStore(SECURITY_ENABLED_SETTINGS, fileRolesStore, nativeRolesStore, reservedRolesStore, - mock(NativePrivilegeStore.class), Collections.emptyList(), new ThreadContext(SECURITY_ENABLED_SETTINGS), - new XPackLicenseState(SECURITY_ENABLED_SETTINGS), cache, mock(ApiKeyService.class), documentSubsetBitsetCache, - rds -> {}); + final CompositeRolesStore compositeRolesStore = buildCompositeRolesStore(SECURITY_ENABLED_SETTINGS, fileRolesStore, + nativeRolesStore, reservedRolesStore, mock(NativePrivilegeStore.class), null, mock(ApiKeyService.class), + documentSubsetBitsetCache, null); verify(fileRolesStore).addListener(any(Consumer.class)); // adds a listener in ctor PlainActionFuture rolesFuture = new PlainActionFuture<>(); @@ -936,10 +925,8 @@ public void testAnonymousUserEnabledRoleAdded() { final ReservedRolesStore reservedRolesStore = spy(new ReservedRolesStore()); final DocumentSubsetBitsetCache documentSubsetBitsetCache = new DocumentSubsetBitsetCache(Settings.EMPTY); - final CompositeRolesStore compositeRolesStore = - new CompositeRolesStore(settings, fileRolesStore, nativeRolesStore, reservedRolesStore, - mock(NativePrivilegeStore.class), Collections.emptyList(), new ThreadContext(settings), - new XPackLicenseState(settings), cache, mock(ApiKeyService.class), documentSubsetBitsetCache, rds -> {}); + final CompositeRolesStore compositeRolesStore = buildCompositeRolesStore(settings, fileRolesStore, nativeRolesStore, + reservedRolesStore, mock(NativePrivilegeStore.class), null, mock(ApiKeyService.class), documentSubsetBitsetCache, null); verify(fileRolesStore).addListener(any(Consumer.class)); // adds a listener in ctor PlainActionFuture rolesFuture = new PlainActionFuture<>(); @@ -1119,11 +1106,9 @@ public void testUsageStats() { final DocumentSubsetBitsetCache documentSubsetBitsetCache = new DocumentSubsetBitsetCache(Settings.EMPTY); - final CompositeRolesStore compositeRolesStore = - new CompositeRolesStore(SECURITY_ENABLED_SETTINGS, fileRolesStore, nativeRolesStore, reservedRolesStore, - mock(NativePrivilegeStore.class), Collections.emptyList(), new ThreadContext(SECURITY_ENABLED_SETTINGS), - new XPackLicenseState(SECURITY_ENABLED_SETTINGS), cache, mock(ApiKeyService.class), documentSubsetBitsetCache, rds -> { - }); + final CompositeRolesStore compositeRolesStore = buildCompositeRolesStore( + SECURITY_ENABLED_SETTINGS, fileRolesStore, nativeRolesStore, reservedRolesStore, null, null, mock(ApiKeyService.class), + documentSubsetBitsetCache, null); PlainActionFuture> usageStatsListener = new PlainActionFuture<>(); compositeRolesStore.usageStats(usageStatsListener); @@ -1133,6 +1118,108 @@ public void testUsageStats() { assertThat(usageStats.get("dls"), is(Map.of("bit_set_cache", documentSubsetBitsetCache.usageStats()))); } + public void testLoggingOfDeprecatedRoles() { + List descriptors = new ArrayList<>(); + Function, RoleDescriptor> newRole = metadata -> new RoleDescriptor( + randomAlphaOfLengthBetween(4, 9), generateRandomStringArray(5, 5, false, true), + null, null, null, null, metadata, null); + + RoleDescriptor deprecated1 = newRole.apply(MetadataUtils.getDeprecatedReservedMetadata("some reason")); + RoleDescriptor deprecated2 = newRole.apply(MetadataUtils.getDeprecatedReservedMetadata("a different reason")); + + // Can't use getDeprecatedReservedMetadata because `Map.of` doesn't accept null values, + // so we clone metadata with a real value and then remove that key + final Map nullReasonMetadata = new HashMap<>(deprecated2.getMetadata()); + nullReasonMetadata.remove(MetadataUtils.DEPRECATED_REASON_METADATA_KEY); + assertThat(nullReasonMetadata.keySet(), hasSize(deprecated2.getMetadata().size() -1)); + RoleDescriptor deprecated3 = newRole.apply(nullReasonMetadata); + + descriptors.add(deprecated1); + descriptors.add(deprecated2); + descriptors.add(deprecated3); + + for (int i = randomIntBetween(2, 10); i > 0; i--) { + // the non-deprecated metadata is randomly one of: + // {}, {_deprecated:null}, {_deprecated:false}, + // {_reserved:true}, {_reserved:true,_deprecated:null}, {_reserved:true,_deprecated:false} + Map metadata = randomBoolean() ? Map.of() : MetadataUtils.DEFAULT_RESERVED_METADATA; + if (randomBoolean()) { + metadata = new HashMap<>(metadata); + metadata.put(MetadataUtils.DEPRECATED_METADATA_KEY, randomBoolean() ? null : false); + } + descriptors.add(newRole.apply(metadata)); + } + Collections.shuffle(descriptors, random()); + + final CompositeRolesStore compositeRolesStore = + buildCompositeRolesStore(SECURITY_ENABLED_SETTINGS, null, null, null, null, null, null, null, null); + + // Use a LHS so that the random-shufle-order of the list is preserved + compositeRolesStore.logDeprecatedRoles(new LinkedHashSet<>(descriptors)); + + assertWarnings( + "The role [" + deprecated1.getName() + "] is deprecated and will be removed in a future version of Elasticsearch." + + " some reason", + "The role [" + deprecated2.getName() + "] is deprecated and will be removed in a future version of Elasticsearch." + + " a different reason", + "The role [" + deprecated3.getName() + "] is deprecated and will be removed in a future version of Elasticsearch." + + " Please check the documentation" + ); + } + + private CompositeRolesStore buildCompositeRolesStore(Settings settings, + @Nullable FileRolesStore fileRolesStore, + @Nullable NativeRolesStore nativeRolesStore, + @Nullable ReservedRolesStore reservedRolesStore, + @Nullable NativePrivilegeStore privilegeStore, + @Nullable XPackLicenseState licenseState, + @Nullable ApiKeyService apiKeyService, + @Nullable DocumentSubsetBitsetCache documentSubsetBitsetCache, + @Nullable Consumer> roleConsumer) { + if (fileRolesStore == null) { + fileRolesStore = mock(FileRolesStore.class); + doCallRealMethod().when(fileRolesStore).accept(any(Set.class), any(ActionListener.class)); + when(fileRolesStore.roleDescriptors(anySetOf(String.class))).thenReturn(Collections.emptySet()); + } + if (nativeRolesStore == null) { + nativeRolesStore = mock(NativeRolesStore.class); + doCallRealMethod().when(nativeRolesStore).accept(any(Set.class), any(ActionListener.class)); + doAnswer((invocationOnMock) -> { + ActionListener callback = (ActionListener) invocationOnMock.getArguments()[1]; + callback.onResponse(RoleRetrievalResult.failure(new RuntimeException("intentionally failed!"))); + return null; + }).when(nativeRolesStore).getRoleDescriptors(isA(Set.class), any(ActionListener.class)); + } + if (reservedRolesStore == null) { + reservedRolesStore = mock(ReservedRolesStore.class); + doCallRealMethod().when(reservedRolesStore).accept(any(Set.class), any(ActionListener.class)); + } + if (privilegeStore == null) { + privilegeStore = mock(NativePrivilegeStore.class); + doAnswer((invocationOnMock) -> { + ActionListener> callback = null; + callback = (ActionListener>) invocationOnMock.getArguments()[2]; + callback.onResponse(Collections.emptyList()); + return null; + }).when(privilegeStore).getPrivileges(isA(Set.class), isA(Set.class), any(ActionListener.class)); + } + if (licenseState == null) { + licenseState = new XPackLicenseState(settings); + } + if (apiKeyService == null) { + apiKeyService = mock(ApiKeyService.class); + } + if (documentSubsetBitsetCache == null) { + documentSubsetBitsetCache = new DocumentSubsetBitsetCache(settings); + } + if (roleConsumer == null) { + roleConsumer = rds -> { }; + } + return new CompositeRolesStore(settings, fileRolesStore, nativeRolesStore, reservedRolesStore, privilegeStore, + Collections.emptyList(), new ThreadContext(settings), licenseState, cache, apiKeyService, documentSubsetBitsetCache, + roleConsumer); + } + private static class InMemoryRolesProvider implements BiConsumer, ActionListener> { private final Function, RoleRetrievalResult> roleDescriptorsFunc; From 26c189e58da42b533b7a59bbbce7b7c5a60db90f Mon Sep 17 00:00:00 2001 From: Tim Vernum Date: Sat, 14 Dec 2019 01:21:30 +1100 Subject: [PATCH 06/11] Switch OIDC test to use kibana_admin --- .../xpack/security/authc/oidc/OpenIdConnectAuthIT.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/qa/oidc-op-tests/src/test/java/org/elasticsearch/xpack/security/authc/oidc/OpenIdConnectAuthIT.java b/x-pack/qa/oidc-op-tests/src/test/java/org/elasticsearch/xpack/security/authc/oidc/OpenIdConnectAuthIT.java index 67643af723894..4b0e3afc813ad 100644 --- a/x-pack/qa/oidc-op-tests/src/test/java/org/elasticsearch/xpack/security/authc/oidc/OpenIdConnectAuthIT.java +++ b/x-pack/qa/oidc-op-tests/src/test/java/org/elasticsearch/xpack/security/authc/oidc/OpenIdConnectAuthIT.java @@ -276,7 +276,7 @@ private void verifyElasticsearchAccessTokenForCodeFlow(String accessToken) throw final Map map = callAuthenticateApiUsingAccessToken(accessToken); logger.info("Authentication with token Response: " + map); assertThat(map.get("username"), equalTo("alice")); - assertThat((List) map.get("roles"), containsInAnyOrder("kibana_user", "auditor")); + assertThat((List) map.get("roles"), containsInAnyOrder("kibana_admin", "auditor")); assertThat(map.get("metadata"), instanceOf(Map.class)); final Map metadata = (Map) map.get("metadata"); @@ -374,7 +374,7 @@ private void setFacilitatorUser() throws IOException { private void setRoleMappings() throws IOException { Request createRoleMappingRequest = new Request("PUT", "/_security/role_mapping/oidc_kibana"); - createRoleMappingRequest.setJsonEntity("{ \"roles\" : [\"kibana_user\"]," + + createRoleMappingRequest.setJsonEntity("{ \"roles\" : [\"kibana_admin\"]," + "\"enabled\": true," + "\"rules\": {" + "\"field\": { \"realm.name\": \"" + REALM_NAME + "\"}" + From 941785009a4f70caaece85922aabc8e7a21e4dc8 Mon Sep 17 00:00:00 2001 From: Tim Vernum Date: Mon, 16 Dec 2019 16:17:08 +1100 Subject: [PATCH 07/11] Update OIDC/SAML docs to not use kibana_admin role --- .../en/security/authentication/oidc-guide.asciidoc | 11 +++++++++-- .../en/security/authentication/saml-guide.asciidoc | 11 +++++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/x-pack/docs/en/security/authentication/oidc-guide.asciidoc b/x-pack/docs/en/security/authentication/oidc-guide.asciidoc index e88fedc5fe99b..758c366e171fc 100644 --- a/x-pack/docs/en/security/authentication/oidc-guide.asciidoc +++ b/x-pack/docs/en/security/authentication/oidc-guide.asciidoc @@ -420,14 +420,14 @@ through either the NOTE: You cannot use <> to grant roles to users authenticating via OpenID Connect. -This is an example of a simple role mapping that grants the `kibana_admin` role +This is an example of a simple role mapping that grants the `siem_view` role to any user who authenticates against the `oidc1` OpenID Connect realm: [source,console] -------------------------------------------------- PUT /_security/role_mapping/oidc-kibana { - "roles": [ "kibana_admin" ], + "roles": [ "siem_view" ], <1> "enabled": true, "rules": { "field": { "realm.name": "oidc1" } @@ -435,6 +435,13 @@ PUT /_security/role_mapping/oidc-kibana } -------------------------------------------------- +<1> The `siem_view` role is *not* a builtin Elasticsearch role. +This example assumes that you have created a custom role of your own, with +`read` access to your SIEM <> and `Read` access to +the SIEM application using +{kibana-ref}/kibana-privileges.html#kibana-feature-privileges[Kibana feature privileges]. +You should create your own roles that provide access to the features that your +users need. The user properties that are mapped via the realm configuration are used to process role mapping rules, and these rules determine which roles a user is granted. diff --git a/x-pack/docs/en/security/authentication/saml-guide.asciidoc b/x-pack/docs/en/security/authentication/saml-guide.asciidoc index 6b1a16bc6667a..33aba0f4c53fe 100644 --- a/x-pack/docs/en/security/authentication/saml-guide.asciidoc +++ b/x-pack/docs/en/security/authentication/saml-guide.asciidoc @@ -639,14 +639,14 @@ through either the NOTE: You cannot use <> to grant roles to users authenticating via SAML. -This is an example of a simple role mapping that grants the `kibana_admin` role +This is an example of a simple role mapping that grants the `siem_view` role to any user who authenticates against the `saml1` realm: [source,console] -------------------------------------------------- PUT /_security/role_mapping/saml-kibana { - "roles": [ "kibana_admin" ], + "roles": [ "siem_view" ], <1> "enabled": true, "rules": { "field": { "realm.name": "saml1" } @@ -654,6 +654,13 @@ PUT /_security/role_mapping/saml-kibana } -------------------------------------------------- +<1> The `siem_view` role is *not* a builtin Elasticsearch role. +This example assumes that you have created a custom role of your own, with +`read` access to your SIEM <> and `Read` access to +the SIEM application using +{kibana-ref}/kibana-privileges.html#kibana-feature-privileges[Kibana feature privileges]. +You should create your own roles that provide access to the features that your +users need. The attributes that are mapped via the realm configuration are used to process role mapping rules, and these rules determine which roles a user is granted. From 11df36b7c0cd9d795d9506b1ed03cff843fec029 Mon Sep 17 00:00:00 2001 From: Tim Vernum Date: Mon, 16 Dec 2019 16:37:05 +1100 Subject: [PATCH 08/11] Update docs not to use kibana_user role --- .../authorization/built-in-roles.asciidoc | 30 +++++++++++++------ .../cross-cluster-kibana.asciidoc | 5 ++-- .../en/security/get-started-security.asciidoc | 9 +++--- 3 files changed, 29 insertions(+), 15 deletions(-) diff --git a/x-pack/docs/en/security/authorization/built-in-roles.asciidoc b/x-pack/docs/en/security/authorization/built-in-roles.asciidoc index 55d12709124f4..275430aebf082 100644 --- a/x-pack/docs/en/security/authorization/built-in-roles.asciidoc +++ b/x-pack/docs/en/security/authorization/built-in-roles.asciidoc @@ -72,10 +72,12 @@ NOTE: This role does *not* provide the ability to create indices; those privileg must be defined in a separate role. [[built-in-roles-kibana-dashboard]] `kibana_dashboard_only_user` :: -Grants access to the {kib} Dashboard and read-only permissions to Kibana. -This role does not have access to editing tools in {kib}. For more -information, see -{kibana-ref}/xpack-dashboard-only-mode.html[{kib} Dashboard Only Mode]. +(This role is deprecated, please use +{kibana-ref}/kibana-privileges.html#kibana-feature-privileges[{kib} feature privileges] +instead). +Grants access to the {kib} Dashboard and read-only permissions to every +{kibana-ref}/xpack-spaces.html[Space in {kib}]. +This role does not have access to editing tools in {kib}. [[built-in-roles-kibana-system]] `kibana_system` :: Grants access necessary for the {kib} system user to read from and write to the @@ -87,8 +89,14 @@ see {kibana-ref}/using-kibana-with-security.html[Configuring Security in {kib}]. NOTE: This role should not be assigned to users as the granted permissions may change between releases. +[[built-in-roles-kibana-admin]] `kibana_admin`:: +Grants access to all features in {kib}. For more information on {kib} authorization, +see {kibana-ref}/xpack-security-authorization.html[Kibana Authorization]. + [[built-in-roles-kibana-user]] `kibana_user`:: -Grants access to all features in {kib}. For more information on Kibana authorization, +(This role is deprecated, please use the +<> role instead.) +Grants access to all features in {kib}. For more information on {kib} authorization, see {kibana-ref}/xpack-security-authorization.html[Kibana Authorization]. [[built-in-roles-logstash-admin]] `logstash_admin` :: @@ -127,7 +135,10 @@ Grants the minimum privileges required for any user of {monitoring} other than t required to use {kib}. This role grants access to the monitoring indices and grants privileges necessary for reading basic cluster information. This role also includes all {kibana-ref}/kibana-privileges.html[Kibana privileges] for the {stack-monitor-features}. -Monitoring users should also be assigned the `kibana_user` role. +Monitoring users should also be assigned the `kibana_admin` role, or another role +with access to Monitoring +{kibana-ref}/kibana-privileges.html#kibana-feature-privileges[feature privilege] +in {kib} [[built-in-roles-remote-monitoring-agent]] `remote_monitoring_agent`:: Grants the minimum privileges required to write data into the monitoring indices @@ -140,9 +151,10 @@ Grants the minimum privileges required to collect monitoring data for the {stack [[built-in-roles-reporting-user]] `reporting_user`:: Grants the specific privileges required for users of {reporting} other than those required to use {kib}. This role grants access to the reporting indices; each -user has access to only their own reports. Reporting users should also be -assigned the `kibana_user` role and a role that grants them access to the data -that will be used to generate reports. +user has access to only their own reports. +Reporting users should also be assigned additional roles with that grant +{kibana-ref}/xpack-security-authorization.html[Access to {kib}] as well as read +access to the <> that will be used to generate reports. [[built-in-roles-snapshot-user]] `snapshot_user`:: Grants the necessary privileges to create snapshots of **all** the indices and diff --git a/x-pack/docs/en/security/ccs-clients-integrations/cross-cluster-kibana.asciidoc b/x-pack/docs/en/security/ccs-clients-integrations/cross-cluster-kibana.asciidoc index 95e5d188f0084..81e2c2384acfe 100644 --- a/x-pack/docs/en/security/ccs-clients-integrations/cross-cluster-kibana.asciidoc +++ b/x-pack/docs/en/security/ccs-clients-integrations/cross-cluster-kibana.asciidoc @@ -31,8 +31,9 @@ NOTE: If you configure the local cluster as another remote in {es}, the `logstash_reader` role on your local cluster also needs to grant the `read_cross_cluster` privilege. -. Assign your {kib} users the `kibana_user` role and your `logstash_reader` -role. +. Assign your {kib} users a role that grants +{kibana-ref}/xpack-security-authorization.html[Access to {kib}] +as well as your `logstash_reader` role. . On the remote cluster, create a `logstash_reader` role that grants the `read_cross_cluster` privilege and `read` and `view_index_metadata` privileges diff --git a/x-pack/docs/en/security/get-started-security.asciidoc b/x-pack/docs/en/security/get-started-security.asciidoc index dca72e6e1d4ba..982ab505a5971 100644 --- a/x-pack/docs/en/security/get-started-security.asciidoc +++ b/x-pack/docs/en/security/get-started-security.asciidoc @@ -168,15 +168,16 @@ Select a role to see more information about its privileges. For example, select the `kibana_system` role to see its list of cluster and index privileges. To learn more, see <>. -Let's assign the `kibana_user` role to your user. Go back to the -*Management / Security / Users* page and select your user. Add the `kibana_user` +Let's assign the `kibana_admin` role to your user. Go back to the +*Management / Security / Users* page and select your user. Add the `kibana_admin` role and save the change. For example: [role="screenshot"] image::security/images/assign-role.jpg["Assigning a role to a user in Kibana"] -This user now has access to all features in {kib}. For more information about granting -access to Kibana see {kibana-ref}/xpack-security-authorization.html[Kibana Authorization]. +This user now has administrative access to all features in {kib}. +For more information about granting access to Kibana see +{kibana-ref}/xpack-security-authorization.html[Kibana Authorization]. If you completed all of the steps in {stack-gs}/get-started-elastic-stack.html[Getting started with the {stack}], you should From 1fcba5234299f56aa512d963109e62ca53199260 Mon Sep 17 00:00:00 2001 From: Tim Vernum Date: Tue, 17 Dec 2019 16:57:29 +1100 Subject: [PATCH 09/11] Doc feedback from @legrego --- .../en/security/authorization/built-in-roles.asciidoc | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/x-pack/docs/en/security/authorization/built-in-roles.asciidoc b/x-pack/docs/en/security/authorization/built-in-roles.asciidoc index 275430aebf082..11e287814be86 100644 --- a/x-pack/docs/en/security/authorization/built-in-roles.asciidoc +++ b/x-pack/docs/en/security/authorization/built-in-roles.asciidoc @@ -75,7 +75,7 @@ must be defined in a separate role. (This role is deprecated, please use {kibana-ref}/kibana-privileges.html#kibana-feature-privileges[{kib} feature privileges] instead). -Grants access to the {kib} Dashboard and read-only permissions to every +Grants read-only access to the {kib} Dashboard in every {kibana-ref}/xpack-spaces.html[Space in {kib}]. This role does not have access to editing tools in {kib}. @@ -136,9 +136,7 @@ required to use {kib}. This role grants access to the monitoring indices and gra privileges necessary for reading basic cluster information. This role also includes all {kibana-ref}/kibana-privileges.html[Kibana privileges] for the {stack-monitor-features}. Monitoring users should also be assigned the `kibana_admin` role, or another role -with access to Monitoring -{kibana-ref}/kibana-privileges.html#kibana-feature-privileges[feature privilege] -in {kib} +with {kibana-ref}/xpack-security-authorization.html[access to the {kib} instance] [[built-in-roles-remote-monitoring-agent]] `remote_monitoring_agent`:: Grants the minimum privileges required to write data into the monitoring indices @@ -152,7 +150,7 @@ Grants the minimum privileges required to collect monitoring data for the {stack Grants the specific privileges required for users of {reporting} other than those required to use {kib}. This role grants access to the reporting indices; each user has access to only their own reports. -Reporting users should also be assigned additional roles with that grant +Reporting users should also be assigned additional roles that grant {kibana-ref}/xpack-security-authorization.html[Access to {kib}] as well as read access to the <> that will be used to generate reports. From df4c6e528bdf5dbcde2f99911f410449ffcd0e6c Mon Sep 17 00:00:00 2001 From: Tim Vernum Date: Mon, 13 Jan 2020 15:26:33 +1100 Subject: [PATCH 10/11] Rename example roles --- .../security/authentication/oidc-guide.asciidoc | 15 ++++++--------- .../security/authentication/saml-guide.asciidoc | 15 ++++++--------- 2 files changed, 12 insertions(+), 18 deletions(-) diff --git a/x-pack/docs/en/security/authentication/oidc-guide.asciidoc b/x-pack/docs/en/security/authentication/oidc-guide.asciidoc index 758c366e171fc..b4e647b4a3c97 100644 --- a/x-pack/docs/en/security/authentication/oidc-guide.asciidoc +++ b/x-pack/docs/en/security/authentication/oidc-guide.asciidoc @@ -420,14 +420,14 @@ through either the NOTE: You cannot use <> to grant roles to users authenticating via OpenID Connect. -This is an example of a simple role mapping that grants the `siem_view` role +This is an example of a simple role mapping that grants the `example_role` role to any user who authenticates against the `oidc1` OpenID Connect realm: [source,console] -------------------------------------------------- -PUT /_security/role_mapping/oidc-kibana +PUT /_security/role_mapping/oidc-example { - "roles": [ "siem_view" ], <1> + "roles": [ "example_role" ], <1> "enabled": true, "rules": { "field": { "realm.name": "oidc1" } @@ -435,13 +435,10 @@ PUT /_security/role_mapping/oidc-kibana } -------------------------------------------------- -<1> The `siem_view` role is *not* a builtin Elasticsearch role. +<1> The `example_role` role is *not* a builtin Elasticsearch role. This example assumes that you have created a custom role of your own, with -`read` access to your SIEM <> and `Read` access to -the SIEM application using -{kibana-ref}/kibana-privileges.html#kibana-feature-privileges[Kibana feature privileges]. -You should create your own roles that provide access to the features that your -users need. +appropriate access to your <> and +{kibana-ref}/kibana-privileges.html#kibana-feature-privileges[Kibana features]. The user properties that are mapped via the realm configuration are used to process role mapping rules, and these rules determine which roles a user is granted. diff --git a/x-pack/docs/en/security/authentication/saml-guide.asciidoc b/x-pack/docs/en/security/authentication/saml-guide.asciidoc index f94e7df0413b3..c100ef161c755 100644 --- a/x-pack/docs/en/security/authentication/saml-guide.asciidoc +++ b/x-pack/docs/en/security/authentication/saml-guide.asciidoc @@ -639,14 +639,14 @@ through either the NOTE: You cannot use <> to grant roles to users authenticating via SAML. -This is an example of a simple role mapping that grants the `siem_view` role +This is an example of a simple role mapping that grants the `example_role` role to any user who authenticates against the `saml1` realm: [source,console] -------------------------------------------------- -PUT /_security/role_mapping/saml-kibana +PUT /_security/role_mapping/saml-example { - "roles": [ "siem_view" ], <1> + "roles": [ "example_role" ], <1> "enabled": true, "rules": { "field": { "realm.name": "saml1" } @@ -654,13 +654,10 @@ PUT /_security/role_mapping/saml-kibana } -------------------------------------------------- -<1> The `siem_view` role is *not* a builtin Elasticsearch role. +<1> The `example_role` role is *not* a builtin Elasticsearch role. This example assumes that you have created a custom role of your own, with -`read` access to your SIEM <> and `Read` access to -the SIEM application using -{kibana-ref}/kibana-privileges.html#kibana-feature-privileges[Kibana feature privileges]. -You should create your own roles that provide access to the features that your -users need. +appropriate access to your <> and +{kibana-ref}/kibana-privileges.html#kibana-feature-privileges[Kibana features]. The attributes that are mapped via the realm configuration are used to process role mapping rules, and these rules determine which roles a user is granted. From 54112e06904f3a95a57f086b6471fb00ab64be10 Mon Sep 17 00:00:00 2001 From: Tim Vernum Date: Tue, 14 Jan 2020 14:59:04 +1100 Subject: [PATCH 11/11] Apply docs feedback --- .../en/security/authorization/built-in-roles.asciidoc | 10 +++++----- .../cross-cluster-kibana.asciidoc | 2 +- x-pack/docs/en/security/get-started-security.asciidoc | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/x-pack/docs/en/security/authorization/built-in-roles.asciidoc b/x-pack/docs/en/security/authorization/built-in-roles.asciidoc index 11e287814be86..60043e62f94ed 100644 --- a/x-pack/docs/en/security/authorization/built-in-roles.asciidoc +++ b/x-pack/docs/en/security/authorization/built-in-roles.asciidoc @@ -76,7 +76,7 @@ must be defined in a separate role. {kibana-ref}/kibana-privileges.html#kibana-feature-privileges[{kib} feature privileges] instead). Grants read-only access to the {kib} Dashboard in every -{kibana-ref}/xpack-spaces.html[Space in {kib}]. +{kibana-ref}/xpack-spaces.html[space in {kib}]. This role does not have access to editing tools in {kib}. [[built-in-roles-kibana-system]] `kibana_system` :: @@ -91,13 +91,13 @@ change between releases. [[built-in-roles-kibana-admin]] `kibana_admin`:: Grants access to all features in {kib}. For more information on {kib} authorization, -see {kibana-ref}/xpack-security-authorization.html[Kibana Authorization]. +see {kibana-ref}/xpack-security-authorization.html[Kibana authorization]. [[built-in-roles-kibana-user]] `kibana_user`:: (This role is deprecated, please use the <> role instead.) Grants access to all features in {kib}. For more information on {kib} authorization, -see {kibana-ref}/xpack-security-authorization.html[Kibana Authorization]. +see {kibana-ref}/xpack-security-authorization.html[Kibana authorization]. [[built-in-roles-logstash-admin]] `logstash_admin` :: Grants access to the `.logstash*` indices for managing configurations. @@ -136,7 +136,7 @@ required to use {kib}. This role grants access to the monitoring indices and gra privileges necessary for reading basic cluster information. This role also includes all {kibana-ref}/kibana-privileges.html[Kibana privileges] for the {stack-monitor-features}. Monitoring users should also be assigned the `kibana_admin` role, or another role -with {kibana-ref}/xpack-security-authorization.html[access to the {kib} instance] +with {kibana-ref}/xpack-security-authorization.html[access to the {kib} instance]. [[built-in-roles-remote-monitoring-agent]] `remote_monitoring_agent`:: Grants the minimum privileges required to write data into the monitoring indices @@ -151,7 +151,7 @@ Grants the specific privileges required for users of {reporting} other than thos required to use {kib}. This role grants access to the reporting indices; each user has access to only their own reports. Reporting users should also be assigned additional roles that grant -{kibana-ref}/xpack-security-authorization.html[Access to {kib}] as well as read +{kibana-ref}/xpack-security-authorization.html[access to {kib}] as well as read access to the <> that will be used to generate reports. [[built-in-roles-snapshot-user]] `snapshot_user`:: diff --git a/x-pack/docs/en/security/ccs-clients-integrations/cross-cluster-kibana.asciidoc b/x-pack/docs/en/security/ccs-clients-integrations/cross-cluster-kibana.asciidoc index 81e2c2384acfe..f9bcd86889c17 100644 --- a/x-pack/docs/en/security/ccs-clients-integrations/cross-cluster-kibana.asciidoc +++ b/x-pack/docs/en/security/ccs-clients-integrations/cross-cluster-kibana.asciidoc @@ -32,7 +32,7 @@ NOTE: If you configure the local cluster as another remote in {es}, the `read_cross_cluster` privilege. . Assign your {kib} users a role that grants -{kibana-ref}/xpack-security-authorization.html[Access to {kib}] +{kibana-ref}/xpack-security-authorization.html[access to {kib}] as well as your `logstash_reader` role. . On the remote cluster, create a `logstash_reader` role that grants the diff --git a/x-pack/docs/en/security/get-started-security.asciidoc b/x-pack/docs/en/security/get-started-security.asciidoc index 982ab505a5971..82f443016021f 100644 --- a/x-pack/docs/en/security/get-started-security.asciidoc +++ b/x-pack/docs/en/security/get-started-security.asciidoc @@ -177,7 +177,7 @@ image::security/images/assign-role.jpg["Assigning a role to a user in Kibana"] This user now has administrative access to all features in {kib}. For more information about granting access to Kibana see -{kibana-ref}/xpack-security-authorization.html[Kibana Authorization]. +{kibana-ref}/xpack-security-authorization.html[Kibana authorization]. If you completed all of the steps in {stack-gs}/get-started-elastic-stack.html[Getting started with the {stack}], you should