Use SPI to glean reserved roles (elastic/x-pack-elasticsearch#3012)

This commit uses SPI to get the list of system wide reserved roles in
security. It does not yet split out the RoleDescriptor to a common
location so the implementing services still depend on security. Each
role, however, only depends on its own feature as well as security.

ref elastic/x-pack-elasticsearch#2925

Original commit: elastic/x-pack-elasticsearch@efebc3e5c8
This commit is contained in:
Michael Basnight 2017-11-29 09:00:23 -06:00 committed by GitHub
parent c641a30bc5
commit bf27cd1457
9 changed files with 330 additions and 84 deletions

View File

@ -0,0 +1,34 @@
/*
* 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.logstash;
import org.elasticsearch.xpack.security.authz.RoleDescriptor;
import org.elasticsearch.xpack.security.SecurityExtension;
import org.elasticsearch.xpack.security.support.MetadataUtils;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class LogstashSecurityExtension implements SecurityExtension {
@Override
public Map<String, RoleDescriptor> getReservedRoles() {
Map<String, RoleDescriptor> roles = new HashMap<>();
roles.put("logstash_admin",
new RoleDescriptor("logstash_admin",
null,
new RoleDescriptor.IndicesPrivileges[]{
RoleDescriptor.IndicesPrivileges.builder().indices(".logstash*")
.privileges("create", "delete", "index", "manage", "read")
.build()
},
null,
MetadataUtils.DEFAULT_RESERVED_METADATA));
return Collections.unmodifiableMap(roles);
}
}

View File

@ -0,0 +1,47 @@
/*
* 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.ml;
import org.elasticsearch.xpack.security.authz.RoleDescriptor;
import org.elasticsearch.xpack.security.SecurityExtension;
import org.elasticsearch.xpack.security.support.MetadataUtils;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class MachineLearningSecurityExtension implements SecurityExtension {
@Override
public Map<String, RoleDescriptor> getReservedRoles() {
Map<String, RoleDescriptor> roles = new HashMap<>();
roles.put("machine_learning_user",
new RoleDescriptor("machine_learning_user",
new String[] { "monitor_ml" },
new RoleDescriptor.IndicesPrivileges[] {
RoleDescriptor.IndicesPrivileges.builder()
.indices(".ml-anomalies*", ".ml-notifications")
.privileges("view_index_metadata", "read")
.build()
},
null,
MetadataUtils.DEFAULT_RESERVED_METADATA));
roles.put("machine_learning_admin",
new RoleDescriptor("machine_learning_admin",
new String[] { "manage_ml" },
new RoleDescriptor.IndicesPrivileges[] {
RoleDescriptor.IndicesPrivileges.builder()
.indices(".ml-*")
.privileges("view_index_metadata", "read")
.build()
},
null,
MetadataUtils.DEFAULT_RESERVED_METADATA));
return Collections.unmodifiableMap(roles);
}
}

View File

@ -0,0 +1,79 @@
/*
* 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.monitoring;
import org.elasticsearch.xpack.monitoring.action.MonitoringBulkAction;
import org.elasticsearch.xpack.security.authz.RoleDescriptor;
import org.elasticsearch.xpack.security.SecurityExtension;
import org.elasticsearch.xpack.security.support.MetadataUtils;
import org.elasticsearch.xpack.security.user.KibanaUser;
import org.elasticsearch.xpack.security.user.LogstashSystemUser;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class MonitoringSecurityExtension implements SecurityExtension {
@Override
public Map<String, RoleDescriptor> getReservedRoles() {
Map<String, RoleDescriptor> roles = new HashMap<>();
roles.put("monitoring_user",
new RoleDescriptor("monitoring_user",
null,
new RoleDescriptor.IndicesPrivileges[] {
RoleDescriptor.IndicesPrivileges.builder()
.indices(".monitoring-*")
.privileges("read", "read_cross_cluster")
.build()
},
null,
MetadataUtils.DEFAULT_RESERVED_METADATA));
roles.put("remote_monitoring_agent",
new RoleDescriptor("remote_monitoring_agent",
new String[] {
"manage_index_templates", "manage_ingest_pipelines", "monitor",
"cluster:monitor/xpack/watcher/watch/get",
"cluster:admin/xpack/watcher/watch/put",
"cluster:admin/xpack/watcher/watch/delete",
},
new RoleDescriptor.IndicesPrivileges[] {
RoleDescriptor.IndicesPrivileges.builder()
.indices(".monitoring-*")
.privileges("all")
.build()
},
null,
MetadataUtils.DEFAULT_RESERVED_METADATA));
// TODO(core-infra) put KibanaUser & LogstashSystemUser into a common place for the split and use them here
roles.put("logstash_system",
new RoleDescriptor(LogstashSystemUser.ROLE_NAME,
new String[]{"monitor", MonitoringBulkAction.NAME},
null,
null,
MetadataUtils.DEFAULT_RESERVED_METADATA));
roles.put("kibana_system",
new RoleDescriptor(KibanaUser.ROLE_NAME,
new String[] { "monitor", "manage_index_templates", MonitoringBulkAction.NAME },
new RoleDescriptor.IndicesPrivileges[] {
RoleDescriptor.IndicesPrivileges.builder()
.indices(".kibana*", ".reporting-*")
.privileges("all")
.build(),
RoleDescriptor.IndicesPrivileges.builder()
.indices(".monitoring-*")
.privileges("read", "read_cross_cluster")
.build()
},
null,
MetadataUtils.DEFAULT_RESERVED_METADATA));
return Collections.unmodifiableMap(roles);
}
}

View File

@ -0,0 +1,26 @@
/*
* 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;
import org.elasticsearch.xpack.security.authz.RoleDescriptor;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
* SPI interface to any plugins that want to provide custom extensions to aid the security module in functioning without
* needing to explicitly know about the behavior of the implementing plugin.
*/
public interface SecurityExtension {
/**
* Gets a set of reserved roles, consisting of the role name and the descriptor.
*/
default Map<String, RoleDescriptor> getReservedRoles() {
return Collections.emptyMap();
}
}

View File

@ -0,0 +1,68 @@
/*
* 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;
import org.elasticsearch.xpack.security.authz.RoleDescriptor;
import org.elasticsearch.xpack.security.support.MetadataUtils;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class StackSecurityExtension implements SecurityExtension {
@Override
public Map<String, RoleDescriptor> getReservedRoles() {
Map<String, RoleDescriptor> roles = new HashMap<>();
roles.put("transport_client",
new RoleDescriptor("transport_client",
new String[] { "transport_client" },
null,
null,
MetadataUtils.DEFAULT_RESERVED_METADATA));
roles.put("kibana_user",
new RoleDescriptor("kibana_user",
null,
new RoleDescriptor.IndicesPrivileges[] {
RoleDescriptor.IndicesPrivileges.builder()
.indices(".kibana*")
.privileges("manage", "read", "index", "delete")
.build()
},
null,
MetadataUtils.DEFAULT_RESERVED_METADATA));
roles.put("ingest_admin",
new RoleDescriptor("ingest_admin",
new String[] { "manage_index_templates", "manage_pipeline" },
null,
null,
MetadataUtils.DEFAULT_RESERVED_METADATA));
// reporting_user doesn't have any privileges in Elasticsearch, and Kibana authorizes privileges based on this role
roles.put("reporting_user",
new RoleDescriptor("reporting_user",
null,
null,
null,
MetadataUtils.DEFAULT_RESERVED_METADATA));
roles.put("kibana_dashboard_only_user",
new RoleDescriptor("kibana_dashboard_only_user",
null,
new RoleDescriptor.IndicesPrivileges[] {
RoleDescriptor.IndicesPrivileges.builder()
.indices(".kibana*")
.privileges("read", "view_index_metadata")
.build()
},
null,
MetadataUtils.DEFAULT_RESERVED_METADATA));
return Collections.unmodifiableMap(roles);
}
}

View File

@ -5,26 +5,24 @@
*/
package org.elasticsearch.xpack.security.authz.store;
import org.elasticsearch.common.collect.MapBuilder;
import org.elasticsearch.xpack.monitoring.action.MonitoringBulkAction;
import org.elasticsearch.xpack.security.authz.RoleDescriptor;
import org.elasticsearch.xpack.security.authz.permission.Role;
import org.elasticsearch.xpack.security.SecurityExtension;
import org.elasticsearch.xpack.security.support.MetadataUtils;
import org.elasticsearch.xpack.security.user.KibanaUser;
import org.elasticsearch.xpack.security.user.SystemUser;
import org.elasticsearch.xpack.security.user.XPackUser;
import org.elasticsearch.xpack.watcher.execution.TriggeredWatchStore;
import org.elasticsearch.xpack.watcher.history.HistoryStore;
import org.elasticsearch.xpack.watcher.watch.Watch;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.ServiceLoader;
import java.util.Set;
public class ReservedRolesStore {
public static final RoleDescriptor SUPERUSER_ROLE_DESCRIPTOR = new RoleDescriptor("superuser", new String[] { "all" },
public static final RoleDescriptor SUPERUSER_ROLE_DESCRIPTOR = new RoleDescriptor("superuser",
new String[] { "all" },
new RoleDescriptor.IndicesPrivileges[] {
RoleDescriptor.IndicesPrivileges.builder().indices("*").privileges("all").build()},
new String[] { "*" },
@ -33,82 +31,16 @@ public class ReservedRolesStore {
private static final Map<String, RoleDescriptor> RESERVED_ROLES = initializeReservedRoles();
private static Map<String, RoleDescriptor> initializeReservedRoles() {
return MapBuilder.<String, RoleDescriptor>newMapBuilder()
.put("superuser", new RoleDescriptor("superuser", new String[] { "all" },
new RoleDescriptor.IndicesPrivileges[] {
RoleDescriptor.IndicesPrivileges.builder().indices("*").privileges("all").build()},
new String[] { "*" },
MetadataUtils.DEFAULT_RESERVED_METADATA))
.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, new RoleDescriptor.IndicesPrivileges[] {
RoleDescriptor.IndicesPrivileges.builder().indices(".kibana*").privileges("manage", "read", "index", "delete")
.build() }, null, MetadataUtils.DEFAULT_RESERVED_METADATA))
.put("monitoring_user", new RoleDescriptor("monitoring_user", null, new RoleDescriptor.IndicesPrivileges[] {
RoleDescriptor.IndicesPrivileges.builder()
.indices(".monitoring-*").privileges("read", "read_cross_cluster").build()
},
null, MetadataUtils.DEFAULT_RESERVED_METADATA))
.put("remote_monitoring_agent", new RoleDescriptor("remote_monitoring_agent",
new String[] {
"manage_index_templates", "manage_ingest_pipelines", "monitor",
"cluster:monitor/xpack/watcher/watch/get",
"cluster:admin/xpack/watcher/watch/put",
"cluster:admin/xpack/watcher/watch/delete",
},
new RoleDescriptor.IndicesPrivileges[] {
RoleDescriptor.IndicesPrivileges.builder().indices(".monitoring-*").privileges("all").build() },
null, MetadataUtils.DEFAULT_RESERVED_METADATA))
.put("ingest_admin", new RoleDescriptor("ingest_admin", new String[] { "manage_index_templates", "manage_pipeline" },
null, null, MetadataUtils.DEFAULT_RESERVED_METADATA))
// reporting_user doesn't have any privileges in Elasticsearch, and Kibana authorizes privileges based on this role
.put("reporting_user", new RoleDescriptor("reporting_user", null, null,
null, MetadataUtils.DEFAULT_RESERVED_METADATA))
.put("kibana_dashboard_only_user", new RoleDescriptor(
"kibana_dashboard_only_user",
null,
new RoleDescriptor.IndicesPrivileges[] {
RoleDescriptor.IndicesPrivileges.builder()
.indices(".kibana*").privileges("read", "view_index_metadata").build()
},
null,
MetadataUtils.DEFAULT_RESERVED_METADATA))
.put(KibanaUser.ROLE_NAME, new RoleDescriptor(KibanaUser.ROLE_NAME,
new String[] { "monitor", "manage_index_templates", MonitoringBulkAction.NAME },
new RoleDescriptor.IndicesPrivileges[] {
RoleDescriptor.IndicesPrivileges.builder().indices(".kibana*", ".reporting-*").privileges("all").build(),
RoleDescriptor.IndicesPrivileges.builder()
.indices(".monitoring-*").privileges("read", "read_cross_cluster").build()
},
null, MetadataUtils.DEFAULT_RESERVED_METADATA))
.put("logstash_system", new RoleDescriptor("logstash_system", new String[] { "monitor", MonitoringBulkAction.NAME},
null, null, MetadataUtils.DEFAULT_RESERVED_METADATA))
.put("machine_learning_user", new RoleDescriptor("machine_learning_user", new String[] { "monitor_ml" },
new RoleDescriptor.IndicesPrivileges[] { RoleDescriptor.IndicesPrivileges.builder().indices(".ml-anomalies*",
".ml-notifications").privileges("view_index_metadata", "read").build() },
null, MetadataUtils.DEFAULT_RESERVED_METADATA))
.put("machine_learning_admin", new RoleDescriptor("machine_learning_admin", new String[] { "manage_ml" },
new RoleDescriptor.IndicesPrivileges[] {
RoleDescriptor.IndicesPrivileges.builder().indices(".ml-*").privileges("view_index_metadata", "read")
.build() }, null, MetadataUtils.DEFAULT_RESERVED_METADATA))
.put("watcher_admin", new RoleDescriptor("watcher_admin", new String[] { "manage_watcher" },
new RoleDescriptor.IndicesPrivileges[] {
RoleDescriptor.IndicesPrivileges.builder().indices(Watch.INDEX, TriggeredWatchStore.INDEX_NAME,
HistoryStore.INDEX_PREFIX + "*").privileges("read").build() },
null, MetadataUtils.DEFAULT_RESERVED_METADATA))
.put("watcher_user", new RoleDescriptor("watcher_user", new String[] { "monitor_watcher" },
new RoleDescriptor.IndicesPrivileges[] {
RoleDescriptor.IndicesPrivileges.builder().indices(Watch.INDEX)
.privileges("read")
.build(),
RoleDescriptor.IndicesPrivileges.builder().indices(HistoryStore.INDEX_PREFIX + "*")
.privileges("read")
.build() }, null, MetadataUtils.DEFAULT_RESERVED_METADATA))
.put("logstash_admin", new RoleDescriptor("logstash_admin", null, new RoleDescriptor.IndicesPrivileges[] {
RoleDescriptor.IndicesPrivileges.builder().indices(".logstash*")
.privileges("create", "delete", "index", "manage", "read").build() },
null, MetadataUtils.DEFAULT_RESERVED_METADATA))
.immutableMap();
Map<String, RoleDescriptor> roles = new HashMap<>();
roles.put("superuser", SUPERUSER_ROLE_DESCRIPTOR);
// Services are loaded through SPI, and are defined in their META-INF/services
for(SecurityExtension ext : ServiceLoader.load(SecurityExtension.class, SecurityExtension.class.getClassLoader())) {
roles.putAll(ext.getReservedRoles());
}
return Collections.unmodifiableMap(roles);
}
public Map<String, Object> usageStats() {

View File

@ -14,7 +14,7 @@ import org.elasticsearch.xpack.security.support.MetadataUtils;
public class LogstashSystemUser extends User {
public static final String NAME = "logstash_system";
private static final String ROLE_NAME = "logstash_system";
public static final String ROLE_NAME = "logstash_system";
public static final Version DEFINED_SINCE = Version.V_5_2_0;
public static final BuiltinUserInfo USER_INFO = new BuiltinUserInfo(NAME, ROLE_NAME, DEFINED_SINCE);

View File

@ -0,0 +1,55 @@
/*
* 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.watcher;
import org.elasticsearch.xpack.security.authz.RoleDescriptor;
import org.elasticsearch.xpack.security.SecurityExtension;
import org.elasticsearch.xpack.security.support.MetadataUtils;
import org.elasticsearch.xpack.watcher.execution.TriggeredWatchStore;
import org.elasticsearch.xpack.watcher.history.HistoryStore;
import org.elasticsearch.xpack.watcher.watch.Watch;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class WatcherSecurityExtension implements SecurityExtension {
@Override
public Map<String, RoleDescriptor> getReservedRoles() {
Map<String, RoleDescriptor> roles = new HashMap<>();
roles.put("watcher_admin",
new RoleDescriptor("watcher_admin",
new String[] { "manage_watcher" },
new RoleDescriptor.IndicesPrivileges[] {
RoleDescriptor.IndicesPrivileges.builder()
.indices(Watch.INDEX,
TriggeredWatchStore.INDEX_NAME,
HistoryStore.INDEX_PREFIX + "*")
.privileges("read").build()
},
null,
MetadataUtils.DEFAULT_RESERVED_METADATA));
roles.put("watcher_user",
new RoleDescriptor("watcher_user",
new String[] { "monitor_watcher" },
new RoleDescriptor.IndicesPrivileges[] {
RoleDescriptor.IndicesPrivileges.builder()
.indices(Watch.INDEX)
.privileges("read")
.build(),
RoleDescriptor.IndicesPrivileges.builder()
.indices(HistoryStore.INDEX_PREFIX + "*")
.privileges("read")
.build()
},
null,
MetadataUtils.DEFAULT_RESERVED_METADATA));
return Collections.unmodifiableMap(roles);
}
}

View File

@ -0,0 +1,5 @@
org.elasticsearch.xpack.logstash.LogstashSecurityExtension
org.elasticsearch.xpack.ml.MachineLearningSecurityExtension
org.elasticsearch.xpack.monitoring.MonitoringSecurityExtension
org.elasticsearch.xpack.security.StackSecurityExtension
org.elasticsearch.xpack.watcher.WatcherSecurityExtension