From 0e7869128a68a159641bdbb9165407f67f836d9f Mon Sep 17 00:00:00 2001 From: Hendrik Muhs Date: Thu, 10 Oct 2019 10:31:24 +0200 Subject: [PATCH] [7.5][Transform] introduce new roles and deprecate old ones (#47780) (#47819) deprecate data_frame_transforms_{user,admin} roles and introduce transform_{user,admin} roles as replacement --- .../client/security/user/privileges/Role.java | 12 +- .../SecurityDocumentationIT.java | 11 +- .../security/get-builtin-privileges.asciidoc | 2 + .../privilege/ClusterPrivilegeResolver.java | 22 ++- .../authz/store/ReservedRolesStore.java | 29 +++- .../TransformInternalIndexConstants.java | 6 +- .../authz/store/ReservedRolesStoreTests.java | 138 +++++++++++------- .../test/privileges/11_builtin.yml | 2 +- .../TransformGetAndGetStatsIT.java | 11 +- .../integration/TransformPivotRestIT.java | 8 +- .../upgrades/TransformSurvivesUpgradeIT.java | 49 +++++-- .../test/rest/XPackRestTestConstants.java | 11 +- 12 files changed, 205 insertions(+), 96 deletions(-) diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/security/user/privileges/Role.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/security/user/privileges/Role.java index c1eae86c9f1..ba98dc6c6eb 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/security/user/privileges/Role.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/security/user/privileges/Role.java @@ -24,8 +24,8 @@ import org.elasticsearch.common.ParseField; import org.elasticsearch.common.Strings; import org.elasticsearch.common.collect.Tuple; import org.elasticsearch.common.xcontent.ConstructingObjectParser; -import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.ObjectParser.ValueType; +import org.elasticsearch.common.xcontent.XContentParser; import java.util.Arrays; import java.util.Collection; @@ -299,12 +299,14 @@ public final class Role { public static final String NONE = "none"; public static final String ALL = "all"; public static final String MONITOR = "monitor"; - public static final String MONITOR_DATA_FRAME_TRANSFORMS = "monitor_data_frame_transforms"; + public static final String MONITOR_TRANSFORM_DEPRECATED = "monitor_data_frame_transforms"; + public static final String MONITOR_TRANSFORM = "monitor_transform"; public static final String MONITOR_ML = "monitor_ml"; public static final String MONITOR_WATCHER = "monitor_watcher"; public static final String MONITOR_ROLLUP = "monitor_rollup"; public static final String MANAGE = "manage"; - public static final String MANAGE_DATA_FRAME_TRANSFORMS = "manage_data_frame_transforms"; + public static final String MANAGE_TRANSFORM_DEPRECATED = "manage_data_frame_transforms"; + public static final String MANAGE_TRANSFORM = "manage_transform"; public static final String MANAGE_ML = "manage_ml"; public static final String MANAGE_WATCHER = "manage_watcher"; public static final String MANAGE_ROLLUP = "manage_rollup"; @@ -320,8 +322,8 @@ public final class Role { public static final String READ_CCR = "read_ccr"; public static final String MANAGE_ILM = "manage_ilm"; public static final String READ_ILM = "read_ilm"; - public static final String[] ALL_ARRAY = new String[] { NONE, ALL, MONITOR, MONITOR_DATA_FRAME_TRANSFORMS, MONITOR_ML, - MONITOR_WATCHER, MONITOR_ROLLUP, MANAGE, MANAGE_DATA_FRAME_TRANSFORMS, + public static final String[] ALL_ARRAY = new String[] { NONE, ALL, MONITOR, MONITOR_TRANSFORM_DEPRECATED, MONITOR_TRANSFORM, + MONITOR_ML, MONITOR_WATCHER, MONITOR_ROLLUP, MANAGE, MANAGE_TRANSFORM_DEPRECATED, MANAGE_TRANSFORM, MANAGE_ML, MANAGE_WATCHER, MANAGE_ROLLUP, MANAGE_INDEX_TEMPLATES, MANAGE_INGEST_PIPELINES, TRANSPORT_CLIENT, MANAGE_SECURITY, MANAGE_SAML, MANAGE_OIDC, MANAGE_TOKEN, MANAGE_PIPELINE, MANAGE_CCR, READ_CCR, MANAGE_ILM, READ_ILM}; } 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 1bc0520ce45..cdf7fb16a40 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 @@ -28,6 +28,7 @@ import org.elasticsearch.client.ESRestHighLevelClientTestCase; import org.elasticsearch.client.RequestOptions; import org.elasticsearch.client.RestHighLevelClient; import org.elasticsearch.client.security.AuthenticateResponse; +import org.elasticsearch.client.security.AuthenticateResponse.RealmInfo; import org.elasticsearch.client.security.ChangePasswordRequest; import org.elasticsearch.client.security.ClearRealmCacheRequest; import org.elasticsearch.client.security.ClearRealmCacheResponse; @@ -79,7 +80,6 @@ import org.elasticsearch.client.security.PutUserRequest; import org.elasticsearch.client.security.PutUserResponse; import org.elasticsearch.client.security.RefreshPolicy; import org.elasticsearch.client.security.TemplateRoleName; -import org.elasticsearch.client.security.AuthenticateResponse.RealmInfo; import org.elasticsearch.client.security.support.ApiKey; import org.elasticsearch.client.security.support.CertificateInfo; import org.elasticsearch.client.security.support.expressiondsl.RoleMapperExpression; @@ -99,8 +99,6 @@ import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.util.set.Sets; import org.hamcrest.Matchers; -import javax.crypto.SecretKeyFactory; -import javax.crypto.spec.PBEKeySpec; import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; @@ -120,6 +118,9 @@ import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.PBEKeySpec; + import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.containsString; @@ -679,8 +680,8 @@ public class SecurityDocumentationIT extends ESRestHighLevelClientTestCase { List roles = response.getRoles(); assertNotNull(response); - // 27 system roles plus the three we created - assertThat(roles.size(), equalTo(30)); + // 29 system roles plus the three we created + assertThat(roles.size(), equalTo(32)); } { diff --git a/x-pack/docs/en/rest-api/security/get-builtin-privileges.asciidoc b/x-pack/docs/en/rest-api/security/get-builtin-privileges.asciidoc index d2a329b9638..aaa9f718979 100644 --- a/x-pack/docs/en/rest-api/security/get-builtin-privileges.asciidoc +++ b/x-pack/docs/en/rest-api/security/get-builtin-privileges.asciidoc @@ -80,11 +80,13 @@ A successful call returns an object with "cluster" and "index" fields. "manage_security", "manage_slm", "manage_token", + "manage_transform", "manage_watcher", "monitor", "monitor_data_frame_transforms", "monitor_ml", "monitor_rollup", + "monitor_transform", "monitor_watcher", "none", "read_ccr", diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/privilege/ClusterPrivilegeResolver.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/privilege/ClusterPrivilegeResolver.java index af599c878c4..57a4325062f 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/privilege/ClusterPrivilegeResolver.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/privilege/ClusterPrivilegeResolver.java @@ -50,7 +50,7 @@ public class ClusterPrivilegeResolver { private static final Set MANAGE_TOKEN_PATTERN = Collections.singleton("cluster:admin/xpack/security/token/*"); private static final Set MANAGE_API_KEY_PATTERN = Collections.singleton("cluster:admin/xpack/security/api_key/*"); private static final Set MONITOR_PATTERN = Collections.singleton("cluster:monitor/*"); - private static final Set MONITOR_DATA_FRAME_PATTERN = Collections.unmodifiableSet( + private static final Set MONITOR_TRANSFORM_PATTERN = Collections.unmodifiableSet( Sets.newHashSet("cluster:monitor/data_frame/*", "cluster:monitor/transform/*")); private static final Set MONITOR_ML_PATTERN = Collections.singleton("cluster:monitor/xpack/ml/*"); private static final Set MONITOR_WATCHER_PATTERN = Collections.singleton("cluster:monitor/xpack/watcher/*"); @@ -59,7 +59,7 @@ public class ClusterPrivilegeResolver { Sets.newHashSet("cluster:*", "indices:admin/template/*")); private static final Set MANAGE_ML_PATTERN = Collections.unmodifiableSet( Sets.newHashSet("cluster:admin/xpack/ml/*", "cluster:monitor/xpack/ml/*")); - private static final Set MANAGE_DATA_FRAME_PATTERN = Collections.unmodifiableSet( + private static final Set MANAGE_TRANSFORM_PATTERN = Collections.unmodifiableSet( Sets.newHashSet("cluster:admin/data_frame/*", "cluster:monitor/data_frame/*", "cluster:monitor/transform/*", "cluster:admin/transform/*")); private static final Set MANAGE_WATCHER_PATTERN = Collections.unmodifiableSet( @@ -89,14 +89,18 @@ public class ClusterPrivilegeResolver { public static final NamedClusterPrivilege ALL = new ActionClusterPrivilege("all", ALL_CLUSTER_PATTERN); public static final NamedClusterPrivilege MONITOR = new ActionClusterPrivilege("monitor", MONITOR_PATTERN); public static final NamedClusterPrivilege MONITOR_ML = new ActionClusterPrivilege("monitor_ml", MONITOR_ML_PATTERN); - public static final NamedClusterPrivilege MONITOR_DATA_FRAME = - new ActionClusterPrivilege("monitor_data_frame_transforms", MONITOR_DATA_FRAME_PATTERN); + public static final NamedClusterPrivilege MONITOR_TRANSFORM_DEPRECATED = + new ActionClusterPrivilege("monitor_data_frame_transforms", MONITOR_TRANSFORM_PATTERN); + public static final NamedClusterPrivilege MONITOR_TRANSFORM = + new ActionClusterPrivilege("monitor_transform", MONITOR_TRANSFORM_PATTERN); public static final NamedClusterPrivilege MONITOR_WATCHER = new ActionClusterPrivilege("monitor_watcher", MONITOR_WATCHER_PATTERN); public static final NamedClusterPrivilege MONITOR_ROLLUP = new ActionClusterPrivilege("monitor_rollup", MONITOR_ROLLUP_PATTERN); public static final NamedClusterPrivilege MANAGE = new ActionClusterPrivilege("manage", ALL_CLUSTER_PATTERN, ALL_SECURITY_PATTERN); public static final NamedClusterPrivilege MANAGE_ML = new ActionClusterPrivilege("manage_ml", MANAGE_ML_PATTERN); - public static final NamedClusterPrivilege MANAGE_DATA_FRAME = - new ActionClusterPrivilege("manage_data_frame_transforms", MANAGE_DATA_FRAME_PATTERN); + public static final NamedClusterPrivilege MANAGE_TRANSFORM_DEPRECATED = + new ActionClusterPrivilege("manage_data_frame_transforms", MANAGE_TRANSFORM_PATTERN); + public static final NamedClusterPrivilege MANAGE_TRANSFORM = + new ActionClusterPrivilege("manage_transform", MANAGE_TRANSFORM_PATTERN); public static final NamedClusterPrivilege MANAGE_TOKEN = new ActionClusterPrivilege("manage_token", MANAGE_TOKEN_PATTERN); public static final NamedClusterPrivilege MANAGE_WATCHER = new ActionClusterPrivilege("manage_watcher", MANAGE_WATCHER_PATTERN); public static final NamedClusterPrivilege MANAGE_ROLLUP = new ActionClusterPrivilege("manage_rollup", MANAGE_ROLLUP_PATTERN); @@ -131,12 +135,14 @@ public class ClusterPrivilegeResolver { ALL, MONITOR, MONITOR_ML, - MONITOR_DATA_FRAME, + MONITOR_TRANSFORM_DEPRECATED, + MONITOR_TRANSFORM, MONITOR_WATCHER, MONITOR_ROLLUP, MANAGE, MANAGE_ML, - MANAGE_DATA_FRAME, + MANAGE_TRANSFORM_DEPRECATED, + MANAGE_TRANSFORM, MANAGE_TOKEN, MANAGE_WATCHER, MANAGE_IDX_TEMPLATES, 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 fcd0c24606e..1bd9478382b 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 @@ -17,6 +17,7 @@ import org.elasticsearch.xpack.core.security.authz.privilege.ConfigurableCluster import org.elasticsearch.xpack.core.security.support.MetadataUtils; import org.elasticsearch.xpack.core.security.user.KibanaUser; import org.elasticsearch.xpack.core.security.user.UsernamesField; +import org.elasticsearch.xpack.core.transform.transforms.persistence.TransformInternalIndexConstants; import org.elasticsearch.xpack.core.watcher.execution.TriggeredWatchStoreField; import org.elasticsearch.xpack.core.watcher.history.HistoryStoreField; import org.elasticsearch.xpack.core.watcher.watch.Watch; @@ -179,28 +180,52 @@ public class ReservedRolesStore implements BiConsumer, ActionListene .application("kibana-*").resources("*").privileges("reserved_ml").build() }, null, null, MetadataUtils.DEFAULT_RESERVED_METADATA, null)) + // DEPRECATED: to be removed in 9.0.0 .put("data_frame_transforms_admin", new RoleDescriptor("data_frame_transforms_admin", new String[] { "manage_data_frame_transforms" }, new RoleDescriptor.IndicesPrivileges[]{ RoleDescriptor.IndicesPrivileges.builder() - .indices(".data-frame-notifications*") + .indices(TransformInternalIndexConstants.AUDIT_INDEX_PATTERN, + TransformInternalIndexConstants.AUDIT_INDEX_PATTERN_DEPRECATED, + TransformInternalIndexConstants.AUDIT_INDEX_READ_ALIAS) .privileges("view_index_metadata", "read").build() }, new RoleDescriptor.ApplicationResourcePrivileges[] { RoleDescriptor.ApplicationResourcePrivileges.builder() .application("kibana-*").resources("*").privileges("reserved_ml").build() }, null, null, MetadataUtils.DEFAULT_RESERVED_METADATA, null)) + // DEPRECATED: to be removed in 9.0.0 .put("data_frame_transforms_user", new RoleDescriptor("data_frame_transforms_user", new String[] { "monitor_data_frame_transforms" }, new RoleDescriptor.IndicesPrivileges[]{ RoleDescriptor.IndicesPrivileges.builder() - .indices(".data-frame-notifications*") + .indices(TransformInternalIndexConstants.AUDIT_INDEX_PATTERN, + TransformInternalIndexConstants.AUDIT_INDEX_PATTERN_DEPRECATED, + TransformInternalIndexConstants.AUDIT_INDEX_READ_ALIAS) .privileges("view_index_metadata", "read").build() }, new RoleDescriptor.ApplicationResourcePrivileges[] { RoleDescriptor.ApplicationResourcePrivileges.builder() .application("kibana-*").resources("*").privileges("reserved_ml").build() }, null, null, MetadataUtils.DEFAULT_RESERVED_METADATA, null)) + .put("transform_admin", new RoleDescriptor("transform_admin", + new String[] { "manage_transform" }, + new RoleDescriptor.IndicesPrivileges[]{ + RoleDescriptor.IndicesPrivileges.builder() + .indices(TransformInternalIndexConstants.AUDIT_INDEX_PATTERN, + TransformInternalIndexConstants.AUDIT_INDEX_PATTERN_DEPRECATED, + TransformInternalIndexConstants.AUDIT_INDEX_READ_ALIAS) + .privileges("view_index_metadata", "read").build() + }, null, null, null, MetadataUtils.DEFAULT_RESERVED_METADATA, null)) + .put("transform_user", new RoleDescriptor("transform_user", + new String[] { "monitor_transform" }, + new RoleDescriptor.IndicesPrivileges[]{ + RoleDescriptor.IndicesPrivileges.builder() + .indices(TransformInternalIndexConstants.AUDIT_INDEX_PATTERN, + TransformInternalIndexConstants.AUDIT_INDEX_PATTERN_DEPRECATED, + TransformInternalIndexConstants.AUDIT_INDEX_READ_ALIAS) + .privileges("view_index_metadata", "read").build() + }, null, null, null, MetadataUtils.DEFAULT_RESERVED_METADATA, null)) .put("watcher_admin", new RoleDescriptor("watcher_admin", new String[] { "manage_watcher" }, new RoleDescriptor.IndicesPrivileges[] { RoleDescriptor.IndicesPrivileges.builder().indices(Watch.INDEX, TriggeredWatchStoreField.INDEX_NAME, diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/transform/transforms/persistence/TransformInternalIndexConstants.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/transform/transforms/persistence/TransformInternalIndexConstants.java index dcf8707e87c..f0828c281ce 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/transform/transforms/persistence/TransformInternalIndexConstants.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/transform/transforms/persistence/TransformInternalIndexConstants.java @@ -30,7 +30,11 @@ public final class TransformInternalIndexConstants { // audit index public static final String AUDIT_TEMPLATE_VERSION = "1"; - public static final String AUDIT_INDEX_PREFIX = ".data-frame-notifications-"; + public static final String AUDIT_INDEX_PREFIX = ".transform-notifications-"; + public static final String AUDIT_INDEX_PATTERN = AUDIT_INDEX_PREFIX + "*"; + public static final String AUDIT_INDEX_PATTERN_DEPRECATED = ".data-frame-notifications-*"; + + public static final String AUDIT_INDEX_READ_ALIAS = ".transform-notifications-read"; public static final String AUDIT_INDEX = AUDIT_INDEX_PREFIX + AUDIT_TEMPLATE_VERSION; private TransformInternalIndexConstants() { 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 9c23def4283..6174075e2b5 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 @@ -186,6 +186,8 @@ public class ReservedRolesStoreTests extends ESTestCase { assertThat(ReservedRolesStore.isReserved("machine_learning_admin"), is(true)); assertThat(ReservedRolesStore.isReserved("data_frame_transforms_user"), is(true)); assertThat(ReservedRolesStore.isReserved("data_frame_transforms_admin"), is(true)); + assertThat(ReservedRolesStore.isReserved("transform_user"), is(true)); + assertThat(ReservedRolesStore.isReserved("transform_admin"), is(true)); assertThat(ReservedRolesStore.isReserved("watcher_user"), is(true)); assertThat(ReservedRolesStore.isReserved("watcher_admin"), is(true)); assertThat(ReservedRolesStore.isReserved("kibana_dashboard_only_user"), is(true)); @@ -1121,82 +1123,108 @@ public class ReservedRolesStoreTests extends ESTestCase { new ApplicationPrivilege(otherApplication, "app-reserved_ml", "reserved_ml"), "*"), is(false)); } - public void testDataFrameTransformsAdminRole() { + public void testTransformAdminRole() { final TransportRequest request = mock(TransportRequest.class); final Authentication authentication = mock(Authentication.class); - RoleDescriptor roleDescriptor = new ReservedRolesStore().roleDescriptor("data_frame_transforms_admin"); - assertNotNull(roleDescriptor); - assertThat(roleDescriptor.getMetadata(), hasEntry("_reserved", true)); + RoleDescriptor[] roleDescriptors = { + new ReservedRolesStore().roleDescriptor("data_frame_transforms_admin"), + new ReservedRolesStore().roleDescriptor("transform_admin") + }; - Role role = Role.builder(roleDescriptor, null).build(); - assertThat(role.cluster().check(DeleteTransformAction.NAME, request, authentication), is(true)); - assertThat(role.cluster().check(GetTransformAction.NAME, request, authentication), is(true)); - assertThat(role.cluster().check(GetTransformStatsAction.NAME, request, authentication), is(true)); - assertThat(role.cluster().check(PreviewTransformAction.NAME, request, authentication), is(true)); - assertThat(role.cluster().check(PutTransformAction.NAME, request, authentication), is(true)); - assertThat(role.cluster().check(StartTransformAction.NAME, request, authentication), is(true)); - assertThat(role.cluster().check(StopTransformAction.NAME, request, authentication), is(true)); - assertThat(role.cluster().check(DelegatePkiAuthenticationAction.NAME, request, authentication), is(false)); + for (RoleDescriptor roleDescriptor : roleDescriptors) { + assertNotNull(roleDescriptor); + assertThat(roleDescriptor.getMetadata(), hasEntry("_reserved", true)); - assertThat(role.runAs().check(randomAlphaOfLengthBetween(1, 30)), is(false)); + Role role = Role.builder(roleDescriptor, null).build(); + assertThat(role.cluster().check(DeleteTransformAction.NAME, request, authentication), is(true)); + assertThat(role.cluster().check(GetTransformAction.NAME, request, authentication), is(true)); + assertThat(role.cluster().check(GetTransformStatsAction.NAME, request, authentication), is(true)); + assertThat(role.cluster().check(PreviewTransformAction.NAME, request, authentication), is(true)); + assertThat(role.cluster().check(PutTransformAction.NAME, request, authentication), is(true)); + assertThat(role.cluster().check(StartTransformAction.NAME, request, authentication), is(true)); + assertThat(role.cluster().check(StopTransformAction.NAME, request, authentication), is(true)); + assertThat(role.cluster().check(DelegatePkiAuthenticationAction.NAME, request, authentication), is(false)); - assertOnlyReadAllowed(role, TransformInternalIndexConstants.AUDIT_INDEX); - assertNoAccessAllowed(role, "foo"); - assertNoAccessAllowed(role, TransformInternalIndexConstants.LATEST_INDEX_NAME); // internal use only + assertThat(role.runAs().check(randomAlphaOfLengthBetween(1, 30)), is(false)); - assertNoAccessAllowed(role, RestrictedIndicesNames.RESTRICTED_NAMES); + assertOnlyReadAllowed(role, TransformInternalIndexConstants.AUDIT_INDEX_READ_ALIAS); + assertOnlyReadAllowed(role, TransformInternalIndexConstants.AUDIT_INDEX_PATTERN); + assertOnlyReadAllowed(role, TransformInternalIndexConstants.AUDIT_INDEX_PATTERN_DEPRECATED); + assertNoAccessAllowed(role, "foo"); + assertNoAccessAllowed(role, TransformInternalIndexConstants.LATEST_INDEX_NAME); // internal use only - final String kibanaApplicationWithRandomIndex = "kibana-" + randomFrom(randomAlphaOfLengthBetween(8, 24), ".kibana"); - assertThat(role.application().grants( - new ApplicationPrivilege(kibanaApplicationWithRandomIndex, "app-foo", "foo"), "*"), is(false)); - assertThat(role.application().grants( - new ApplicationPrivilege(kibanaApplicationWithRandomIndex, "app-reserved_ml", "reserved_ml"), "*"), is(true)); + assertNoAccessAllowed(role, RestrictedIndicesNames.RESTRICTED_NAMES); - final String otherApplication = "logstash-" + randomAlphaOfLengthBetween(8, 24); - assertThat(role.application().grants( - new ApplicationPrivilege(otherApplication, "app-foo", "foo"), "*"), is(false)); - assertThat(role.application().grants( - new ApplicationPrivilege(otherApplication, "app-reserved_ml", "reserved_ml"), "*"), is(false)); + final String kibanaApplicationWithRandomIndex = "kibana-" + randomFrom(randomAlphaOfLengthBetween(8, 24), ".kibana"); + assertThat(role.application().grants( + new ApplicationPrivilege(kibanaApplicationWithRandomIndex, "app-foo", "foo"), "*"), is(false)); + + if (roleDescriptor.getName().equals("data_frame_transforms_admin")) { + assertThat(role.application() + .grants(new ApplicationPrivilege(kibanaApplicationWithRandomIndex, "app-reserved_ml", "reserved_ml"), "*"), is(true)); + } + + final String otherApplication = "logstash-" + randomAlphaOfLengthBetween(8, 24); + assertThat(role.application().grants( + new ApplicationPrivilege(otherApplication, "app-foo", "foo"), "*"), is(false)); + if (roleDescriptor.getName().equals("data_frame_transforms_admin")) { + assertThat(role.application().grants( + new ApplicationPrivilege(otherApplication, "app-reserved_ml", "reserved_ml"), "*"), is(false)); + } + } } public void testDataFrameTransformsUserRole() { final TransportRequest request = mock(TransportRequest.class); final Authentication authentication = mock(Authentication.class); - RoleDescriptor roleDescriptor = new ReservedRolesStore().roleDescriptor("data_frame_transforms_user"); - assertNotNull(roleDescriptor); - assertThat(roleDescriptor.getMetadata(), hasEntry("_reserved", true)); + RoleDescriptor[] roleDescriptors = { + new ReservedRolesStore().roleDescriptor("data_frame_transforms_user"), + new ReservedRolesStore().roleDescriptor("transform_user") + }; - Role role = Role.builder(roleDescriptor, null).build(); - assertThat(role.cluster().check(DeleteTransformAction.NAME, request, authentication), is(false)); - assertThat(role.cluster().check(GetTransformAction.NAME, request, authentication), is(true)); - assertThat(role.cluster().check(GetTransformStatsAction.NAME, request, authentication), is(true)); - assertThat(role.cluster().check(PreviewTransformAction.NAME, request, authentication), is(false)); - assertThat(role.cluster().check(PutTransformAction.NAME, request, authentication), is(false)); - assertThat(role.cluster().check(StartTransformAction.NAME, request, authentication), is(false)); - assertThat(role.cluster().check(StopTransformAction.NAME, request, authentication), is(false)); - assertThat(role.cluster().check(DelegatePkiAuthenticationAction.NAME, request, authentication), is(false)); + for (RoleDescriptor roleDescriptor : roleDescriptors) { + assertNotNull(roleDescriptor); + assertThat(roleDescriptor.getMetadata(), hasEntry("_reserved", true)); - assertThat(role.runAs().check(randomAlphaOfLengthBetween(1, 30)), is(false)); + Role role = Role.builder(roleDescriptor, null).build(); + assertThat(role.cluster().check(DeleteTransformAction.NAME, request, authentication), is(false)); + assertThat(role.cluster().check(GetTransformAction.NAME, request, authentication), is(true)); + assertThat(role.cluster().check(GetTransformStatsAction.NAME, request, authentication), is(true)); + assertThat(role.cluster().check(PreviewTransformAction.NAME, request, authentication), is(false)); + assertThat(role.cluster().check(PutTransformAction.NAME, request, authentication), is(false)); + assertThat(role.cluster().check(StartTransformAction.NAME, request, authentication), is(false)); + assertThat(role.cluster().check(StopTransformAction.NAME, request, authentication), is(false)); + assertThat(role.cluster().check(DelegatePkiAuthenticationAction.NAME, request, authentication), is(false)); - assertOnlyReadAllowed(role, TransformInternalIndexConstants.AUDIT_INDEX); - assertNoAccessAllowed(role, "foo"); - assertNoAccessAllowed(role, TransformInternalIndexConstants.LATEST_INDEX_NAME); + assertThat(role.runAs().check(randomAlphaOfLengthBetween(1, 30)), is(false)); - assertNoAccessAllowed(role, RestrictedIndicesNames.RESTRICTED_NAMES); + assertOnlyReadAllowed(role, TransformInternalIndexConstants.AUDIT_INDEX_READ_ALIAS); + assertOnlyReadAllowed(role, TransformInternalIndexConstants.AUDIT_INDEX_PATTERN); + assertOnlyReadAllowed(role, TransformInternalIndexConstants.AUDIT_INDEX_PATTERN_DEPRECATED); + assertNoAccessAllowed(role, "foo"); + assertNoAccessAllowed(role, TransformInternalIndexConstants.LATEST_INDEX_NAME); - final String kibanaApplicationWithRandomIndex = "kibana-" + randomFrom(randomAlphaOfLengthBetween(8, 24), ".kibana"); - assertThat(role.application().grants( - new ApplicationPrivilege(kibanaApplicationWithRandomIndex, "app-foo", "foo"), "*"), is(false)); - assertThat(role.application().grants( - new ApplicationPrivilege(kibanaApplicationWithRandomIndex, "app-reserved_ml", "reserved_ml"), "*"), is(true)); + assertNoAccessAllowed(role, RestrictedIndicesNames.RESTRICTED_NAMES); - final String otherApplication = "logstash-" + randomAlphaOfLengthBetween(8, 24); - assertThat(role.application().grants( - new ApplicationPrivilege(otherApplication, "app-foo", "foo"), "*"), is(false)); - assertThat(role.application().grants( - new ApplicationPrivilege(otherApplication, "app-reserved_ml", "reserved_ml"), "*"), is(false)); + final String kibanaApplicationWithRandomIndex = "kibana-" + randomFrom(randomAlphaOfLengthBetween(8, 24), ".kibana"); + assertThat(role.application().grants( + new ApplicationPrivilege(kibanaApplicationWithRandomIndex, "app-foo", "foo"), "*"), is(false)); + + if (roleDescriptor.getName().equals("data_frame_transforms_user")) { + assertThat(role.application().grants( + new ApplicationPrivilege(kibanaApplicationWithRandomIndex, "app-reserved_ml", "reserved_ml"), "*"), is(true)); + } + + final String otherApplication = "logstash-" + randomAlphaOfLengthBetween(8, 24); + assertThat(role.application().grants( + new ApplicationPrivilege(otherApplication, "app-foo", "foo"), "*"), is(false)); + if (roleDescriptor.getName().equals("data_frame_transforms_user")) { + assertThat(role.application().grants( + new ApplicationPrivilege(otherApplication, "app-reserved_ml", "reserved_ml"), "*"), is(false)); + } + } } public void testWatcherAdminRole() { diff --git a/x-pack/plugin/src/test/resources/rest-api-spec/test/privileges/11_builtin.yml b/x-pack/plugin/src/test/resources/rest-api-spec/test/privileges/11_builtin.yml index 9ac2fdf23c9..836977b0a0c 100644 --- a/x-pack/plugin/src/test/resources/rest-api-spec/test/privileges/11_builtin.yml +++ b/x-pack/plugin/src/test/resources/rest-api-spec/test/privileges/11_builtin.yml @@ -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" : 30 } + - length: { "cluster" : 32 } - length: { "index" : 17 } diff --git a/x-pack/plugin/transform/qa/single-node-tests/src/test/java/org/elasticsearch/xpack/transform/integration/TransformGetAndGetStatsIT.java b/x-pack/plugin/transform/qa/single-node-tests/src/test/java/org/elasticsearch/xpack/transform/integration/TransformGetAndGetStatsIT.java index 3ef271fb42e..8c80616fcd7 100644 --- a/x-pack/plugin/transform/qa/single-node-tests/src/test/java/org/elasticsearch/xpack/transform/integration/TransformGetAndGetStatsIT.java +++ b/x-pack/plugin/transform/qa/single-node-tests/src/test/java/org/elasticsearch/xpack/transform/integration/TransformGetAndGetStatsIT.java @@ -53,8 +53,15 @@ public class TransformGetAndGetStatsIT extends TransformRestTestCase { createReviewsIndex(); indicesCreated = true; - setupUser(TEST_USER_NAME, Collections.singletonList("data_frame_transforms_user")); - setupUser(TEST_ADMIN_USER_NAME, Collections.singletonList("data_frame_transforms_admin")); + + // at random test the old deprecated roles, to be removed in 9.0.0 + if (randomBoolean()) { + setupUser(TEST_USER_NAME, Collections.singletonList("transform_user")); + setupUser(TEST_ADMIN_USER_NAME, Collections.singletonList("transform_admin")); + } else { + setupUser(TEST_USER_NAME, Collections.singletonList("data_frame_transforms_user")); + setupUser(TEST_ADMIN_USER_NAME, Collections.singletonList("data_frame_transforms_admin")); + } } @After diff --git a/x-pack/plugin/transform/qa/single-node-tests/src/test/java/org/elasticsearch/xpack/transform/integration/TransformPivotRestIT.java b/x-pack/plugin/transform/qa/single-node-tests/src/test/java/org/elasticsearch/xpack/transform/integration/TransformPivotRestIT.java index 72e9a621d54..c47a191b19f 100644 --- a/x-pack/plugin/transform/qa/single-node-tests/src/test/java/org/elasticsearch/xpack/transform/integration/TransformPivotRestIT.java +++ b/x-pack/plugin/transform/qa/single-node-tests/src/test/java/org/elasticsearch/xpack/transform/integration/TransformPivotRestIT.java @@ -50,7 +50,13 @@ public class TransformPivotRestIT extends TransformRestTestCase { createReviewsIndex(); indicesCreated = true; setupDataAccessRole(DATA_ACCESS_ROLE, REVIEWS_INDEX_NAME); - setupUser(TEST_USER_NAME, Arrays.asList("data_frame_transforms_admin", DATA_ACCESS_ROLE)); + + // at random test the old deprecated roles, to be removed in 9.0.0 + if (randomBoolean()) { + setupUser(TEST_USER_NAME, Arrays.asList("transform_admin", DATA_ACCESS_ROLE)); + } else { + setupUser(TEST_USER_NAME, Arrays.asList("data_frame_transforms_admin", DATA_ACCESS_ROLE)); + } } public void testSimplePivot() throws Exception { diff --git a/x-pack/qa/rolling-upgrade/src/test/java/org/elasticsearch/upgrades/TransformSurvivesUpgradeIT.java b/x-pack/qa/rolling-upgrade/src/test/java/org/elasticsearch/upgrades/TransformSurvivesUpgradeIT.java index 44d340cb2cc..86775467860 100644 --- a/x-pack/qa/rolling-upgrade/src/test/java/org/elasticsearch/upgrades/TransformSurvivesUpgradeIT.java +++ b/x-pack/qa/rolling-upgrade/src/test/java/org/elasticsearch/upgrades/TransformSurvivesUpgradeIT.java @@ -25,6 +25,7 @@ import org.elasticsearch.client.transform.transforms.pivot.PivotConfig; import org.elasticsearch.client.transform.transforms.pivot.TermsGroupSource; import org.elasticsearch.common.Booleans; import org.elasticsearch.common.Strings; +import org.elasticsearch.common.io.Streams; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.xcontent.DeprecationHandler; @@ -35,21 +36,25 @@ import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.common.xcontent.support.XContentMapValues; import org.elasticsearch.search.aggregations.AggregationBuilders; import org.elasticsearch.search.aggregations.AggregatorFactories; -import org.elasticsearch.xpack.test.rest.XPackRestTestConstants; +import org.junit.Before; import java.io.IOException; import java.time.Instant; import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.SortedSet; +import java.util.TreeSet; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; import java.util.stream.Collectors; import java.util.stream.Stream; import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; +import static org.elasticsearch.xpack.test.rest.XPackRestTestConstants.TRANSFORM_INTERNAL_INDEX_PREFIX; +import static org.elasticsearch.xpack.test.rest.XPackRestTestConstants.TRANSFORM_INTERNAL_INDEX_PREFIX_DEPRECATED; +import static org.elasticsearch.xpack.test.rest.XPackRestTestConstants.TRANSFORM_NOTIFICATIONS_INDEX_PREFIX; +import static org.elasticsearch.xpack.test.rest.XPackRestTestConstants.TRANSFORM_NOTIFICATIONS_INDEX_PREFIX_DEPRECATED; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.greaterThan; import static org.hamcrest.Matchers.greaterThanOrEqualTo; @@ -72,14 +77,38 @@ public class TransformSurvivesUpgradeIT extends AbstractUpgradeTestCase { .map(TimeValue::timeValueMinutes) .collect(Collectors.toList()); - @Override - protected Collection templatesToWaitFor() { - if (UPGRADE_FROM_VERSION.onOrAfter(Version.V_7_4_0)) { - return Stream.concat(XPackRestTestConstants.DATA_FRAME_TEMPLATES.stream(), - super.templatesToWaitFor().stream()).collect(Collectors.toSet()); - } else { - return Collections.emptySet(); + @Before + public void waitForTemplates() throws Exception { + // no transform before 7.2 + if (UPGRADE_FROM_VERSION.before(Version.V_7_2_0)) { + return; } + + assertBusy(() -> { + final Request catRequest = new Request("GET", "_cat/templates?h=n&s=n"); + final Response catResponse = adminClient().performRequest(catRequest); + + final SortedSet templates = new TreeSet<>(Streams.readAllLines(catResponse.getEntity().getContent())); + + // match templates, independent of the version, at least 2 should exist + SortedSet internalDeprecated = templates.tailSet(TRANSFORM_INTERNAL_INDEX_PREFIX_DEPRECATED); + SortedSet internal = templates.tailSet(TRANSFORM_INTERNAL_INDEX_PREFIX); + SortedSet notificationsDeprecated = templates + .tailSet(TRANSFORM_NOTIFICATIONS_INDEX_PREFIX_DEPRECATED); + SortedSet notifications = templates.tailSet(TRANSFORM_NOTIFICATIONS_INDEX_PREFIX); + + int foundTemplates = 0; + foundTemplates += internalDeprecated.isEmpty() ? 0 + : internalDeprecated.first().startsWith(TRANSFORM_INTERNAL_INDEX_PREFIX_DEPRECATED) ? 1 : 0; + foundTemplates += internal.isEmpty() ? 0 : internal.first().startsWith(TRANSFORM_INTERNAL_INDEX_PREFIX) ? 1 : 0; + foundTemplates += notificationsDeprecated.isEmpty() ? 0 + : notificationsDeprecated.first().startsWith(TRANSFORM_NOTIFICATIONS_INDEX_PREFIX_DEPRECATED) ? 1 : 0; + foundTemplates += notifications.isEmpty() ? 0 : notifications.first().startsWith(TRANSFORM_NOTIFICATIONS_INDEX_PREFIX) ? 1 : 0; + + if (foundTemplates < 2) { + fail("Transform index templates not found. The templates that exist are: " + templates); + } + }); } protected static void waitForPendingDataFrameTasks() throws Exception { diff --git a/x-pack/qa/src/main/java/org/elasticsearch/xpack/test/rest/XPackRestTestConstants.java b/x-pack/qa/src/main/java/org/elasticsearch/xpack/test/rest/XPackRestTestConstants.java index d09d09bbc40..acfeed8b91e 100644 --- a/x-pack/qa/src/main/java/org/elasticsearch/xpack/test/rest/XPackRestTestConstants.java +++ b/x-pack/qa/src/main/java/org/elasticsearch/xpack/test/rest/XPackRestTestConstants.java @@ -38,12 +38,11 @@ public final class XPackRestTestConstants { RESULTS_INDEX_PREFIX, CONFIG_INDEX)); - // Data Frame constants: - public static final String DATA_FRAME_INTERNAL_INDEX = ".data-frame-internal-2"; - public static final String DATA_FRAME_NOTIFICATIONS_INDEX = ".data-frame-notifications-1"; - - public static final List DATA_FRAME_TEMPLATES = - Collections.unmodifiableList(Arrays.asList(DATA_FRAME_INTERNAL_INDEX, DATA_FRAME_NOTIFICATIONS_INDEX)); + // Transform constants: + public static final String TRANSFORM_INTERNAL_INDEX_PREFIX = ".transform-internal-"; + public static final String TRANSFORM_NOTIFICATIONS_INDEX_PREFIX = ".transform-notifications-"; + public static final String TRANSFORM_INTERNAL_INDEX_PREFIX_DEPRECATED = ".data-frame-internal-"; + public static final String TRANSFORM_NOTIFICATIONS_INDEX_PREFIX_DEPRECATED = ".data-frame-notifications-"; private XPackRestTestConstants() { }