Skip to content

Commit

Permalink
[7.17] Add DEBUG log when DLS/FLS usage is detected (#82182) (#82398)
Browse files Browse the repository at this point in the history
* Add DEBUG log when DLS/FLS usage is detected (#82182)

The `DlsFlsLicenseRequestInterceptor` detects when Field or Document
Level Security is directly used (that is, an index is accessed for which
there is an effective Field or Document level control in place for the
current authentication context). This commit adds DEBUG logging when the
usage is detected, so that unexpected license usage can be more easily
debugged. And example of the logging (for an API Key with DLS) is: >
[DEBUG][o.e.x.s.a.i.DlsFlsLicenseRequestInterceptor] [node] User >
[Authentication[User[username=elastic,roles=[],fullName=null,email=null,
>
metadata={_reserved=true}],type=API_KEY,by={Realm[_es_api_key._es_api_key]
> on Node[node01]}]] has document level security on [[index1]] Relates:
#79152

* Fix backport
  • Loading branch information
tvernum committed Jan 11, 2022
1 parent 0ac0272 commit a9a8fb3
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
Expand Down Expand Up @@ -97,12 +98,21 @@ public DlsFlsUsage getFieldAndDocumentLevelSecurityUsage() {
}

public List<String> getIndicesWithFieldOrDocumentLevelSecurity() {
return getIndexNames(iac -> iac.fieldPermissions.hasFieldLevelSecurity() || iac.documentPermissions.hasDocumentLevelPermissions());
}

public List<String> getIndicesWithFieldLevelSecurity() {
return getIndexNames(iac -> iac.fieldPermissions.hasFieldLevelSecurity());
}

public List<String> getIndicesWithDocumentLevelSecurity() {
return getIndexNames(iac -> iac.documentPermissions.hasDocumentLevelPermissions());
}

private List<String> getIndexNames(Predicate<IndexAccessControl> predicate) {
return indexPermissions.entrySet()
.stream()
.filter(
entry -> entry.getValue().fieldPermissions.hasFieldLevelSecurity()
|| entry.getValue().documentPermissions.hasDocumentLevelPermissions()
)
.filter(entry -> predicate.test(entry.getValue()))
.map(Map.Entry::getKey)
.collect(Collectors.toList());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.message.ParameterizedMessage;
import org.elasticsearch.ElasticsearchSecurityException;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.IndicesRequest;
Expand Down Expand Up @@ -58,11 +59,25 @@ public void intercept(
final IndicesAccessControl.DlsFlsUsage dlsFlsUsage = indicesAccessControl.getFieldAndDocumentLevelSecurityUsage();
boolean incompatibleLicense = false;
if (dlsFlsUsage.hasFieldLevelSecurity()) {
logger.debug(
() -> new ParameterizedMessage(
"User [{}] has field level security on [{}]",
requestInfo.getAuthentication(),
indicesAccessControl.getIndicesWithFieldLevelSecurity()
)
);
if (false == FIELD_LEVEL_SECURITY_FEATURE.check(frozenLicenseState)) {
incompatibleLicense = true;
}
}
if (dlsFlsUsage.hasDocumentLevelSecurity()) {
logger.debug(
() -> new ParameterizedMessage(
"User [{}] has document level security on [{}]",
requestInfo.getAuthentication(),
indicesAccessControl.getIndicesWithDocumentLevelSecurity()
)
);
if (false == DOCUMENT_LEVEL_SECURITY_FEATURE.check(frozenLicenseState)) {
incompatibleLicense = true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.core.Map;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.core.security.authz.accesscontrol.IndicesAccessControl;
import org.elasticsearch.xpack.core.security.authz.accesscontrol.IndicesAccessControl.IndexAccessControl;
Expand All @@ -18,6 +19,7 @@
import java.util.Collections;
import java.util.Set;

import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.emptyIterable;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
Expand All @@ -33,36 +35,51 @@ public void testEmptyIndicesAccessControl() {
IndicesAccessControl indicesAccessControl = new IndicesAccessControl(true, Collections.emptyMap());
assertTrue(indicesAccessControl.isGranted());
assertNull(indicesAccessControl.getIndexPermissions(randomAlphaOfLengthBetween(3, 20)));
assertThat(indicesAccessControl.getIndicesWithFieldOrDocumentLevelSecurity(), emptyIterable());
assertThat(indicesAccessControl.getIndicesWithFieldLevelSecurity(), emptyIterable());
assertThat(indicesAccessControl.getIndicesWithDocumentLevelSecurity(), emptyIterable());
}

public void testSLimitedIndicesAccessControl() {
public void testLimitedIndicesAccessControl() {
IndicesAccessControl indicesAccessControl = new IndicesAccessControl(true, Collections.emptyMap());
IndicesAccessControl limitedByIndicesAccessControl = new IndicesAccessControl(true, Collections.emptyMap());
IndicesAccessControl result = indicesAccessControl.limitIndicesAccessControl(limitedByIndicesAccessControl);
assertThat(result, is(notNullValue()));
assertThat(result.isGranted(), is(true));
assertThat(result.getIndexPermissions("_index"), is(nullValue()));
assertThat(result.getIndicesWithFieldOrDocumentLevelSecurity(), emptyIterable());
assertThat(result.getIndicesWithFieldLevelSecurity(), emptyIterable());
assertThat(result.getIndicesWithDocumentLevelSecurity(), emptyIterable());

indicesAccessControl = new IndicesAccessControl(true, Collections.emptyMap());
limitedByIndicesAccessControl = new IndicesAccessControl(false, Collections.emptyMap());
result = indicesAccessControl.limitIndicesAccessControl(limitedByIndicesAccessControl);
assertThat(result, is(notNullValue()));
assertThat(result.isGranted(), is(false));
assertThat(result.getIndexPermissions("_index"), is(nullValue()));
assertThat(result.getIndicesWithFieldOrDocumentLevelSecurity(), emptyIterable());
assertThat(result.getIndicesWithFieldLevelSecurity(), emptyIterable());
assertThat(result.getIndicesWithDocumentLevelSecurity(), emptyIterable());

indicesAccessControl = new IndicesAccessControl(false, Collections.emptyMap());
limitedByIndicesAccessControl = new IndicesAccessControl(true, Collections.emptyMap());
result = indicesAccessControl.limitIndicesAccessControl(limitedByIndicesAccessControl);
assertThat(result, is(notNullValue()));
assertThat(result.isGranted(), is(false));
assertThat(result.getIndexPermissions("_index"), is(nullValue()));
assertThat(result.getIndicesWithFieldOrDocumentLevelSecurity(), emptyIterable());
assertThat(result.getIndicesWithFieldLevelSecurity(), emptyIterable());
assertThat(result.getIndicesWithDocumentLevelSecurity(), emptyIterable());

indicesAccessControl = new IndicesAccessControl(false, Collections.emptyMap());
limitedByIndicesAccessControl = new IndicesAccessControl(false, Collections.emptyMap());
result = indicesAccessControl.limitIndicesAccessControl(limitedByIndicesAccessControl);
assertThat(result, is(notNullValue()));
assertThat(result.isGranted(), is(false));
assertThat(result.getIndexPermissions("_index"), is(nullValue()));
assertThat(result.getIndicesWithFieldOrDocumentLevelSecurity(), emptyIterable());
assertThat(result.getIndicesWithFieldLevelSecurity(), emptyIterable());
assertThat(result.getIndicesWithDocumentLevelSecurity(), emptyIterable());

indicesAccessControl = new IndicesAccessControl(
true,
Expand All @@ -72,6 +89,9 @@ public void testSLimitedIndicesAccessControl() {
result = indicesAccessControl.limitIndicesAccessControl(limitedByIndicesAccessControl);
assertThat(result, is(notNullValue()));
assertThat(result.getIndexPermissions("_index"), is(nullValue()));
assertThat(result.getIndicesWithFieldOrDocumentLevelSecurity(), emptyIterable());
assertThat(result.getIndicesWithFieldLevelSecurity(), emptyIterable());
assertThat(result.getIndicesWithDocumentLevelSecurity(), emptyIterable());

indicesAccessControl = new IndicesAccessControl(
true,
Expand All @@ -87,6 +107,9 @@ public void testSLimitedIndicesAccessControl() {
assertThat(result.getIndexPermissions("_index").isGranted(), is(true));
assertThat(result.getIndexPermissions("_index").getFieldPermissions().hasFieldLevelSecurity(), is(false));
assertThat(result.getIndexPermissions("_index").getDocumentPermissions().hasDocumentLevelPermissions(), is(false));
assertThat(result.getIndicesWithFieldOrDocumentLevelSecurity(), emptyIterable());
assertThat(result.getIndicesWithFieldLevelSecurity(), emptyIterable());
assertThat(result.getIndicesWithDocumentLevelSecurity(), emptyIterable());

final FieldPermissions fieldPermissions1 = new FieldPermissions(
new FieldPermissionsDefinition(new String[] { "f1", "f2", "f3*" }, new String[] { "f3" })
Expand All @@ -96,18 +119,28 @@ public void testSLimitedIndicesAccessControl() {
);
indicesAccessControl = new IndicesAccessControl(
true,
Collections.singletonMap("_index", new IndexAccessControl(true, fieldPermissions1, DocumentPermissions.allowAll()))
Map.ofEntries(
Map.entry("_index", new IndexAccessControl(true, fieldPermissions1, DocumentPermissions.allowAll())),
Map.entry("another-index", new IndexAccessControl(true, new FieldPermissions(), DocumentPermissions.allowAll()))
)
);
limitedByIndicesAccessControl = new IndicesAccessControl(
true,
Collections.singletonMap("_index", new IndexAccessControl(true, fieldPermissions2, DocumentPermissions.allowAll()))
Map.ofEntries(
Map.entry("_index", new IndexAccessControl(true, fieldPermissions2, DocumentPermissions.allowAll())),
Map.entry("another-index", new IndexAccessControl(true, fieldPermissions2, DocumentPermissions.allowAll()))
)
);
result = indicesAccessControl.limitIndicesAccessControl(limitedByIndicesAccessControl);
assertThat(result, is(notNullValue()));
assertThat(result.getIndexPermissions("_index"), is(notNullValue()));
assertThat(result.getIndexPermissions("_index").isGranted(), is(true));
assertThat(result.getIndexPermissions("_index").getFieldPermissions().hasFieldLevelSecurity(), is(true));
assertThat(result.getIndexPermissions("_index").getDocumentPermissions().hasDocumentLevelPermissions(), is(false));
assertThat(result.getIndicesWithFieldOrDocumentLevelSecurity(), containsInAnyOrder("_index", "another-index"));
assertThat(result.getIndicesWithFieldLevelSecurity(), containsInAnyOrder("_index", "another-index"));
assertThat(result.getIndicesWithDocumentLevelSecurity(), emptyIterable());

FieldPermissions resultFieldPermissions = result.getIndexPermissions("_index").getFieldPermissions();
assertThat(resultFieldPermissions.grantsAccessTo("f1"), is(true));
assertThat(resultFieldPermissions.grantsAccessTo("f2"), is(false));
Expand All @@ -116,18 +149,28 @@ public void testSLimitedIndicesAccessControl() {
assertThat(resultFieldPermissions.grantsAccessTo("f4"), is(false));

Set<BytesReference> queries = Collections.singleton(new BytesArray("{\"match_all\" : {}}"));
final DocumentPermissions documentPermissions = DocumentPermissions.filteredBy(queries);
assertThat(documentPermissions, is(notNullValue()));
assertThat(documentPermissions.hasDocumentLevelPermissions(), is(true));
assertThat(documentPermissions.getQueries(), equalTo(queries));
final DocumentPermissions documentPermissions1 = DocumentPermissions.filteredBy(queries);
assertThat(documentPermissions1, is(notNullValue()));
assertThat(documentPermissions1.hasDocumentLevelPermissions(), is(true));
assertThat(documentPermissions1.getQueries(), equalTo(queries));

final DocumentPermissions documentPermissions2 = DocumentPermissions.filteredBy(
org.elasticsearch.core.Set.of(new BytesArray("{\"term\":{ \"public\":true } }"))
);

indicesAccessControl = new IndicesAccessControl(
true,
Collections.singletonMap("_index", new IndexAccessControl(true, new FieldPermissions(), DocumentPermissions.allowAll()))
Map.ofEntries(
Map.entry("_index", new IndexAccessControl(true, new FieldPermissions(), DocumentPermissions.allowAll())),
Map.entry("another-index", new IndexAccessControl(true, new FieldPermissions(), documentPermissions2))
)
);
limitedByIndicesAccessControl = new IndicesAccessControl(
true,
Collections.singletonMap("_index", new IndexAccessControl(true, new FieldPermissions(), documentPermissions))
Map.ofEntries(
Map.entry("_index", new IndexAccessControl(true, new FieldPermissions(), documentPermissions1)),
Map.entry("another-index", new IndexAccessControl(true, new FieldPermissions(), DocumentPermissions.allowAll()))
)
);
result = indicesAccessControl.limitIndicesAccessControl(limitedByIndicesAccessControl);
assertThat(result, is(notNullValue()));
Expand All @@ -137,6 +180,9 @@ public void testSLimitedIndicesAccessControl() {
assertThat(result.getIndexPermissions("_index").getDocumentPermissions().hasDocumentLevelPermissions(), is(true));
assertThat(result.getIndexPermissions("_index").getDocumentPermissions().getQueries(), is(nullValue()));
assertThat(result.getIndexPermissions("_index").getDocumentPermissions().getLimitedByQueries(), equalTo(queries));
assertThat(result.getIndicesWithFieldOrDocumentLevelSecurity(), containsInAnyOrder("_index", "another-index"));
assertThat(result.getIndicesWithFieldLevelSecurity(), emptyIterable());
assertThat(result.getIndicesWithDocumentLevelSecurity(), containsInAnyOrder("_index", "another-index"));
}

public void testAllowAllIndicesAccessControl() {
Expand All @@ -148,6 +194,8 @@ public void testAllowAllIndicesAccessControl() {
assertThat(allowAll.getDeniedIndices(), emptyIterable());
assertThat(allowAll.getFieldAndDocumentLevelSecurityUsage(), is(IndicesAccessControl.DlsFlsUsage.NONE));
assertThat(allowAll.getIndicesWithFieldOrDocumentLevelSecurity(), emptyIterable());
assertThat(allowAll.getIndicesWithFieldLevelSecurity(), emptyIterable());
assertThat(allowAll.getIndicesWithDocumentLevelSecurity(), emptyIterable());

final IndicesAccessControl indicesAccessControl = new IndicesAccessControl(randomBoolean(), org.elasticsearch.core.Map.of());
assertThat(allowAll.limitIndicesAccessControl(indicesAccessControl), is(indicesAccessControl));
Expand Down

0 comments on commit a9a8fb3

Please sign in to comment.