Skip to content

Commit

Permalink
Allow access to restricted system indices for reserved system roles (#…
Browse files Browse the repository at this point in the history
…76845)

* Add system index patterns to TestRestrictedIndices

A missing piece in #74212 was system index patterns in the tests for the
ReservedRolesStore. Without these patterns, the tests did not accurately
check whether a role was incorrectly accessing a system index that was
not previously a restricted index.

This commit adds all of the current system index patterns to the test
class and adds restricted index access to the system roles that need it
for tests to pass.

* Preserve existing Kibana data telemetry privileges
* Test that data telemetry can't access security and async indices
  • Loading branch information
williamrandolph committed Aug 26, 2021
1 parent d349f25 commit 8759c85
Show file tree
Hide file tree
Showing 3 changed files with 159 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ private static Map<String, RoleDescriptor> initializeReservedRoles() {
RoleDescriptor.IndicesPrivileges.builder()
.indices("*").privileges("monitor").allowRestrictedIndices(true).build(),
RoleDescriptor.IndicesPrivileges.builder()
.indices(".kibana*").privileges("read").build()
.indices(".kibana*").privileges("read").allowRestrictedIndices(true).build()
},
null,
null,
Expand Down Expand Up @@ -199,6 +199,7 @@ private static Map<String, RoleDescriptor> initializeReservedRoles() {
new RoleDescriptor.IndicesPrivileges[] {
RoleDescriptor.IndicesPrivileges.builder()
.indices(".ml-anomalies*", ".ml-notifications*", ".ml-state*", ".ml-meta*", ".ml-stats-*")
.allowRestrictedIndices(true) // .ml-meta is a restricted index
.privileges("view_index_metadata", "read").build(),
RoleDescriptor.IndicesPrivileges.builder().indices(".ml-annotations*")
.privileges("view_index_metadata", "read", "write").build()
Expand Down Expand Up @@ -258,12 +259,13 @@ private static Map<String, RoleDescriptor> initializeReservedRoles() {
.put("watcher_admin", new RoleDescriptor("watcher_admin", new String[] { "manage_watcher" },
new RoleDescriptor.IndicesPrivileges[] {
RoleDescriptor.IndicesPrivileges.builder().indices(Watch.INDEX, TriggeredWatchStoreField.INDEX_NAME,
HistoryStoreField.INDEX_PREFIX + "*").privileges("read").build() },
HistoryStoreField.INDEX_PREFIX + "*").privileges("read").allowRestrictedIndices(true).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")
.allowRestrictedIndices(true)
.build(),
RoleDescriptor.IndicesPrivileges.builder().indices(HistoryStoreField.INDEX_PREFIX + "*")
.privileges("read")
Expand All @@ -272,6 +274,7 @@ private static Map<String, RoleDescriptor> initializeReservedRoles() {
new RoleDescriptor.IndicesPrivileges[] {
RoleDescriptor.IndicesPrivileges.builder().indices(".logstash*")
.privileges("create", "delete", "index", "manage", "read")
.allowRestrictedIndices(true)
.build() },
null, MetadataUtils.DEFAULT_RESERVED_METADATA))
.put("rollup_user", new RoleDescriptor("rollup_user", new String[] { "monitor_rollup" },
Expand Down Expand Up @@ -369,8 +372,9 @@ public static RoleDescriptor kibanaSystemRoleDescriptor(String name) {
"cancel_task"
},
new RoleDescriptor.IndicesPrivileges[] {
// System indices defined in KibanaPlugin
RoleDescriptor.IndicesPrivileges.builder()
.indices(".kibana*", ".reporting-*").privileges("all").build(),
.indices(".kibana*", ".reporting-*").privileges("all").allowRestrictedIndices(true).build(),
RoleDescriptor.IndicesPrivileges.builder()
.indices(".monitoring-*").privileges("read", "read_cross_cluster").build(),
RoleDescriptor.IndicesPrivileges.builder()
Expand All @@ -381,19 +385,20 @@ public static RoleDescriptor kibanaSystemRoleDescriptor(String name) {
.privileges("read").build(),
RoleDescriptor.IndicesPrivileges.builder().indices(".ml-annotations*", ".ml-notifications*")
.privileges("read", "write").build(),
// APM agent configuration
// APM agent configuration - system index defined in KibanaPlugin
RoleDescriptor.IndicesPrivileges.builder()
.indices(".apm-agent-configuration").privileges("all").build(),
// APM custom link index creation
.indices(".apm-agent-configuration").privileges("all").allowRestrictedIndices(true).build(),
// APM custom link index creation - system index defined in KibanaPlugin
RoleDescriptor.IndicesPrivileges.builder()
.indices(".apm-custom-link").privileges("all").build(),
.indices(".apm-custom-link").privileges("all").allowRestrictedIndices(true).build(),
// APM telemetry queries APM indices in kibana task runner
RoleDescriptor.IndicesPrivileges.builder()
.indices("apm-*")
.privileges("read", "read_cross_cluster").build(),
// Data telemetry reads mappings, metadata and stats of indices
// Data telemetry reads mappings, metadata and stats of indices (excluding security and async search indices)
RoleDescriptor.IndicesPrivileges.builder()
.indices("*")
.indices("/@&~(\\.security.*)&~(\\.async-search.*)/")
.allowRestrictedIndices(true)
.privileges("view_index_metadata", "monitor").build(),
// Endpoint diagnostic information. Kibana reads from these indices to send telemetry
RoleDescriptor.IndicesPrivileges.builder()
Expand All @@ -403,6 +408,7 @@ public static RoleDescriptor kibanaSystemRoleDescriptor(String name) {
// Fleet Server indices. Kibana read and write to this indice to manage Elastic Agents
RoleDescriptor.IndicesPrivileges.builder()
.indices(".fleet*")
.allowRestrictedIndices(true)
.privileges("all").build(),
// Legacy "Alerts as data" used in Security Solution.
// Kibana user creates these indices; reads / writes to them.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -532,7 +532,10 @@ public void testKibanaSystemRole() {


// Data telemetry reads mappings, metadata and stats of indices
Arrays.asList(randomAlphaOfLengthBetween(8, 24), "packetbeat-*", "logs-*").forEach((index) -> {
Arrays.asList(randomAlphaOfLengthBetween(8, 24), "packetbeat-*", "logs-*",
// check system indices other than .security* and .async-search*
".watches", ".triggered-watches", ".tasks", ".enrich"
).forEach((index) -> {
logger.info("index name [{}]", index);
assertThat(kibanaRole.indices().allowedIndicesMatcher(GetIndexAction.NAME).test(mockIndexAbstraction(index)), is(true));
assertThat(kibanaRole.indices().allowedIndicesMatcher(GetMappingsAction.NAME).test(mockIndexAbstraction(index)), is(true));
Expand All @@ -550,6 +553,17 @@ public void testKibanaSystemRole() {
assertThat(kibanaRole.indices().allowedIndicesMatcher(READ_CROSS_CLUSTER_NAME).test(mockIndexAbstraction(index)), is(false));
});

// Data telemetry does not have access to security and async search
RestrictedIndicesNames.RESTRICTED_NAMES.forEach((index) -> {
logger.info("index name [{}]", index);
assertThat(kibanaRole.indices().allowedIndicesMatcher(GetIndexAction.NAME).test(mockIndexAbstraction(index)), is(false));
assertThat(kibanaRole.indices().allowedIndicesMatcher(GetMappingsAction.NAME).test(mockIndexAbstraction(index)), is(false));
assertThat(kibanaRole.indices().allowedIndicesMatcher(IndicesStatsAction.NAME).test(mockIndexAbstraction(index)), is(false));
assertThat(kibanaRole.indices().allowedIndicesMatcher("indices:foo").test(mockIndexAbstraction(index)), is(false));
assertThat(kibanaRole.indices().allowedIndicesMatcher("indices:bar").test(mockIndexAbstraction(index)), is(false));
assertThat(kibanaRole.indices().allowedIndicesMatcher(READ_CROSS_CLUSTER_NAME).test(mockIndexAbstraction(index)), is(false));
});

// read-only datastream for Endpoint policy responses
Arrays.asList("metrics-endpoint.policy-" + randomAlphaOfLength(randomIntBetween(0, 13))).forEach((index) -> {
assertThat(kibanaRole.indices().allowedIndicesMatcher("indices:foo").test(mockIndexAbstraction(index)), is(false));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

Expand All @@ -39,51 +40,140 @@ public class TestRestrictedIndices {
public static final IndexNameExpressionResolver RESOLVER;

static {
SystemIndices systemIndices = new SystemIndices(Map.of(
"security-mock",
Map<String, Feature> featureMap = new HashMap<>();
featureMap.put("security-mock",
new Feature("security-mock", "fake security for test restricted indices", List.of(
SystemIndexDescriptor.builder()
// This can't just be `.security-*` because that would overlap with the tokens index pattern
.setIndexPattern(".security-[0-9]+")
.setPrimaryIndex(RestrictedIndicesNames.INTERNAL_SECURITY_MAIN_INDEX_7)
.setDescription("Contains Security configuration")
.setMappings(mockMappings())
.setSettings(Settings.EMPTY)
.setAliasName(SECURITY_MAIN_ALIAS)
.setIndexFormat(7)
.setVersionMetaKey("version")
.setOrigin(SECURITY_ORIGIN)
.setThreadPools(ExecutorNames.CRITICAL_SYSTEM_INDEX_THREAD_POOLS)
.build(),
SystemIndexDescriptor.builder()
.setIndexPattern(".security-tokens-[0-9]+")
.setPrimaryIndex(RestrictedIndicesNames.INTERNAL_SECURITY_TOKENS_INDEX_7)
.setDescription("Contains auth token data")
.setMappings(mockMappings())
.setSettings(Settings.EMPTY)
.setAliasName(SECURITY_TOKENS_ALIAS)
.setIndexFormat(7)
.setVersionMetaKey("version")
.setOrigin(SECURITY_ORIGIN)
.setThreadPools(ExecutorNames.CRITICAL_SYSTEM_INDEX_THREAD_POOLS)
.build()
)),
"async-search-mock",
getMainSecurityDescriptor(),
getSecurityTokensDescriptor())));
featureMap.put("async-search-mock",
new Feature("async search mock", "fake async search for restricted indices", List.of(
SystemIndexDescriptor.builder()
.setIndexPattern(XPackPlugin.ASYNC_RESULTS_INDEX + "*")
.setDescription("Async search results")
.setPrimaryIndex(XPackPlugin.ASYNC_RESULTS_INDEX)
.setMappings(mockMappings())
.setSettings(Settings.EMPTY)
.setVersionMetaKey("version")
.setOrigin(ASYNC_SEARCH_ORIGIN)
.build()
))));
getAsyncSearchDescriptor())));
featureMap.put("kibana-mock",
new Feature("kibana-mock", "fake kibana for testing restricted indices", List.of(
getKibanaSavedObjectsDescriptor(),
getReportingIndexDescriptor(),
getApmAgentConfigDescriptor(),
getApmCustomLinkDescriptor())));

// From here, we have very minimal mock features that only supply system index patterns,
// not settings or mock mappings.
featureMap.put("enrich-mock",
new Feature("enrich-mock", "fake enrich for restricted indices tests", List.of(
new SystemIndexDescriptor(".enrich-*", "enrich pattern"))));
featureMap.put("fleet-mock",
new Feature("fleet-mock", "fake fleet for restricted indices tests", List.of(
new SystemIndexDescriptor(".fleet-actions~(-results*)", "fleet actions"),
new SystemIndexDescriptor(".fleet-agents*", "fleet agents"),
new SystemIndexDescriptor(".fleet-enrollment-api-keys*", "fleet enrollment"),
new SystemIndexDescriptor(".fleet-policies-[0-9]+", "fleet policies"),
new SystemIndexDescriptor(".fleet-policies-leader*", "fleet policies leader"),
new SystemIndexDescriptor(".fleet-servers*", "fleet servers"),
new SystemIndexDescriptor(".fleet-artifacts*", "fleet artifacts"))));
featureMap.put("ingest-geoip-mock",
new Feature("ingest-geoip-mock", "fake geoip for restricted indices tests", List.of(
new SystemIndexDescriptor(".geoip_databases", "geoip databases"))));
featureMap.put("logstash-mock",
new Feature("logstash-mock", "fake logstash for restricted indices tests", List.of(
new SystemIndexDescriptor(".logstash", "logstash"))));
featureMap.put("machine-learning-mock",
new Feature("machine-learning-mock", "fake machine learning for restricted indices tests", List.of(
new SystemIndexDescriptor(".ml-meta*", "machine learning meta"),
new SystemIndexDescriptor(".ml-config*", "machine learning config"),
new SystemIndexDescriptor(".ml-inference*", "machine learning inference"))));
featureMap.put("searchable-snapshots-mock",
new Feature("searchable-snapshots-mock", "fake searchable snapshots for restricted indices tests", List.of(
new SystemIndexDescriptor(".snapshot-blob-cache", "snapshot blob cache"))));
featureMap.put("transform-mock",
new Feature("transform-mock", "fake transform for restricted indices tests", List.of(
new SystemIndexDescriptor(".transform-internal-*", "transform internal"))));
featureMap.put("watcher-mock",
new Feature("watcher-mock", "fake watcher for restricted indices tests", List.of(
new SystemIndexDescriptor(".watches*", "watches"),
new SystemIndexDescriptor(".triggered-watches*", "triggered watches"))));

SystemIndices systemIndices = new SystemIndices(featureMap);
RESTRICTED_INDICES_AUTOMATON = systemIndices.getSystemNameAutomaton();
RESOLVER = TestIndexNameExpressionResolver.newInstance(systemIndices);
}

private static SystemIndexDescriptor.Builder getInitializedDescriptorBuilder() {
return SystemIndexDescriptor.builder()
.setMappings(mockMappings())
.setSettings(Settings.EMPTY)
.setVersionMetaKey("version");
}

private static SystemIndexDescriptor getMainSecurityDescriptor() {
return getInitializedDescriptorBuilder()
// This can't just be `.security-*` because that would overlap with the tokens index pattern
.setIndexPattern(".security-[0-9]+")
.setPrimaryIndex(RestrictedIndicesNames.INTERNAL_SECURITY_MAIN_INDEX_7)
.setDescription("Contains Security configuration")
.setAliasName(SECURITY_MAIN_ALIAS)
.setIndexFormat(7)
.setOrigin(SECURITY_ORIGIN)
.setThreadPools(ExecutorNames.CRITICAL_SYSTEM_INDEX_THREAD_POOLS)
.build();
}

private static SystemIndexDescriptor getSecurityTokensDescriptor() {
return getInitializedDescriptorBuilder()
.setIndexPattern(".security-tokens-[0-9]+")
.setPrimaryIndex(RestrictedIndicesNames.INTERNAL_SECURITY_TOKENS_INDEX_7)
.setDescription("Contains auth token data")
.setAliasName(SECURITY_TOKENS_ALIAS)
.setIndexFormat(7)
.setOrigin(SECURITY_ORIGIN)
.setThreadPools(ExecutorNames.CRITICAL_SYSTEM_INDEX_THREAD_POOLS)
.build();
}

private static SystemIndexDescriptor getAsyncSearchDescriptor() {
return getInitializedDescriptorBuilder()
.setIndexPattern(XPackPlugin.ASYNC_RESULTS_INDEX + "*")
.setDescription("Async search results")
.setPrimaryIndex(XPackPlugin.ASYNC_RESULTS_INDEX)
.setOrigin(ASYNC_SEARCH_ORIGIN)
.build();
}

private static SystemIndexDescriptor getKibanaSavedObjectsDescriptor() {
return SystemIndexDescriptor.builder()
.setIndexPattern(".kibana_*")
.setDescription("Kibana saved objects system index")
.setAliasName(".kibana")
.setType(SystemIndexDescriptor.Type.EXTERNAL_UNMANAGED)
.setAllowedElasticProductOrigins( List.of("kibana"))
.build();
}

private static SystemIndexDescriptor getReportingIndexDescriptor() {
return SystemIndexDescriptor.builder()
.setIndexPattern(".reporting-*")
.setDescription("system index for reporting")
.setType(SystemIndexDescriptor.Type.EXTERNAL_UNMANAGED)
.setAllowedElasticProductOrigins(List.of("kibana"))
.build();
}

private static SystemIndexDescriptor getApmAgentConfigDescriptor() {
return SystemIndexDescriptor.builder()
.setIndexPattern(".apm-agent-configuration")
.setDescription("system index for APM agent configuration")
.setType(SystemIndexDescriptor.Type.EXTERNAL_UNMANAGED)
.setAllowedElasticProductOrigins(List.of("kibana"))
.build();
}

private static SystemIndexDescriptor getApmCustomLinkDescriptor() {
return SystemIndexDescriptor.builder()
.setIndexPattern(".apm-custom-link")
.setDescription("system index for APM custom links")
.setType(SystemIndexDescriptor.Type.EXTERNAL_UNMANAGED)
.setAllowedElasticProductOrigins(List.of("kibana"))
.build();
}

private TestRestrictedIndices() {}

private static XContentBuilder mockMappings() {
Expand Down

0 comments on commit 8759c85

Please sign in to comment.