Skip to content

Commit a620525

Browse files
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.
1 parent 8727f27 commit a620525

File tree

9 files changed

+218
-13
lines changed

9 files changed

+218
-13
lines changed

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/support/mapper/expressiondsl/FieldExpression.java

+1-5
Original file line numberDiff line numberDiff line change
@@ -119,17 +119,13 @@ public FieldValue(Object value) {
119119
private static CharacterRunAutomaton buildAutomaton(Object value) {
120120
if (value instanceof String) {
121121
final String str = (String) value;
122-
if (Regex.isSimpleMatchPattern(str) || isLuceneRegex(str)) {
122+
if (Regex.isSimpleMatchPattern(str) || Automatons.isLuceneRegex(str)) {
123123
return new CharacterRunAutomaton(Automatons.patterns(str));
124124
}
125125
}
126126
return null;
127127
}
128128

129-
private static boolean isLuceneRegex(String str) {
130-
return str.length() > 1 && str.charAt(0) == '/' && str.charAt(str.length() - 1) == '/';
131-
}
132-
133129
public Object getValue() {
134130
return value;
135131
}

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/permission/IndicesPermission.java

+12-4
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import org.elasticsearch.common.Nullable;
1616
import org.elasticsearch.common.Strings;
1717
import org.elasticsearch.common.bytes.BytesReference;
18+
import org.elasticsearch.common.regex.Regex;
1819
import org.elasticsearch.xpack.core.security.authz.accesscontrol.IndicesAccessControl;
1920
import org.elasticsearch.xpack.core.security.authz.privilege.IndexPrivilege;
2021
import org.elasticsearch.xpack.core.security.index.RestrictedIndicesNames;
@@ -139,7 +140,7 @@ public ResourcePrivilegesMap checkResourcePrivileges(Set<String> checkForIndexPa
139140
final Map<IndicesPermission.Group, Automaton> predicateCache = new HashMap<>();
140141
for (String forIndexPattern : checkForIndexPatterns) {
141142
Automaton checkIndexAutomaton = Automatons.patterns(forIndexPattern);
142-
if (false == allowRestrictedIndices && false == RestrictedIndicesNames.RESTRICTED_NAMES.contains(forIndexPattern)) {
143+
if (false == allowRestrictedIndices && false == isConcreteRestrictedIndex(forIndexPattern)) {
143144
checkIndexAutomaton = Automatons.minusAndMinimize(checkIndexAutomaton, RestrictedIndicesNames.NAMES_AUTOMATON);
144145
}
145146
if (false == Operations.isEmpty(checkIndexAutomaton)) {
@@ -268,6 +269,13 @@ public Map<String, IndicesAccessControl.IndexAccessControl> authorize(String act
268269
return unmodifiableMap(indexPermissions);
269270
}
270271

272+
private boolean isConcreteRestrictedIndex(String indexPattern) {
273+
if (Regex.isSimpleMatchPattern(indexPattern) || Automatons.isLuceneRegex(indexPattern)) {
274+
return false;
275+
}
276+
return RestrictedIndicesNames.isRestricted(indexPattern);
277+
}
278+
271279
public static class Group {
272280
private final IndexPrivilege privilege;
273281
private final Predicate<String> actionMatcher;
@@ -316,7 +324,7 @@ private boolean check(String action) {
316324
private boolean check(String action, String index) {
317325
assert index != null;
318326
return check(action) && indexNameMatcher.test(index)
319-
&& (allowRestrictedIndices || (false == RestrictedIndicesNames.RESTRICTED_NAMES.contains(index)));
327+
&& (allowRestrictedIndices || (false == RestrictedIndicesNames.isRestricted(index)));
320328
}
321329

322330
boolean hasQuery() {
@@ -351,13 +359,13 @@ private static Predicate<String> buildIndexMatcherPredicateForAction(String acti
351359
final Predicate<String> predicate;
352360
if (restrictedIndices.isEmpty()) {
353361
predicate = indexMatcher(ordinaryIndices)
354-
.and(index -> false == RestrictedIndicesNames.RESTRICTED_NAMES.contains(index));
362+
.and(index -> false == RestrictedIndicesNames.isRestricted(index));
355363
} else if (ordinaryIndices.isEmpty()) {
356364
predicate = indexMatcher(restrictedIndices);
357365
} else {
358366
predicate = indexMatcher(restrictedIndices)
359367
.or(indexMatcher(ordinaryIndices)
360-
.and(index -> false == RestrictedIndicesNames.RESTRICTED_NAMES.contains(index)));
368+
.and(index -> false == RestrictedIndicesNames.isRestricted(index)));
361369
}
362370
return predicate;
363371
}

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/index/RestrictedIndicesNames.java

+12-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import org.elasticsearch.common.util.set.Sets;
1111
import org.elasticsearch.xpack.core.security.support.Automatons;
1212

13+
import java.util.Arrays;
1314
import java.util.Collections;
1415
import java.util.Set;
1516

@@ -21,10 +22,20 @@ public final class RestrictedIndicesNames {
2122
public static final String INTERNAL_SECURITY_TOKENS_INDEX_7 = ".security-tokens-7";
2223
public static final String SECURITY_TOKENS_ALIAS = ".security-tokens";
2324

25+
// public for tests
26+
public static final String ASYNC_SEARCH_PREFIX = ".async-search-";
27+
private static final Automaton ASYNC_SEARCH_AUTOMATON = Automatons.patterns(ASYNC_SEARCH_PREFIX + "*");
28+
29+
// public for tests
2430
public static final Set<String> RESTRICTED_NAMES = Collections.unmodifiableSet(Sets.newHashSet(SECURITY_MAIN_ALIAS,
2531
INTERNAL_SECURITY_MAIN_INDEX_6, INTERNAL_SECURITY_MAIN_INDEX_7, INTERNAL_SECURITY_TOKENS_INDEX_7, SECURITY_TOKENS_ALIAS));
2632

27-
public static final Automaton NAMES_AUTOMATON = Automatons.patterns(RESTRICTED_NAMES);
33+
public static boolean isRestricted(String concreteIndexName) {
34+
return RESTRICTED_NAMES.contains(concreteIndexName) || concreteIndexName.startsWith(ASYNC_SEARCH_PREFIX);
35+
}
36+
37+
public static final Automaton NAMES_AUTOMATON = Automatons.unionAndMinimize(Arrays.asList(Automatons.patterns(RESTRICTED_NAMES),
38+
ASYNC_SEARCH_AUTOMATON));
2839

2940
private RestrictedIndicesNames() {
3041
}

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/support/Automatons.java

+7
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,13 @@ static Automaton pattern(String pattern) {
107107
}
108108
}
109109

110+
/**
111+
* Is the str a lucene type of pattern
112+
*/
113+
public static boolean isLuceneRegex(String str) {
114+
return str.length() > 1 && str.charAt(0) == '/' && str.charAt(str.length() - 1) == '/';
115+
}
116+
110117
private static Automaton buildAutomaton(String pattern) {
111118
if (pattern.startsWith("/")) { // it's a lucene regexp
112119
if (pattern.length() == 1 || !pattern.endsWith("/")) {

0 commit comments

Comments
 (0)