diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authz/permission/IngestAdminRole.java b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authz/permission/IngestAdminRole.java new file mode 100644 index 00000000000..12581d36e98 --- /dev/null +++ b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authz/permission/IngestAdminRole.java @@ -0,0 +1,30 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.xpack.security.authz.permission; + +import org.elasticsearch.xpack.security.authz.RoleDescriptor; +import org.elasticsearch.xpack.security.authz.privilege.ClusterPrivilege; +import org.elasticsearch.xpack.security.authz.privilege.Privilege.Name; + +/** + * Role for users that should be allowed to use the Add Data/Ingest features in the UI + */ +public class IngestAdminRole extends Role { + + private static final String[] CLUSTER_PRIVILEGES = new String[] { "manage_index_templates", "manage_pipeline" }; + private static final RoleDescriptor.IndicesPrivileges[] INDICES_PRIVILEGES = new RoleDescriptor.IndicesPrivileges[0]; + + public static final String NAME = "ingest_admin"; + public static final RoleDescriptor DESCRIPTOR = new RoleDescriptor(NAME, CLUSTER_PRIVILEGES, INDICES_PRIVILEGES, null); + public static final IngestAdminRole INSTANCE = new IngestAdminRole(); + + private IngestAdminRole() { + super(DESCRIPTOR.getName(), + new ClusterPermission.Core(ClusterPrivilege.get(new Name(DESCRIPTOR.getClusterPrivileges()))), + new IndicesPermission.Core(Role.Builder.convertFromIndicesPrivileges(DESCRIPTOR.getIndicesPrivileges())), + RunAsPermission.Core.NONE); + } +} diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authz/privilege/ClusterPrivilege.java b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authz/privilege/ClusterPrivilege.java index 98959c9bc9e..d733b0cd8a0 100644 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authz/privilege/ClusterPrivilege.java +++ b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authz/privilege/ClusterPrivilege.java @@ -42,6 +42,7 @@ public class ClusterPrivilege extends AbstractAutomatonPrivilege ACTION_MATCHER = ClusterPrivilege.ALL.predicate(); @@ -56,6 +57,7 @@ public class ClusterPrivilege extends AbstractAutomatonPrivilege values() { diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authz/store/ReservedRolesStore.java b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authz/store/ReservedRolesStore.java index 3a2bcd5ee5b..d6ed72968a7 100644 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authz/store/ReservedRolesStore.java +++ b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authz/store/ReservedRolesStore.java @@ -14,6 +14,7 @@ import java.util.Set; import org.elasticsearch.common.util.set.Sets; import org.elasticsearch.xpack.security.SecurityContext; import org.elasticsearch.xpack.security.authz.RoleDescriptor; +import org.elasticsearch.xpack.security.authz.permission.IngestAdminRole; import org.elasticsearch.xpack.security.authz.permission.KibanaRole; import org.elasticsearch.xpack.security.authz.permission.KibanaUserRole; import org.elasticsearch.xpack.security.authz.permission.MonitoringUserRole; @@ -48,6 +49,8 @@ public class ReservedRolesStore implements RolesStore { return MonitoringUserRole.INSTANCE; case RemoteMonitoringAgentRole.NAME: return RemoteMonitoringAgentRole.INSTANCE; + case IngestAdminRole.NAME: + return IngestAdminRole.INSTANCE; case KibanaRole.NAME: // The only user that should know about this role is the kibana user itself (who has this role). The reason we want to hide // this role is that it was created specifically for kibana, with all the permissions that the kibana user needs. @@ -78,6 +81,8 @@ public class ReservedRolesStore implements RolesStore { return MonitoringUserRole.DESCRIPTOR; case RemoteMonitoringAgentRole.NAME: return RemoteMonitoringAgentRole.DESCRIPTOR; + case IngestAdminRole.NAME: + return IngestAdminRole.DESCRIPTOR; case KibanaRole.NAME: // The only user that should know about this role is the kibana user itself (who has this role). The reason we want to hide // this role is that it was created specifically for kibana, with all the permissions that the kibana user needs. @@ -94,15 +99,16 @@ public class ReservedRolesStore implements RolesStore { public Collection roleDescriptors() { if (KibanaUser.is(securityContext.getUser())) { return Arrays.asList(SuperuserRole.DESCRIPTOR, TransportClientRole.DESCRIPTOR, KibanaUserRole.DESCRIPTOR, - KibanaRole.DESCRIPTOR, MonitoringUserRole.DESCRIPTOR, RemoteMonitoringAgentRole.DESCRIPTOR); + KibanaRole.DESCRIPTOR, MonitoringUserRole.DESCRIPTOR, RemoteMonitoringAgentRole.DESCRIPTOR, + IngestAdminRole.DESCRIPTOR); } return Arrays.asList(SuperuserRole.DESCRIPTOR, TransportClientRole.DESCRIPTOR, KibanaUserRole.DESCRIPTOR, - MonitoringUserRole.DESCRIPTOR, RemoteMonitoringAgentRole.DESCRIPTOR); + MonitoringUserRole.DESCRIPTOR, RemoteMonitoringAgentRole.DESCRIPTOR, IngestAdminRole.DESCRIPTOR); } public static Set names() { return Sets.newHashSet(SuperuserRole.NAME, KibanaRole.NAME, TransportClientRole.NAME, KibanaUserRole.NAME, - MonitoringUserRole.NAME, RemoteMonitoringAgentRole.NAME); + MonitoringUserRole.NAME, RemoteMonitoringAgentRole.NAME, IngestAdminRole.NAME); } public static boolean isReserved(String role) { @@ -114,6 +120,7 @@ public class ReservedRolesStore implements RolesStore { case MonitoringUserRole.NAME: case RemoteMonitoringAgentRole.NAME: case SystemUser.ROLE_NAME: + case IngestAdminRole.NAME: return true; default: return false; diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authz/permission/IngestAdminRoleTests.java b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authz/permission/IngestAdminRoleTests.java new file mode 100644 index 00000000000..266c44f36ba --- /dev/null +++ b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authz/permission/IngestAdminRoleTests.java @@ -0,0 +1,51 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.xpack.security.authz.permission; + +import org.elasticsearch.action.admin.cluster.reroute.ClusterRerouteAction; +import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsAction; +import org.elasticsearch.action.admin.indices.template.delete.DeleteIndexTemplateAction; +import org.elasticsearch.action.admin.indices.template.get.GetIndexTemplatesAction; +import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateAction; +import org.elasticsearch.action.get.GetAction; +import org.elasticsearch.action.index.IndexAction; +import org.elasticsearch.action.ingest.DeletePipelineAction; +import org.elasticsearch.action.ingest.GetPipelineAction; +import org.elasticsearch.action.ingest.PutPipelineAction; +import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.transport.TransportRequest; +import org.elasticsearch.xpack.monitoring.action.MonitoringBulkAction; +import org.elasticsearch.xpack.security.authc.Authentication; + +import static org.hamcrest.Matchers.is; +import static org.mockito.Mockito.mock; + +public class IngestAdminRoleTests extends ESTestCase { + + public void testClusterPermissions() { + final TransportRequest request = new TransportRequest.Empty(); + final Authentication authentication = mock(Authentication.class); + assertThat(IngestAdminRole.INSTANCE.cluster().check(PutIndexTemplateAction.NAME, request, authentication), is(true)); + assertThat(IngestAdminRole.INSTANCE.cluster().check(GetIndexTemplatesAction.NAME, request, authentication), is(true)); + assertThat(IngestAdminRole.INSTANCE.cluster().check(DeleteIndexTemplateAction.NAME, request, authentication), is(true)); + assertThat(IngestAdminRole.INSTANCE.cluster().check(PutPipelineAction.NAME, request, authentication), is(true)); + assertThat(IngestAdminRole.INSTANCE.cluster().check(GetPipelineAction.NAME, request, authentication), is(true)); + assertThat(IngestAdminRole.INSTANCE.cluster().check(DeletePipelineAction.NAME, request, authentication), is(true)); + + + assertThat(IngestAdminRole.INSTANCE.cluster().check(ClusterRerouteAction.NAME, request, authentication), is(false)); + assertThat(IngestAdminRole.INSTANCE.cluster().check(ClusterUpdateSettingsAction.NAME, request, authentication), is(false)); + assertThat(IngestAdminRole.INSTANCE.cluster().check(MonitoringBulkAction.NAME, request, authentication), is(false)); + } + + public void testNoIndicesPermissions() { + assertThat(IngestAdminRole.INSTANCE.indices().allowedIndicesMatcher(IndexAction.NAME).test("foo"), is(false)); + assertThat(IngestAdminRole.INSTANCE.indices().allowedIndicesMatcher("indices:foo").test(randomAsciiOfLengthBetween(8, 24)), + is(false)); + assertThat(IngestAdminRole.INSTANCE.indices().allowedIndicesMatcher(GetAction.NAME).test(randomAsciiOfLengthBetween(8, 24)), + is(false)); + } +} diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authz/store/ReservedRolesStoreTests.java b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authz/store/ReservedRolesStoreTests.java index 991b500eaa2..bffce016af9 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authz/store/ReservedRolesStoreTests.java +++ b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authz/store/ReservedRolesStoreTests.java @@ -6,6 +6,7 @@ package org.elasticsearch.xpack.security.authz.store; import org.elasticsearch.xpack.security.SecurityContext; +import org.elasticsearch.xpack.security.authz.permission.IngestAdminRole; import org.elasticsearch.xpack.security.authz.permission.KibanaRole; import org.elasticsearch.xpack.security.authz.permission.KibanaUserRole; import org.elasticsearch.xpack.security.authz.permission.MonitoringUserRole; @@ -56,6 +57,9 @@ public class ReservedRolesStoreTests extends ESTestCase { assertThat(reservedRolesStore.role(KibanaUserRole.NAME), sameInstance(KibanaUserRole.INSTANCE)); assertThat(reservedRolesStore.roleDescriptor(KibanaUserRole.NAME), sameInstance(KibanaUserRole.DESCRIPTOR)); + assertThat(reservedRolesStore.role(IngestAdminRole.NAME), sameInstance(IngestAdminRole.INSTANCE)); + assertThat(reservedRolesStore.roleDescriptor(IngestAdminRole.NAME), sameInstance(IngestAdminRole.DESCRIPTOR)); + assertThat(reservedRolesStore.role(MonitoringUserRole.NAME), sameInstance(MonitoringUserRole.INSTANCE)); assertThat(reservedRolesStore.roleDescriptor(MonitoringUserRole.NAME), sameInstance(MonitoringUserRole.DESCRIPTOR)); @@ -63,7 +67,8 @@ public class ReservedRolesStoreTests extends ESTestCase { assertThat(reservedRolesStore.roleDescriptor(RemoteMonitoringAgentRole.NAME), sameInstance(RemoteMonitoringAgentRole.DESCRIPTOR)); assertThat(reservedRolesStore.roleDescriptors(), contains(SuperuserRole.DESCRIPTOR, TransportClientRole.DESCRIPTOR, - KibanaUserRole.DESCRIPTOR, MonitoringUserRole.DESCRIPTOR, RemoteMonitoringAgentRole.DESCRIPTOR)); + KibanaUserRole.DESCRIPTOR, MonitoringUserRole.DESCRIPTOR, RemoteMonitoringAgentRole.DESCRIPTOR, + IngestAdminRole.DESCRIPTOR)); assertThat(reservedRolesStore.role(KibanaRole.NAME), nullValue()); assertThat(reservedRolesStore.roleDescriptor(KibanaRole.NAME), nullValue()); @@ -82,6 +87,9 @@ public class ReservedRolesStoreTests extends ESTestCase { assertThat(reservedRolesStore.role(KibanaUserRole.NAME), sameInstance(KibanaUserRole.INSTANCE)); assertThat(reservedRolesStore.roleDescriptor(KibanaUserRole.NAME), sameInstance(KibanaUserRole.DESCRIPTOR)); + assertThat(reservedRolesStore.role(IngestAdminRole.NAME), sameInstance(IngestAdminRole.INSTANCE)); + assertThat(reservedRolesStore.roleDescriptor(IngestAdminRole.NAME), sameInstance(IngestAdminRole.DESCRIPTOR)); + assertThat(reservedRolesStore.role(KibanaRole.NAME), sameInstance(KibanaRole.INSTANCE)); assertThat(reservedRolesStore.roleDescriptor(KibanaRole.NAME), sameInstance(KibanaRole.DESCRIPTOR)); @@ -92,7 +100,8 @@ public class ReservedRolesStoreTests extends ESTestCase { assertThat(reservedRolesStore.roleDescriptor(RemoteMonitoringAgentRole.NAME), sameInstance(RemoteMonitoringAgentRole.DESCRIPTOR)); assertThat(reservedRolesStore.roleDescriptors(), contains(SuperuserRole.DESCRIPTOR, TransportClientRole.DESCRIPTOR, - KibanaUserRole.DESCRIPTOR, KibanaRole.DESCRIPTOR, MonitoringUserRole.DESCRIPTOR, RemoteMonitoringAgentRole.DESCRIPTOR)); + KibanaUserRole.DESCRIPTOR, KibanaRole.DESCRIPTOR, MonitoringUserRole.DESCRIPTOR, RemoteMonitoringAgentRole.DESCRIPTOR, + IngestAdminRole.DESCRIPTOR)); assertThat(reservedRolesStore.role(SystemUser.ROLE_NAME), nullValue()); } @@ -104,6 +113,7 @@ public class ReservedRolesStoreTests extends ESTestCase { assertThat(ReservedRolesStore.isReserved(SystemUser.ROLE_NAME), is(true)); assertThat(ReservedRolesStore.isReserved(TransportClientRole.NAME), is(true)); assertThat(ReservedRolesStore.isReserved(KibanaUserRole.NAME), is(true)); + assertThat(ReservedRolesStore.isReserved(IngestAdminRole.NAME), is(true)); assertThat(ReservedRolesStore.isReserved(RemoteMonitoringAgentRole.NAME), is(true)); assertThat(ReservedRolesStore.isReserved(MonitoringUserRole.NAME), is(true)); }