security: add a reserved role for the ingest feature in Kibana

Closes elastic/elasticsearch#1667

Original commit: elastic/x-pack-elasticsearch@da2f6d9c4e
This commit is contained in:
jaymode 2016-06-24 08:53:41 -04:00
parent 3638c8639f
commit 836e1d3a28
5 changed files with 105 additions and 5 deletions

View File

@ -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);
}
}

View File

@ -42,6 +42,7 @@ public class ClusterPrivilege extends AbstractAutomatonPrivilege<ClusterPrivileg
new ClusterPrivilege("manage_ingest_pipelines", MANAGE_INGEST_PIPELINE_AUTOMATON);
public static final ClusterPrivilege TRANSPORT_CLIENT = new ClusterPrivilege("transport_client", TRANSPORT_CLIENT_AUTOMATON);
public static final ClusterPrivilege MANAGE_SECURITY = new ClusterPrivilege("manage_security", MANAGE_SECURITY_AUTOMATON);
public static final ClusterPrivilege MANAGE_PIPELINE = new ClusterPrivilege("manage_pipeline", "cluster:admin/ingest/pipeline/*");
public static final Predicate<String> ACTION_MATCHER = ClusterPrivilege.ALL.predicate();
@ -56,6 +57,7 @@ public class ClusterPrivilege extends AbstractAutomatonPrivilege<ClusterPrivileg
values.add(MANAGE_INGEST_PIPELINES);
values.add(TRANSPORT_CLIENT);
values.add(MANAGE_SECURITY);
values.add(MANAGE_PIPELINE);
}
static Set<ClusterPrivilege> values() {

View File

@ -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<RoleDescriptor> 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<String> 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;

View File

@ -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));
}
}

View File

@ -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));
}