Security: Add watcher_user and watcher_admin role (elastic/x-pack-elasticsearch#983)
This built-in watcher_admin role is able to execute all watcher actions, read the watch history indices and read the watches index index. The watcher_user role allows to GET a watch and to get the stats and thats it. relates elastic/x-pack-elasticsearch#978 Original commit: elastic/x-pack-elasticsearch@11b33a413b
This commit is contained in:
parent
a5f0a74b67
commit
71852c7215
|
@ -120,6 +120,18 @@ Grants access necessary for the Logstash system user to send data to Elasticsear
|
|||
NOTE: This role should not be assigned to users as the granted permissions may
|
||||
change between releases.
|
||||
|
||||
[[built-in-roles-watcher-user]]
|
||||
`watcher_user`::
|
||||
+
|
||||
Grants read access to the `.watches` index, the get watch action and the watcher
|
||||
stats.
|
||||
|
||||
[[built-in-roles-watcher-admin]]
|
||||
`watcher_admin`::
|
||||
+
|
||||
Grants write access to the `.watches` index, read access to the watch history and
|
||||
the triggered watches index and allows to execute all watcher actions.
|
||||
|
||||
[[defining-roles]]
|
||||
=== Defining Roles
|
||||
|
||||
|
|
|
@ -15,6 +15,9 @@ settings update, rerouting, or managing users and roles.
|
|||
All cluster read-only operations, like cluster health & state, hot threads, node
|
||||
info, node & cluster stats, snapshot/restore status, pending cluster tasks.
|
||||
|
||||
`monitor_watcher`::
|
||||
All read only watcher operations, such as getting a watch and watcher stats.
|
||||
|
||||
`manage`::
|
||||
Builds on `monitor` and adds cluster operations that change values in the cluster.
|
||||
This includes snapshotting,updating settings, and rerouting. This privilege does
|
||||
|
@ -30,6 +33,9 @@ All operations on index templates.
|
|||
`manage_pipeline`::
|
||||
All operations on ingest pipelines.
|
||||
|
||||
`manage_watcher`::
|
||||
All watcher operations, such as putting watches, executing, activate or acknowledging.
|
||||
|
||||
`transport_client`::
|
||||
All privileges necessary for a transport client to connect.
|
||||
|
||||
|
|
|
@ -27,9 +27,11 @@ public final class ClusterPrivilege extends Privilege {
|
|||
private static final Automaton MANAGE_SECURITY_AUTOMATON = patterns("cluster:admin/xpack/security/*");
|
||||
private static final Automaton MONITOR_AUTOMATON = patterns("cluster:monitor/*");
|
||||
private static final Automaton MONITOR_ML_AUTOMATON = patterns("cluster:monitor/xpack/ml/*");
|
||||
private static final Automaton MONITOR_WATCHER_AUTOMATON = patterns("cluster:monitor/xpack/watcher/*");
|
||||
private static final Automaton ALL_CLUSTER_AUTOMATON = patterns("cluster:*", "indices:admin/template/*");
|
||||
private static final Automaton MANAGE_AUTOMATON = minusAndMinimize(ALL_CLUSTER_AUTOMATON, MANAGE_SECURITY_AUTOMATON);
|
||||
private static final Automaton MANAGE_ML_AUTOMATON = patterns("cluster:admin/xpack/ml/*", "cluster:monitor/xpack/ml/*");
|
||||
private static final Automaton MANAGE_WATCHER_AUTOMATON = patterns("cluster:admin/xpack/watcher/*", "cluster:monitor/xpack/watcher/*");
|
||||
private static final Automaton TRANSPORT_CLIENT_AUTOMATON = patterns("cluster:monitor/nodes/liveness", "cluster:monitor/state");
|
||||
private static final Automaton MANAGE_IDX_TEMPLATE_AUTOMATON = patterns("indices:admin/template/*");
|
||||
private static final Automaton MANAGE_INGEST_PIPELINE_AUTOMATON = patterns("cluster:admin/ingest/pipeline/*");
|
||||
|
@ -38,8 +40,10 @@ public final class ClusterPrivilege extends Privilege {
|
|||
public static final ClusterPrivilege ALL = new ClusterPrivilege("all", ALL_CLUSTER_AUTOMATON);
|
||||
public static final ClusterPrivilege MONITOR = new ClusterPrivilege("monitor", MONITOR_AUTOMATON);
|
||||
public static final ClusterPrivilege MONITOR_ML = new ClusterPrivilege("monitor_ml", MONITOR_ML_AUTOMATON);
|
||||
public static final ClusterPrivilege MONITOR_WATCHER = new ClusterPrivilege("monitor_watcher", MONITOR_WATCHER_AUTOMATON);
|
||||
public static final ClusterPrivilege MANAGE = new ClusterPrivilege("manage", MANAGE_AUTOMATON);
|
||||
public static final ClusterPrivilege MANAGE_ML = new ClusterPrivilege("manage_ml", MANAGE_ML_AUTOMATON);
|
||||
public static final ClusterPrivilege MANAGE_WATCHER = new ClusterPrivilege("manage_watcher", MANAGE_WATCHER_AUTOMATON);
|
||||
public static final ClusterPrivilege MANAGE_IDX_TEMPLATES =
|
||||
new ClusterPrivilege("manage_index_templates", MANAGE_IDX_TEMPLATE_AUTOMATON);
|
||||
public static final ClusterPrivilege MANAGE_INGEST_PIPELINES =
|
||||
|
@ -55,8 +59,10 @@ public final class ClusterPrivilege extends Privilege {
|
|||
.put("all", ALL)
|
||||
.put("monitor", MONITOR)
|
||||
.put("monitor_ml", MONITOR_ML)
|
||||
.put("monitor_watcher", MONITOR_WATCHER)
|
||||
.put("manage", MANAGE)
|
||||
.put("manage_ml", MANAGE_ML)
|
||||
.put("manage_watcher", MANAGE_WATCHER)
|
||||
.put("manage_index_templates", MANAGE_IDX_TEMPLATES)
|
||||
.put("manage_ingest_pipelines", MANAGE_INGEST_PIPELINES)
|
||||
.put("transport_client", TRANSPORT_CLIENT)
|
||||
|
|
|
@ -5,19 +5,21 @@
|
|||
*/
|
||||
package org.elasticsearch.xpack.security.authz.store;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
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.support.MetadataUtils;
|
||||
|
||||
import org.elasticsearch.xpack.security.user.KibanaUser;
|
||||
import org.elasticsearch.xpack.security.user.SystemUser;
|
||||
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.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class ReservedRolesStore {
|
||||
|
||||
|
@ -70,6 +72,19 @@ public class ReservedRolesStore {
|
|||
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))
|
||||
.immutableMap();
|
||||
}
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ import org.elasticsearch.cluster.metadata.IndexMetaData;
|
|||
import org.elasticsearch.cluster.metadata.MetaData;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.util.set.Sets;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.xpack.monitoring.action.MonitoringBulkAction;
|
||||
import org.elasticsearch.xpack.security.action.role.PutRoleAction;
|
||||
import org.elasticsearch.xpack.security.action.user.PutUserAction;
|
||||
|
@ -41,7 +42,19 @@ import org.elasticsearch.xpack.security.authz.accesscontrol.IndicesAccessControl
|
|||
import org.elasticsearch.xpack.security.authz.permission.FieldPermissionsCache;
|
||||
import org.elasticsearch.xpack.security.authz.permission.Role;
|
||||
import org.elasticsearch.xpack.security.user.SystemUser;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.xpack.watcher.execution.TriggeredWatchStore;
|
||||
import org.elasticsearch.xpack.watcher.history.HistoryStore;
|
||||
import org.elasticsearch.xpack.watcher.transport.actions.ack.AckWatchAction;
|
||||
import org.elasticsearch.xpack.watcher.transport.actions.activate.ActivateWatchAction;
|
||||
import org.elasticsearch.xpack.watcher.transport.actions.delete.DeleteWatchAction;
|
||||
import org.elasticsearch.xpack.watcher.transport.actions.execute.ExecuteWatchAction;
|
||||
import org.elasticsearch.xpack.watcher.transport.actions.get.GetWatchAction;
|
||||
import org.elasticsearch.xpack.watcher.transport.actions.put.PutWatchAction;
|
||||
import org.elasticsearch.xpack.watcher.transport.actions.service.WatcherServiceAction;
|
||||
import org.elasticsearch.xpack.watcher.transport.actions.stats.WatcherStatsAction;
|
||||
import org.elasticsearch.xpack.watcher.watch.Watch;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.DateTimeZone;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
|
@ -65,6 +78,8 @@ public class ReservedRolesStoreTests extends ESTestCase {
|
|||
assertThat(ReservedRolesStore.isReserved("remote_monitoring_agent"), is(true));
|
||||
assertThat(ReservedRolesStore.isReserved("monitoring_user"), is(true));
|
||||
assertThat(ReservedRolesStore.isReserved("reporting_user"), is(true));
|
||||
assertThat(ReservedRolesStore.isReserved("watcher_user"), is(true));
|
||||
assertThat(ReservedRolesStore.isReserved("watcher_admin"), is(true));
|
||||
}
|
||||
|
||||
public void testIngestAdminRole() {
|
||||
|
@ -361,4 +376,67 @@ public class ReservedRolesStoreTests extends ESTestCase {
|
|||
assertThat(beatsSystemRole.indices().allowedIndicesMatcher("indices:foo").test(randomAlphaOfLengthBetween(8, 24)),
|
||||
is(false));
|
||||
}
|
||||
|
||||
public void testWatcherAdminRole() {
|
||||
RoleDescriptor roleDescriptor = new ReservedRolesStore().roleDescriptor("watcher_admin");
|
||||
assertNotNull(roleDescriptor);
|
||||
assertThat(roleDescriptor.getMetadata(), hasEntry("_reserved", true));
|
||||
|
||||
Role role = Role.builder(roleDescriptor, null).build();
|
||||
assertThat(role.cluster().check(PutWatchAction.NAME), is(true));
|
||||
assertThat(role.cluster().check(GetWatchAction.NAME), is(true));
|
||||
assertThat(role.cluster().check(DeleteWatchAction.NAME), is(true));
|
||||
assertThat(role.cluster().check(ExecuteWatchAction.NAME), is(true));
|
||||
assertThat(role.cluster().check(AckWatchAction.NAME), is(true));
|
||||
assertThat(role.cluster().check(ActivateWatchAction.NAME), is(true));
|
||||
assertThat(role.cluster().check(WatcherServiceAction.NAME), is(true));
|
||||
assertThat(role.cluster().check(WatcherStatsAction.NAME), is(true));
|
||||
assertThat(role.runAs().check(randomAlphaOfLengthBetween(1, 30)), is(false));
|
||||
|
||||
assertThat(role.indices().allowedIndicesMatcher(IndexAction.NAME).test("foo"), is(false));
|
||||
|
||||
DateTime now = DateTime.now(DateTimeZone.UTC);
|
||||
String historyIndex = HistoryStore.getHistoryIndexNameForTime(now);
|
||||
for (String index : new String[]{ Watch.INDEX, historyIndex, TriggeredWatchStore.INDEX_NAME }) {
|
||||
assertOnlyReadAllowed(role, index);
|
||||
}
|
||||
}
|
||||
|
||||
public void testWatcherUserRole() {
|
||||
RoleDescriptor roleDescriptor = new ReservedRolesStore().roleDescriptor("watcher_user");
|
||||
assertNotNull(roleDescriptor);
|
||||
assertThat(roleDescriptor.getMetadata(), hasEntry("_reserved", true));
|
||||
|
||||
Role role = Role.builder(roleDescriptor, null).build();
|
||||
assertThat(role.cluster().check(PutWatchAction.NAME), is(false));
|
||||
assertThat(role.cluster().check(GetWatchAction.NAME), is(true));
|
||||
assertThat(role.cluster().check(DeleteWatchAction.NAME), is(false));
|
||||
assertThat(role.cluster().check(ExecuteWatchAction.NAME), is(false));
|
||||
assertThat(role.cluster().check(AckWatchAction.NAME), is(false));
|
||||
assertThat(role.cluster().check(ActivateWatchAction.NAME), is(false));
|
||||
assertThat(role.cluster().check(WatcherServiceAction.NAME), is(false));
|
||||
assertThat(role.cluster().check(WatcherStatsAction.NAME), is(true));
|
||||
assertThat(role.runAs().check(randomAlphaOfLengthBetween(1, 30)), is(false));
|
||||
|
||||
assertThat(role.indices().allowedIndicesMatcher(IndexAction.NAME).test("foo"), is(false));
|
||||
assertThat(role.indices().allowedIndicesMatcher(IndexAction.NAME).test(TriggeredWatchStore.INDEX_NAME), is(false));
|
||||
|
||||
DateTime now = DateTime.now(DateTimeZone.UTC);
|
||||
String historyIndex = HistoryStore.getHistoryIndexNameForTime(now);
|
||||
for (String index : new String[]{ Watch.INDEX, historyIndex }) {
|
||||
assertOnlyReadAllowed(role, index);
|
||||
}
|
||||
}
|
||||
|
||||
private void assertOnlyReadAllowed(Role role, String index) {
|
||||
assertThat(role.indices().allowedIndicesMatcher(DeleteIndexAction.NAME).test(index), is(false));
|
||||
assertThat(role.indices().allowedIndicesMatcher(CreateIndexAction.NAME).test(index), is(false));
|
||||
assertThat(role.indices().allowedIndicesMatcher(UpdateSettingsAction.NAME).test(index), is(false));
|
||||
assertThat(role.indices().allowedIndicesMatcher(SearchAction.NAME).test(index), is(true));
|
||||
assertThat(role.indices().allowedIndicesMatcher(GetAction.NAME).test(index), is(true));
|
||||
assertThat(role.indices().allowedIndicesMatcher(IndexAction.NAME).test(index), is(false));
|
||||
assertThat(role.indices().allowedIndicesMatcher(UpdateAction.NAME).test(index), is(false));
|
||||
assertThat(role.indices().allowedIndicesMatcher(DeleteAction.NAME).test(index), is(false));
|
||||
assertThat(role.indices().allowedIndicesMatcher(BulkAction.NAME).test(index), is(false));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue