Make .async-search-* a restricted namespace (#50294)
Hide the `.async-search-*` in Security by making it a restricted index namespace. The namespace is hard-coded. To grant privileges on restricted indices, one must explicitly toggle the `allow_restricted_indices` flag in the indices permission in the role definition. As is the case with any other index, if a certain user lacks all permissions for an index, that index is effectively nonexistent for that user.
This commit is contained in:
parent
c31a21c3d8
commit
2b789fa3e6
|
@ -119,17 +119,13 @@ public final class FieldExpression implements RoleMapperExpression {
|
|||
private static CharacterRunAutomaton buildAutomaton(Object value) {
|
||||
if (value instanceof String) {
|
||||
final String str = (String) value;
|
||||
if (Regex.isSimpleMatchPattern(str) || isLuceneRegex(str)) {
|
||||
if (Regex.isSimpleMatchPattern(str) || Automatons.isLuceneRegex(str)) {
|
||||
return new CharacterRunAutomaton(Automatons.patterns(str));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean isLuceneRegex(String str) {
|
||||
return str.length() > 1 && str.charAt(0) == '/' && str.charAt(str.length() - 1) == '/';
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ import org.elasticsearch.cluster.metadata.IndexMetaData;
|
|||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.bytes.BytesReference;
|
||||
import org.elasticsearch.common.regex.Regex;
|
||||
import org.elasticsearch.xpack.core.security.authz.accesscontrol.IndicesAccessControl;
|
||||
import org.elasticsearch.xpack.core.security.authz.privilege.IndexPrivilege;
|
||||
import org.elasticsearch.xpack.core.security.index.RestrictedIndicesNames;
|
||||
|
@ -139,7 +140,7 @@ public final class IndicesPermission {
|
|||
final Map<IndicesPermission.Group, Automaton> predicateCache = new HashMap<>();
|
||||
for (String forIndexPattern : checkForIndexPatterns) {
|
||||
Automaton checkIndexAutomaton = Automatons.patterns(forIndexPattern);
|
||||
if (false == allowRestrictedIndices && false == RestrictedIndicesNames.RESTRICTED_NAMES.contains(forIndexPattern)) {
|
||||
if (false == allowRestrictedIndices && false == isConcreteRestrictedIndex(forIndexPattern)) {
|
||||
checkIndexAutomaton = Automatons.minusAndMinimize(checkIndexAutomaton, RestrictedIndicesNames.NAMES_AUTOMATON);
|
||||
}
|
||||
if (false == Operations.isEmpty(checkIndexAutomaton)) {
|
||||
|
@ -268,6 +269,13 @@ public final class IndicesPermission {
|
|||
return unmodifiableMap(indexPermissions);
|
||||
}
|
||||
|
||||
private boolean isConcreteRestrictedIndex(String indexPattern) {
|
||||
if (Regex.isSimpleMatchPattern(indexPattern) || Automatons.isLuceneRegex(indexPattern)) {
|
||||
return false;
|
||||
}
|
||||
return RestrictedIndicesNames.isRestricted(indexPattern);
|
||||
}
|
||||
|
||||
public static class Group {
|
||||
private final IndexPrivilege privilege;
|
||||
private final Predicate<String> actionMatcher;
|
||||
|
@ -316,7 +324,7 @@ public final class IndicesPermission {
|
|||
private boolean check(String action, String index) {
|
||||
assert index != null;
|
||||
return check(action) && indexNameMatcher.test(index)
|
||||
&& (allowRestrictedIndices || (false == RestrictedIndicesNames.RESTRICTED_NAMES.contains(index)));
|
||||
&& (allowRestrictedIndices || (false == RestrictedIndicesNames.isRestricted(index)));
|
||||
}
|
||||
|
||||
boolean hasQuery() {
|
||||
|
@ -351,13 +359,13 @@ public final class IndicesPermission {
|
|||
final Predicate<String> predicate;
|
||||
if (restrictedIndices.isEmpty()) {
|
||||
predicate = indexMatcher(ordinaryIndices)
|
||||
.and(index -> false == RestrictedIndicesNames.RESTRICTED_NAMES.contains(index));
|
||||
.and(index -> false == RestrictedIndicesNames.isRestricted(index));
|
||||
} else if (ordinaryIndices.isEmpty()) {
|
||||
predicate = indexMatcher(restrictedIndices);
|
||||
} else {
|
||||
predicate = indexMatcher(restrictedIndices)
|
||||
.or(indexMatcher(ordinaryIndices)
|
||||
.and(index -> false == RestrictedIndicesNames.RESTRICTED_NAMES.contains(index)));
|
||||
.and(index -> false == RestrictedIndicesNames.isRestricted(index)));
|
||||
}
|
||||
return predicate;
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import org.apache.lucene.util.automaton.Automaton;
|
|||
import org.elasticsearch.common.util.set.Sets;
|
||||
import org.elasticsearch.xpack.core.security.support.Automatons;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
|
@ -21,10 +22,20 @@ public final class RestrictedIndicesNames {
|
|||
public static final String INTERNAL_SECURITY_TOKENS_INDEX_7 = ".security-tokens-7";
|
||||
public static final String SECURITY_TOKENS_ALIAS = ".security-tokens";
|
||||
|
||||
// public for tests
|
||||
public static final String ASYNC_SEARCH_PREFIX = ".async-search-";
|
||||
private static final Automaton ASYNC_SEARCH_AUTOMATON = Automatons.patterns(ASYNC_SEARCH_PREFIX + "*");
|
||||
|
||||
// public for tests
|
||||
public static final Set<String> RESTRICTED_NAMES = Collections.unmodifiableSet(Sets.newHashSet(SECURITY_MAIN_ALIAS,
|
||||
INTERNAL_SECURITY_MAIN_INDEX_6, INTERNAL_SECURITY_MAIN_INDEX_7, INTERNAL_SECURITY_TOKENS_INDEX_7, SECURITY_TOKENS_ALIAS));
|
||||
|
||||
public static final Automaton NAMES_AUTOMATON = Automatons.patterns(RESTRICTED_NAMES);
|
||||
public static boolean isRestricted(String concreteIndexName) {
|
||||
return RESTRICTED_NAMES.contains(concreteIndexName) || concreteIndexName.startsWith(ASYNC_SEARCH_PREFIX);
|
||||
}
|
||||
|
||||
public static final Automaton NAMES_AUTOMATON = Automatons.unionAndMinimize(Arrays.asList(Automatons.patterns(RESTRICTED_NAMES),
|
||||
ASYNC_SEARCH_AUTOMATON));
|
||||
|
||||
private RestrictedIndicesNames() {
|
||||
}
|
||||
|
|
|
@ -107,6 +107,13 @@ public final class Automatons {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the str a lucene type of pattern
|
||||
*/
|
||||
public static boolean isLuceneRegex(String str) {
|
||||
return str.length() > 1 && str.charAt(0) == '/' && str.charAt(str.length() - 1) == '/';
|
||||
}
|
||||
|
||||
private static Automaton buildAutomaton(String pattern) {
|
||||
if (pattern.startsWith("/")) { // it's a lucene regexp
|
||||
if (pattern.length() == 1 || !pattern.endsWith("/")) {
|
||||
|
|
|
@ -249,8 +249,11 @@ public class ReservedRolesStoreTests extends ESTestCase {
|
|||
// but that depends on how users are supposed to perform snapshots of those new indices.
|
||||
assertThat(snapshotUserRole.indices().allowedIndicesMatcher(GetIndexAction.NAME).test(index), is(true));
|
||||
}
|
||||
assertThat(snapshotUserRole.indices().allowedIndicesMatcher(GetIndexAction.NAME).test(
|
||||
RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2)), is(true));
|
||||
|
||||
assertNoAccessAllowed(snapshotUserRole, RestrictedIndicesNames.RESTRICTED_NAMES);
|
||||
assertNoAccessAllowed(snapshotUserRole, RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2));
|
||||
}
|
||||
|
||||
public void testIngestAdminRole() {
|
||||
|
@ -280,6 +283,7 @@ public class ReservedRolesStoreTests extends ESTestCase {
|
|||
is(false));
|
||||
|
||||
assertNoAccessAllowed(ingestAdminRole, RestrictedIndicesNames.RESTRICTED_NAMES);
|
||||
assertNoAccessAllowed(ingestAdminRole, RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2));
|
||||
}
|
||||
|
||||
public void testKibanaSystemRole() {
|
||||
|
@ -390,6 +394,7 @@ public class ReservedRolesStoreTests extends ESTestCase {
|
|||
assertThat(kibanaRole.indices().allowedIndicesMatcher(READ_CROSS_CLUSTER_NAME).test(index), is(false));
|
||||
|
||||
assertNoAccessAllowed(kibanaRole, RestrictedIndicesNames.RESTRICTED_NAMES);
|
||||
assertNoAccessAllowed(kibanaRole, RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2));
|
||||
}
|
||||
|
||||
public void testKibanaUserRole() {
|
||||
|
@ -429,6 +434,7 @@ public class ReservedRolesStoreTests extends ESTestCase {
|
|||
"*"), is(false));
|
||||
|
||||
assertNoAccessAllowed(kibanaUserRole, RestrictedIndicesNames.RESTRICTED_NAMES);
|
||||
assertNoAccessAllowed(kibanaUserRole, RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2));
|
||||
}
|
||||
|
||||
public void testMonitoringUserRole() {
|
||||
|
@ -476,6 +482,7 @@ public class ReservedRolesStoreTests extends ESTestCase {
|
|||
assertThat(monitoringUserRole.indices().allowedIndicesMatcher(READ_CROSS_CLUSTER_NAME).test(index), is(true));
|
||||
|
||||
assertNoAccessAllowed(monitoringUserRole, RestrictedIndicesNames.RESTRICTED_NAMES);
|
||||
assertNoAccessAllowed(monitoringUserRole, RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2));
|
||||
|
||||
final String kibanaApplicationWithRandomIndex = "kibana-" + randomFrom(randomAlphaOfLengthBetween(8, 24), ".kibana");
|
||||
assertThat(monitoringUserRole.application().grants(
|
||||
|
@ -550,6 +557,7 @@ public class ReservedRolesStoreTests extends ESTestCase {
|
|||
assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(GetAction.NAME).test(metricbeatIndex), is(false));
|
||||
|
||||
assertNoAccessAllowed(remoteMonitoringAgentRole, RestrictedIndicesNames.RESTRICTED_NAMES);
|
||||
assertNoAccessAllowed(remoteMonitoringAgentRole, RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2));
|
||||
}
|
||||
|
||||
public void testRemoteMonitoringCollectorRole() {
|
||||
|
@ -603,29 +611,50 @@ public class ReservedRolesStoreTests extends ESTestCase {
|
|||
// (but ideally, the monitoring user should see all indices).
|
||||
assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(GetSettingsAction.NAME)
|
||||
.test(randomFrom(RestrictedIndicesNames.RESTRICTED_NAMES)), is(true));
|
||||
assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(GetSettingsAction.NAME)
|
||||
.test(RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2)), is(true));
|
||||
assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(IndicesShardStoresAction.NAME)
|
||||
.test(randomFrom(RestrictedIndicesNames.RESTRICTED_NAMES)), is(true));
|
||||
assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(IndicesShardStoresAction.NAME)
|
||||
.test(RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2)), is(true));
|
||||
assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(UpgradeStatusAction.NAME)
|
||||
.test(randomFrom(RestrictedIndicesNames.RESTRICTED_NAMES)), is(true));
|
||||
assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(UpgradeStatusAction.NAME)
|
||||
.test(RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2)), is(true));
|
||||
assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(RecoveryAction.NAME)
|
||||
.test(randomFrom(RestrictedIndicesNames.RESTRICTED_NAMES)), is(true));
|
||||
assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(RecoveryAction.NAME)
|
||||
.test(RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2)), is(true));
|
||||
assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(IndicesStatsAction.NAME)
|
||||
.test(randomFrom(RestrictedIndicesNames.RESTRICTED_NAMES)), is(true));
|
||||
assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(IndicesStatsAction.NAME)
|
||||
.test(RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2)), is(true));
|
||||
assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(IndicesSegmentsAction.NAME)
|
||||
.test(randomFrom(RestrictedIndicesNames.RESTRICTED_NAMES)), is(true));
|
||||
assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(IndicesSegmentsAction.NAME)
|
||||
.test(RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2)), is(true));
|
||||
|
||||
assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(SearchAction.NAME)
|
||||
.test(randomFrom(RestrictedIndicesNames.RESTRICTED_NAMES)), is(false));
|
||||
assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(SearchAction.NAME)
|
||||
.test(RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2)), is(false));
|
||||
assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(GetAction.NAME)
|
||||
.test(randomFrom(RestrictedIndicesNames.RESTRICTED_NAMES)), is(false));
|
||||
assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(GetAction.NAME)
|
||||
.test(RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2)), is(false));
|
||||
assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(DeleteAction.NAME)
|
||||
.test(randomFrom(RestrictedIndicesNames.RESTRICTED_NAMES)), is(false));
|
||||
assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(DeleteAction.NAME)
|
||||
.test(RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2)), is(false));
|
||||
assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(IndexAction.NAME)
|
||||
.test(randomFrom(RestrictedIndicesNames.RESTRICTED_NAMES)), is(false));
|
||||
assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(IndexAction.NAME)
|
||||
.test(RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2)), is(false));
|
||||
|
||||
assertMonitoringOnRestrictedIndices(remoteMonitoringAgentRole);
|
||||
|
||||
assertNoAccessAllowed(remoteMonitoringAgentRole, RestrictedIndicesNames.RESTRICTED_NAMES);
|
||||
assertNoAccessAllowed(remoteMonitoringAgentRole, RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2));
|
||||
}
|
||||
|
||||
private void assertMonitoringOnRestrictedIndices(Role role) {
|
||||
|
@ -644,11 +673,13 @@ public class ReservedRolesStoreTests extends ESTestCase {
|
|||
final List<String> indexMonitoringActionNamesList = Arrays.asList(IndicesStatsAction.NAME, IndicesSegmentsAction.NAME,
|
||||
GetSettingsAction.NAME, IndicesShardStoresAction.NAME, UpgradeStatusAction.NAME, RecoveryAction.NAME);
|
||||
for (final String indexMonitoringActionName : indexMonitoringActionNamesList) {
|
||||
String asyncSearchIndex = RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2);
|
||||
final Map<String, IndexAccessControl> authzMap = role.indices().authorize(indexMonitoringActionName,
|
||||
Sets.newHashSet(internalSecurityIndex, RestrictedIndicesNames.SECURITY_MAIN_ALIAS),
|
||||
Sets.newHashSet(internalSecurityIndex, RestrictedIndicesNames.SECURITY_MAIN_ALIAS, asyncSearchIndex),
|
||||
metaData.getAliasAndIndexLookup(), fieldPermissionsCache);
|
||||
assertThat(authzMap.get(internalSecurityIndex).isGranted(), is(true));
|
||||
assertThat(authzMap.get(RestrictedIndicesNames.SECURITY_MAIN_ALIAS).isGranted(), is(true));
|
||||
assertThat(authzMap.get(asyncSearchIndex).isGranted(), is(true));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -692,6 +723,7 @@ public class ReservedRolesStoreTests extends ESTestCase {
|
|||
assertThat(reportingUserRole.indices().allowedIndicesMatcher(BulkAction.NAME).test(index), is(false));
|
||||
|
||||
assertNoAccessAllowed(reportingUserRole, RestrictedIndicesNames.RESTRICTED_NAMES);
|
||||
assertNoAccessAllowed(reportingUserRole, RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2));
|
||||
}
|
||||
|
||||
public void testKibanaDashboardOnlyUserRole() {
|
||||
|
@ -728,6 +760,7 @@ public class ReservedRolesStoreTests extends ESTestCase {
|
|||
new ApplicationPrivilege(applicationWithRandomIndex, "app-random-index", "all"), "*"), is(false));
|
||||
|
||||
assertNoAccessAllowed(dashboardsOnlyUserRole, RestrictedIndicesNames.RESTRICTED_NAMES);
|
||||
assertNoAccessAllowed(dashboardsOnlyUserRole, RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2));
|
||||
}
|
||||
|
||||
public void testSuperuserRole() {
|
||||
|
@ -828,6 +861,7 @@ public class ReservedRolesStoreTests extends ESTestCase {
|
|||
is(false));
|
||||
|
||||
assertNoAccessAllowed(logstashSystemRole, RestrictedIndicesNames.RESTRICTED_NAMES);
|
||||
assertNoAccessAllowed(logstashSystemRole, RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2));
|
||||
}
|
||||
|
||||
public void testBeatsAdminRole() {
|
||||
|
@ -868,6 +902,7 @@ public class ReservedRolesStoreTests extends ESTestCase {
|
|||
assertThat(beatsAdminRole.indices().allowedIndicesMatcher(GetAction.NAME).test(index), is(true));
|
||||
|
||||
assertNoAccessAllowed(beatsAdminRole, RestrictedIndicesNames.RESTRICTED_NAMES);
|
||||
assertNoAccessAllowed(beatsAdminRole, RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2));
|
||||
}
|
||||
|
||||
public void testBeatsSystemRole() {
|
||||
|
@ -903,6 +938,7 @@ public class ReservedRolesStoreTests extends ESTestCase {
|
|||
assertThat(beatsSystemRole.indices().allowedIndicesMatcher(BulkAction.NAME).test(index), is(true));
|
||||
|
||||
assertNoAccessAllowed(beatsSystemRole, RestrictedIndicesNames.RESTRICTED_NAMES);
|
||||
assertNoAccessAllowed(beatsSystemRole, RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2));
|
||||
}
|
||||
|
||||
public void testAPMSystemRole() {
|
||||
|
@ -943,7 +979,7 @@ public class ReservedRolesStoreTests extends ESTestCase {
|
|||
"indices:data/write/index:op_type/" + randomAlphaOfLengthBetween(3,5)).test(index), is(false));
|
||||
|
||||
assertNoAccessAllowed(APMSystemRole, RestrictedIndicesNames.RESTRICTED_NAMES);
|
||||
|
||||
assertNoAccessAllowed(APMSystemRole, RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2));
|
||||
}
|
||||
|
||||
public void testAPMUserRole() {
|
||||
|
@ -1037,6 +1073,7 @@ public class ReservedRolesStoreTests extends ESTestCase {
|
|||
assertReadWriteDocsButNotDeleteIndexAllowed(role, AnnotationIndex.INDEX_NAME);
|
||||
|
||||
assertNoAccessAllowed(role, RestrictedIndicesNames.RESTRICTED_NAMES);
|
||||
assertNoAccessAllowed(role, RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2));
|
||||
|
||||
final String kibanaApplicationWithRandomIndex = "kibana-" + randomFrom(randomAlphaOfLengthBetween(8, 24), ".kibana");
|
||||
assertThat(role.application().grants(
|
||||
|
@ -1123,6 +1160,7 @@ public class ReservedRolesStoreTests extends ESTestCase {
|
|||
assertReadWriteDocsButNotDeleteIndexAllowed(role, AnnotationIndex.INDEX_NAME);
|
||||
|
||||
assertNoAccessAllowed(role, RestrictedIndicesNames.RESTRICTED_NAMES);
|
||||
assertNoAccessAllowed(role, RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2));
|
||||
|
||||
|
||||
final String kibanaApplicationWithRandomIndex = "kibana-" + randomFrom(randomAlphaOfLengthBetween(8, 24), ".kibana");
|
||||
|
@ -1170,6 +1208,7 @@ public class ReservedRolesStoreTests extends ESTestCase {
|
|||
assertNoAccessAllowed(role, TransformInternalIndexConstants.LATEST_INDEX_NAME); // internal use only
|
||||
|
||||
assertNoAccessAllowed(role, RestrictedIndicesNames.RESTRICTED_NAMES);
|
||||
assertNoAccessAllowed(role, RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2));
|
||||
|
||||
final String kibanaApplicationWithRandomIndex = "kibana-" + randomFrom(randomAlphaOfLengthBetween(8, 24), ".kibana");
|
||||
assertThat(role.application().grants(
|
||||
|
@ -1222,6 +1261,7 @@ public class ReservedRolesStoreTests extends ESTestCase {
|
|||
assertNoAccessAllowed(role, TransformInternalIndexConstants.LATEST_INDEX_NAME);
|
||||
|
||||
assertNoAccessAllowed(role, RestrictedIndicesNames.RESTRICTED_NAMES);
|
||||
assertNoAccessAllowed(role, RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2));
|
||||
|
||||
final String kibanaApplicationWithRandomIndex = "kibana-" + randomFrom(randomAlphaOfLengthBetween(8, 24), ".kibana");
|
||||
assertThat(role.application().grants(
|
||||
|
@ -1272,6 +1312,7 @@ public class ReservedRolesStoreTests extends ESTestCase {
|
|||
}
|
||||
|
||||
assertNoAccessAllowed(role, RestrictedIndicesNames.RESTRICTED_NAMES);
|
||||
assertNoAccessAllowed(role, RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2));
|
||||
}
|
||||
|
||||
public void testWatcherUserRole() {
|
||||
|
@ -1305,6 +1346,7 @@ public class ReservedRolesStoreTests extends ESTestCase {
|
|||
}
|
||||
|
||||
assertNoAccessAllowed(role, RestrictedIndicesNames.RESTRICTED_NAMES);
|
||||
assertNoAccessAllowed(role, RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2));
|
||||
}
|
||||
|
||||
private void assertReadWriteDocsButNotDeleteIndexAllowed(Role role, String index) {
|
||||
|
@ -1329,6 +1371,7 @@ public class ReservedRolesStoreTests extends ESTestCase {
|
|||
assertThat(role.indices().allowedIndicesMatcher(BulkAction.NAME).test(index), is(false));
|
||||
|
||||
assertNoAccessAllowed(role, RestrictedIndicesNames.RESTRICTED_NAMES);
|
||||
assertNoAccessAllowed(role, RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2));
|
||||
}
|
||||
|
||||
private void assertNoAccessAllowed(Role role, Collection<String> indices) {
|
||||
|
|
|
@ -545,6 +545,117 @@ public class RBACEngineTests extends ESTestCase {
|
|||
));
|
||||
}
|
||||
|
||||
public void testCheckRestrictedIndexPatternPermission() throws Exception {
|
||||
User user = new User(randomAlphaOfLengthBetween(4, 12));
|
||||
Authentication authentication = mock(Authentication.class);
|
||||
when(authentication.getUser()).thenReturn(user);
|
||||
final String patternPrefix = RestrictedIndicesNames.ASYNC_SEARCH_PREFIX.substring(0,
|
||||
randomIntBetween(1, RestrictedIndicesNames.ASYNC_SEARCH_PREFIX.length() - 2));
|
||||
Role role = Role.builder("role")
|
||||
.add(FieldPermissions.DEFAULT, null, IndexPrivilege.INDEX, false, patternPrefix + "*")
|
||||
.build();
|
||||
RBACAuthorizationInfo authzInfo = new RBACAuthorizationInfo(role, null);
|
||||
|
||||
String prePatternPrefix = patternPrefix.substring(0, randomIntBetween(1, patternPrefix.length() - 1)) + "*";
|
||||
HasPrivilegesResponse response = hasPrivileges(RoleDescriptor.IndicesPrivileges.builder()
|
||||
.indices(prePatternPrefix)
|
||||
.allowRestrictedIndices(randomBoolean())
|
||||
.privileges("index")
|
||||
.build(), authentication, authzInfo, Collections.emptyList(), Strings.EMPTY_ARRAY);
|
||||
assertThat(response.isCompleteMatch(), is(false));
|
||||
assertThat(response.getIndexPrivileges(), Matchers.iterableWithSize(1));
|
||||
assertThat(response.getIndexPrivileges(), containsInAnyOrder(
|
||||
ResourcePrivileges.builder(prePatternPrefix)
|
||||
.addPrivileges(MapBuilder.newMapBuilder(new LinkedHashMap<String, Boolean>())
|
||||
.put("index", false).map()).build()));
|
||||
|
||||
String matchesPatternPrefix = RestrictedIndicesNames.ASYNC_SEARCH_PREFIX.substring(0, patternPrefix.length() + 1);
|
||||
response = hasPrivileges(RoleDescriptor.IndicesPrivileges.builder()
|
||||
.indices(matchesPatternPrefix + "*")
|
||||
.allowRestrictedIndices(false)
|
||||
.privileges("index")
|
||||
.build(), authentication, authzInfo, Collections.emptyList(), Strings.EMPTY_ARRAY);
|
||||
assertThat(response.isCompleteMatch(), is(true));
|
||||
assertThat(response.getIndexPrivileges(), Matchers.iterableWithSize(1));
|
||||
assertThat(response.getIndexPrivileges(), containsInAnyOrder(
|
||||
ResourcePrivileges.builder(matchesPatternPrefix + "*")
|
||||
.addPrivileges(MapBuilder.newMapBuilder(new LinkedHashMap<String, Boolean>())
|
||||
.put("index", true).map()).build()));
|
||||
response = hasPrivileges(RoleDescriptor.IndicesPrivileges.builder()
|
||||
.indices(matchesPatternPrefix + "*")
|
||||
.allowRestrictedIndices(true)
|
||||
.privileges("index")
|
||||
.build(), authentication, authzInfo, Collections.emptyList(), Strings.EMPTY_ARRAY);
|
||||
assertThat(response.isCompleteMatch(), is(false));
|
||||
assertThat(response.getIndexPrivileges(), Matchers.iterableWithSize(1));
|
||||
assertThat(response.getIndexPrivileges(), containsInAnyOrder(
|
||||
ResourcePrivileges.builder(matchesPatternPrefix + "*")
|
||||
.addPrivileges(MapBuilder.newMapBuilder(new LinkedHashMap<String, Boolean>())
|
||||
.put("index", false).map()).build()));
|
||||
response = hasPrivileges(RoleDescriptor.IndicesPrivileges.builder()
|
||||
.indices(matchesPatternPrefix)
|
||||
.allowRestrictedIndices(randomBoolean())
|
||||
.privileges("index")
|
||||
.build(), authentication, authzInfo, Collections.emptyList(), Strings.EMPTY_ARRAY);
|
||||
assertThat(response.isCompleteMatch(), is(true));
|
||||
assertThat(response.getIndexPrivileges(), Matchers.iterableWithSize(1));
|
||||
assertThat(response.getIndexPrivileges(), containsInAnyOrder(
|
||||
ResourcePrivileges.builder(matchesPatternPrefix)
|
||||
.addPrivileges(MapBuilder.newMapBuilder(new LinkedHashMap<String, Boolean>())
|
||||
.put("index", true).map()).build()));
|
||||
|
||||
final String restrictedIndexMatchingWildcard = RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2);
|
||||
response = hasPrivileges(RoleDescriptor.IndicesPrivileges.builder()
|
||||
.indices(restrictedIndexMatchingWildcard + "*")
|
||||
.allowRestrictedIndices(true)
|
||||
.privileges("index")
|
||||
.build(), authentication, authzInfo, Collections.emptyList(), Strings.EMPTY_ARRAY);
|
||||
assertThat(response.isCompleteMatch(), is(false));
|
||||
assertThat(response.getIndexPrivileges(), Matchers.iterableWithSize(1));
|
||||
assertThat(response.getIndexPrivileges(), containsInAnyOrder(
|
||||
ResourcePrivileges.builder(restrictedIndexMatchingWildcard + "*")
|
||||
.addPrivileges(MapBuilder.newMapBuilder(new LinkedHashMap<String, Boolean>())
|
||||
.put("index", false).map()).build()));
|
||||
response = hasPrivileges(RoleDescriptor.IndicesPrivileges.builder()
|
||||
.indices(restrictedIndexMatchingWildcard + "*")
|
||||
.allowRestrictedIndices(false)
|
||||
.privileges("index")
|
||||
.build(), authentication, authzInfo, Collections.emptyList(), Strings.EMPTY_ARRAY);
|
||||
assertThat(response.isCompleteMatch(), is(false));
|
||||
assertThat(response.getIndexPrivileges(), Matchers.iterableWithSize(1));
|
||||
assertThat(response.getIndexPrivileges(), containsInAnyOrder(
|
||||
ResourcePrivileges.builder(restrictedIndexMatchingWildcard + "*")
|
||||
.addPrivileges(MapBuilder.newMapBuilder(new LinkedHashMap<String, Boolean>())
|
||||
.put("index", false).map()).build()));
|
||||
response = hasPrivileges(RoleDescriptor.IndicesPrivileges.builder()
|
||||
.indices(restrictedIndexMatchingWildcard)
|
||||
.allowRestrictedIndices(randomBoolean())
|
||||
.privileges("index")
|
||||
.build(), authentication, authzInfo, Collections.emptyList(), Strings.EMPTY_ARRAY);
|
||||
assertThat(response.isCompleteMatch(), is(false));
|
||||
assertThat(response.getIndexPrivileges(), Matchers.iterableWithSize(1));
|
||||
assertThat(response.getIndexPrivileges(), containsInAnyOrder(
|
||||
ResourcePrivileges.builder(restrictedIndexMatchingWildcard)
|
||||
.addPrivileges(MapBuilder.newMapBuilder(new LinkedHashMap<String, Boolean>())
|
||||
.put("index", false).map()).build()));
|
||||
|
||||
role = Role.builder("role")
|
||||
.add(FieldPermissions.DEFAULT, null, IndexPrivilege.INDEX, true, patternPrefix + "*")
|
||||
.build();
|
||||
authzInfo = new RBACAuthorizationInfo(role, null);
|
||||
response = hasPrivileges(RoleDescriptor.IndicesPrivileges.builder()
|
||||
.indices(matchesPatternPrefix + "*")
|
||||
.allowRestrictedIndices(randomBoolean())
|
||||
.privileges("index")
|
||||
.build(), authentication, authzInfo, Collections.emptyList(), Strings.EMPTY_ARRAY);
|
||||
assertThat(response.isCompleteMatch(), is(true));
|
||||
assertThat(response.getIndexPrivileges(), Matchers.iterableWithSize(1));
|
||||
assertThat(response.getIndexPrivileges(), containsInAnyOrder(
|
||||
ResourcePrivileges.builder(matchesPatternPrefix + "*")
|
||||
.addPrivileges(MapBuilder.newMapBuilder(new LinkedHashMap<String, Boolean>())
|
||||
.put("index", true).map()).build()));
|
||||
}
|
||||
|
||||
public void testCheckExplicitRestrictedIndexPermissions() throws Exception {
|
||||
User user = new User(randomAlphaOfLengthBetween(4, 12));
|
||||
Authentication authentication = mock(Authentication.class);
|
||||
|
|
|
@ -323,6 +323,32 @@ public class IndicesPermissionTests extends ESTestCase {
|
|||
assertThat(authzMap.get(RestrictedIndicesNames.SECURITY_MAIN_ALIAS).isGranted(), is(true));
|
||||
}
|
||||
|
||||
public void testAsyncSearchIndicesPermissions() {
|
||||
final Settings indexSettings = Settings.builder().put("index.version.created", Version.CURRENT).build();
|
||||
final String asyncSearchIndex = RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2);
|
||||
final MetaData metaData = new MetaData.Builder()
|
||||
.put(new IndexMetaData.Builder(asyncSearchIndex)
|
||||
.settings(indexSettings)
|
||||
.numberOfShards(1)
|
||||
.numberOfReplicas(0)
|
||||
.build(), true)
|
||||
.build();
|
||||
FieldPermissionsCache fieldPermissionsCache = new FieldPermissionsCache(Settings.EMPTY);
|
||||
SortedMap<String, AliasOrIndex> lookup = metaData.getAliasAndIndexLookup();
|
||||
|
||||
// allow_restricted_indices: false
|
||||
IndicesPermission.Group group = new IndicesPermission.Group(IndexPrivilege.ALL, new FieldPermissions(), null, false, "*");
|
||||
Map<String, IndicesAccessControl.IndexAccessControl> authzMap = new IndicesPermission(group).authorize(SearchAction.NAME,
|
||||
Sets.newHashSet(asyncSearchIndex), lookup, fieldPermissionsCache);
|
||||
assertThat(authzMap.get(asyncSearchIndex).isGranted(), is(false));
|
||||
|
||||
// allow_restricted_indices: true
|
||||
group = new IndicesPermission.Group(IndexPrivilege.ALL, new FieldPermissions(), null, true, "*");
|
||||
authzMap = new IndicesPermission(group).authorize(SearchAction.NAME,
|
||||
Sets.newHashSet(asyncSearchIndex), lookup, fieldPermissionsCache);
|
||||
assertThat(authzMap.get(asyncSearchIndex).isGranted(), is(true));
|
||||
}
|
||||
|
||||
private static FieldPermissionsDefinition fieldPermissionDef(String[] granted, String[] denied) {
|
||||
return new FieldPermissionsDefinition(granted, denied);
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ public class XPackUserTests extends ESTestCase {
|
|||
for (String index : RestrictedIndicesNames.RESTRICTED_NAMES) {
|
||||
assertThat(predicate.test(index), Matchers.is(false));
|
||||
}
|
||||
assertThat(predicate.test(RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2)), Matchers.is(false));
|
||||
}
|
||||
|
||||
public void testXPackUserCanReadAuditTrail() {
|
||||
|
|
|
@ -41,6 +41,7 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static java.util.Collections.singletonMap;
|
||||
|
@ -650,7 +651,8 @@ public abstract class SqlSecurityTestCase extends ESRestTestCase {
|
|||
* SQL drops them from the interface. So we might have access to them, but we
|
||||
* don't show them.
|
||||
*/
|
||||
indices.removeAll(RestrictedIndicesNames.RESTRICTED_NAMES);
|
||||
indices = indices.stream().filter(
|
||||
idx -> false == RestrictedIndicesNames.isRestricted(idx)).collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
// Use a sorted list for indices for consistent error reporting
|
||||
|
|
Loading…
Reference in New Issue