To avoid ambiguity (as cluster and index policies may have the same

name) changing implementation to have to separate policies for
`index_privileges` and `cluster_privileges`.
If both are set for the same policy, throw the IllegalArgumentException.
This commit is contained in:
BigPandaToo 2021-01-28 21:32:10 +01:00
parent a7585b783f
commit cb5bc09c7e
4 changed files with 144 additions and 52 deletions

View file

@ -149,13 +149,26 @@ A list of authentication realm names or wildcards. The specified policy will
not print audit events for users in these realms. not print audit events for users in these realms.
// end::xpack-sa-lf-events-ignore-realms-tag[] // end::xpack-sa-lf-events-ignore-realms-tag[]
[[xpack-sa-lf-events-ignore-privileges]] [[xpack-sa-lf-events-ignore-index-privileges]]
// tag::xpack-sa-lf-events-ignore-privileges-tag[] // tag::xpack-sa-lf-events-ignore-index-privileges-tag[]
`xpack.security.audit.logfile.events.ignore_filters.<policy_name>.privileges`:: `xpack.security.audit.logfile.events.ignore_filters.<policy_name>.index_privileges`::
(<<dynamic-cluster-setting,Dynamic>>) (<<dynamic-cluster-setting,Dynamic>>)
A list of privileges. The specified policy will not print audit events for actions A list of index privileges. The specified policy will not print audit events for actions
requiring any of these privileges. requiring any of these privileges.
// end::xpack-sa-lf-events-ignore-privileges-tag[] // end::xpack-sa-lf-events-ignore-index-privileges-tag[]
[[xpack-sa-lf-events-ignore-cluster-privileges]]
// tag::xpack-sa-lf-events-ignore-cluster-privileges-tag[]
`xpack.security.audit.logfile.events.ignore_filters.<policy_name>.cluster_privileges`::
(<<dynamic-cluster-setting,Dynamic>>)
A list of cluster privileges. The specified policy will not print audit events for actions
requiring any of these privileges.
// end::xpack-sa-lf-events-ignore-cluster-privileges-tag[]
[NOTE]
Either `cluster_privileges` or `index_privileges` ignore filter can be specified
for the same policy.
If you need to filter out both index and cluster actions, you can create two different policies.
[[xpack-sa-lf-events-ignore-roles]] [[xpack-sa-lf-events-ignore-roles]]
// tag::xpack-sa-lf-events-ignore-roles-tag[] // tag::xpack-sa-lf-events-ignore-roles-tag[]

View file

@ -79,7 +79,6 @@ import org.elasticsearch.xpack.security.Security;
import org.elasticsearch.xpack.security.audit.AuditLevel; import org.elasticsearch.xpack.security.audit.AuditLevel;
import org.elasticsearch.xpack.security.audit.AuditTrail; import org.elasticsearch.xpack.security.audit.AuditTrail;
import org.elasticsearch.xpack.security.authc.ApiKeyService; import org.elasticsearch.xpack.security.authc.ApiKeyService;
import org.elasticsearch.xpack.security.authz.AuthorizationService;
import org.elasticsearch.xpack.security.rest.RemoteHostHeader; import org.elasticsearch.xpack.security.rest.RemoteHostHeader;
import org.elasticsearch.xpack.security.transport.filter.IPFilter; import org.elasticsearch.xpack.security.transport.filter.IPFilter;
import org.elasticsearch.xpack.security.transport.filter.SecurityIpFilterRule; import org.elasticsearch.xpack.security.transport.filter.SecurityIpFilterRule;
@ -94,6 +93,7 @@ import java.util.Collections;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Objects; import java.util.Objects;
@ -221,8 +221,12 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
Setting.affixKeySetting(FILTER_POLICY_PREFIX, "indices", Setting.affixKeySetting(FILTER_POLICY_PREFIX, "indices",
(key) -> Setting.listSetting(key, Collections.singletonList("*"), Function.identity(), (key) -> Setting.listSetting(key, Collections.singletonList("*"), Function.identity(),
value -> EventFilterPolicy.parsePredicate(value), Property.NodeScope, Property.Dynamic)); value -> EventFilterPolicy.parsePredicate(value), Property.NodeScope, Property.Dynamic));
protected static final Setting.AffixSetting<List<String>> FILTER_POLICY_IGNORE_PRIVILEGES = protected static final Setting.AffixSetting<List<String>> FILTER_POLICY_IGNORE_INDEX_PRIVILEGES =
Setting.affixKeySetting(FILTER_POLICY_PREFIX, "privileges", Setting.affixKeySetting(FILTER_POLICY_PREFIX, "index_privileges",
(key) -> Setting.listSetting(key, Collections.singletonList("*"), Function.identity(),
value -> EventFilterPolicy.parsePredicate(value), Property.NodeScope, Property.Dynamic));
protected static final Setting.AffixSetting<List<String>> FILTER_POLICY_IGNORE_CLUSTER_PRIVILEGES =
Setting.affixKeySetting(FILTER_POLICY_PREFIX, "cluster_privileges",
(key) -> Setting.listSetting(key, Collections.singletonList("*"), Function.identity(), (key) -> Setting.listSetting(key, Collections.singletonList("*"), Function.identity(),
value -> EventFilterPolicy.parsePredicate(value), Property.NodeScope, Property.Dynamic)); value -> EventFilterPolicy.parsePredicate(value), Property.NodeScope, Property.Dynamic));
@ -284,10 +288,16 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
final EventFilterPolicy newPolicy = policy.orElse(new EventFilterPolicy(policyName, settings)).changeIndicesFilter(filtersList); final EventFilterPolicy newPolicy = policy.orElse(new EventFilterPolicy(policyName, settings)).changeIndicesFilter(filtersList);
this.eventFilterPolicyRegistry.set(policyName, newPolicy); this.eventFilterPolicyRegistry.set(policyName, newPolicy);
}, (policyName, filtersList) -> EventFilterPolicy.parsePredicate(filtersList)); }, (policyName, filtersList) -> EventFilterPolicy.parsePredicate(filtersList));
clusterService.getClusterSettings().addAffixUpdateConsumer(FILTER_POLICY_IGNORE_PRIVILEGES, (policyName, filtersList) -> { clusterService.getClusterSettings().addAffixUpdateConsumer(FILTER_POLICY_IGNORE_INDEX_PRIVILEGES, (policyName, filtersList) -> {
final Optional<EventFilterPolicy> policy = eventFilterPolicyRegistry.get(policyName); final Optional<EventFilterPolicy> policy = eventFilterPolicyRegistry.get(policyName);
final EventFilterPolicy newPolicy = policy.orElse(new EventFilterPolicy(policyName, settings)). final EventFilterPolicy newPolicy = policy.orElse(new EventFilterPolicy(policyName, settings)).
changePrivilegesFilter(filtersList); changeIndexPrivilegesFilter(filtersList);
this.eventFilterPolicyRegistry.set(policyName, newPolicy);
}, (policyName, filtersList) -> EventFilterPolicy.parsePredicate(filtersList));
clusterService.getClusterSettings().addAffixUpdateConsumer(FILTER_POLICY_IGNORE_CLUSTER_PRIVILEGES, (policyName, filtersList) -> {
final Optional<EventFilterPolicy> policy = eventFilterPolicyRegistry.get(policyName);
final EventFilterPolicy newPolicy = policy.orElse(new EventFilterPolicy(policyName, settings)).
changeClusterPrivilegesFilter(filtersList);
this.eventFilterPolicyRegistry.set(policyName, newPolicy); this.eventFilterPolicyRegistry.set(policyName, newPolicy);
}, (policyName, filtersList) -> EventFilterPolicy.parsePredicate(filtersList)); }, (policyName, filtersList) -> EventFilterPolicy.parsePredicate(filtersList));
// this log filter ensures that audit events are not filtered out because of the log level // this log filter ensures that audit events are not filtered out because of the log level
@ -1345,13 +1355,15 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
settings.add(FILTER_POLICY_IGNORE_INDICES); settings.add(FILTER_POLICY_IGNORE_INDICES);
settings.add(FILTER_POLICY_IGNORE_ROLES); settings.add(FILTER_POLICY_IGNORE_ROLES);
settings.add(FILTER_POLICY_IGNORE_REALMS); settings.add(FILTER_POLICY_IGNORE_REALMS);
settings.add(FILTER_POLICY_IGNORE_PRIVILEGES); settings.add(FILTER_POLICY_IGNORE_INDEX_PRIVILEGES);
settings.add(FILTER_POLICY_IGNORE_CLUSTER_PRIVILEGES);
} }
/** /**
* Builds the predicate for a single policy filter. The predicate matches events * Builds the predicate for a single policy filter. The predicate matches events
* that will be ignored, aka filtered out, aka not logged. The event can be * that will be ignored, aka filtered out, aka not logged. The event can be
* filtered by the following fields : `user`, `realm`, `role` and `index`. * filtered by the following fields : `user`, `realm`, `role`, `index`, and
* (`index_privilege` or `cluster_privilege`).
* Predicates on each field are ANDed together to form the filter predicate of * Predicates on each field are ANDed together to form the filter predicate of
* the policy. * the policy.
*/ */
@ -1361,14 +1373,25 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
private final Predicate<String> ignoreRealmsPredicate; private final Predicate<String> ignoreRealmsPredicate;
private final Predicate<String> ignoreRolesPredicate; private final Predicate<String> ignoreRolesPredicate;
private final Predicate<String> ignoreIndicesPredicate; private final Predicate<String> ignoreIndicesPredicate;
private final Predicate<String> ignorePrivilegesPredicate; private final Predicate<String> ignoreIndexPrivilegesPredicate;
private final Predicate<String> ignoreClusterPrivilegesPredicate;
EventFilterPolicy(String name, Settings settings) { EventFilterPolicy(String name, Settings settings) {
this(name, parsePredicate(FILTER_POLICY_IGNORE_PRINCIPALS.getConcreteSettingForNamespace(name).get(settings)), this(name, parsePredicate(FILTER_POLICY_IGNORE_PRINCIPALS.getConcreteSettingForNamespace(name).get(settings)),
parsePredicate(FILTER_POLICY_IGNORE_REALMS.getConcreteSettingForNamespace(name).get(settings)), parsePredicate(FILTER_POLICY_IGNORE_REALMS.getConcreteSettingForNamespace(name).get(settings)),
parsePredicate(FILTER_POLICY_IGNORE_ROLES.getConcreteSettingForNamespace(name).get(settings)), parsePredicate(FILTER_POLICY_IGNORE_ROLES.getConcreteSettingForNamespace(name).get(settings)),
parsePredicate(FILTER_POLICY_IGNORE_INDICES.getConcreteSettingForNamespace(name).get(settings)), parsePredicate(FILTER_POLICY_IGNORE_INDICES.getConcreteSettingForNamespace(name).get(settings)),
parsePredicate(FILTER_POLICY_IGNORE_PRIVILEGES.getConcreteSettingForNamespace(name).get(settings))); parsePredicate(FILTER_POLICY_IGNORE_INDEX_PRIVILEGES.getConcreteSettingForNamespace(name).get(settings)),
parsePredicate(FILTER_POLICY_IGNORE_CLUSTER_PRIVILEGES.getConcreteSettingForNamespace(name).get(settings)));
if (FILTER_POLICY_IGNORE_INDEX_PRIVILEGES.getConcreteSettingForNamespace(name).exists(settings) &&
FILTER_POLICY_IGNORE_CLUSTER_PRIVILEGES.getConcreteSettingForNamespace(name).exists(settings)) {
final String message = String.format(
Locale.ROOT,
"Both Index and Cluster privilege ignore filters are set for policy [%s]. " +
"Please update your configuration settings and remove one of these filters to avoid ambiguity.", this.name);
throw new IllegalArgumentException(message);
}
} }
/** /**
@ -1378,39 +1401,45 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
*/ */
EventFilterPolicy(String name, Predicate<String> ignorePrincipalsPredicate, Predicate<String> ignoreRealmsPredicate, EventFilterPolicy(String name, Predicate<String> ignorePrincipalsPredicate, Predicate<String> ignoreRealmsPredicate,
Predicate<String> ignoreRolesPredicate, Predicate<String> ignoreIndicesPredicate, Predicate<String> ignoreRolesPredicate, Predicate<String> ignoreIndicesPredicate,
Predicate<String> ignoreActionsPredicate) { Predicate<String> ignoreIndexPrivilegesPredicate, Predicate<String> ignoreClusterPrivilegesPredicate) {
this.name = name; this.name = name;
// "null" values are "unexpected" and should not match any ignore policy // "null" values are "unexpected" and should not match any ignore policy
this.ignorePrincipalsPredicate = ignorePrincipalsPredicate; this.ignorePrincipalsPredicate = ignorePrincipalsPredicate;
this.ignoreRealmsPredicate = ignoreRealmsPredicate; this.ignoreRealmsPredicate = ignoreRealmsPredicate;
this.ignoreRolesPredicate = ignoreRolesPredicate; this.ignoreRolesPredicate = ignoreRolesPredicate;
this.ignoreIndicesPredicate = ignoreIndicesPredicate; this.ignoreIndicesPredicate = ignoreIndicesPredicate;
this.ignorePrivilegesPredicate = ignoreActionsPredicate; this.ignoreIndexPrivilegesPredicate = ignoreIndexPrivilegesPredicate;
this.ignoreClusterPrivilegesPredicate = ignoreClusterPrivilegesPredicate;
} }
private EventFilterPolicy changePrincipalsFilter(List<String> filtersList) { private EventFilterPolicy changePrincipalsFilter(List<String> filtersList) {
return new EventFilterPolicy(name, parsePredicate(filtersList), ignoreRealmsPredicate, ignoreRolesPredicate, return new EventFilterPolicy(name, parsePredicate(filtersList), ignoreRealmsPredicate, ignoreRolesPredicate,
ignoreIndicesPredicate, ignorePrivilegesPredicate); ignoreIndicesPredicate, ignoreIndexPrivilegesPredicate, ignoreClusterPrivilegesPredicate);
} }
private EventFilterPolicy changeRealmsFilter(List<String> filtersList) { private EventFilterPolicy changeRealmsFilter(List<String> filtersList) {
return new EventFilterPolicy(name, ignorePrincipalsPredicate, parsePredicate(filtersList), ignoreRolesPredicate, return new EventFilterPolicy(name, ignorePrincipalsPredicate, parsePredicate(filtersList), ignoreRolesPredicate,
ignoreIndicesPredicate, ignorePrivilegesPredicate); ignoreIndicesPredicate, ignoreIndexPrivilegesPredicate, ignoreClusterPrivilegesPredicate);
} }
private EventFilterPolicy changeRolesFilter(List<String> filtersList) { private EventFilterPolicy changeRolesFilter(List<String> filtersList) {
return new EventFilterPolicy(name, ignorePrincipalsPredicate, ignoreRealmsPredicate, parsePredicate(filtersList), return new EventFilterPolicy(name, ignorePrincipalsPredicate, ignoreRealmsPredicate, parsePredicate(filtersList),
ignoreIndicesPredicate, ignorePrivilegesPredicate); ignoreIndicesPredicate, ignoreIndexPrivilegesPredicate, ignoreClusterPrivilegesPredicate);
} }
private EventFilterPolicy changeIndicesFilter(List<String> filtersList) { private EventFilterPolicy changeIndicesFilter(List<String> filtersList) {
return new EventFilterPolicy(name, ignorePrincipalsPredicate, ignoreRealmsPredicate, ignoreRolesPredicate, return new EventFilterPolicy(name, ignorePrincipalsPredicate, ignoreRealmsPredicate, ignoreRolesPredicate,
parsePredicate(filtersList), ignorePrivilegesPredicate); parsePredicate(filtersList), ignoreIndexPrivilegesPredicate, ignoreClusterPrivilegesPredicate);
} }
private EventFilterPolicy changePrivilegesFilter(List<String> filtersList) { private EventFilterPolicy changeIndexPrivilegesFilter(List<String> filtersList) {
return new EventFilterPolicy(name, ignorePrincipalsPredicate, ignoreRealmsPredicate, ignoreRolesPredicate, return new EventFilterPolicy(name, ignorePrincipalsPredicate, ignoreRealmsPredicate, ignoreRolesPredicate,
ignoreIndicesPredicate, parsePredicate(filtersList)); ignoreIndicesPredicate, parsePredicate(filtersList), ignoreClusterPrivilegesPredicate);
}
private EventFilterPolicy changeClusterPrivilegesFilter(List<String> filtersList) {
return new EventFilterPolicy(name, ignorePrincipalsPredicate, ignoreRealmsPredicate, ignoreRolesPredicate,
ignoreIndicesPredicate, ignoreIndexPrivilegesPredicate, parsePredicate(filtersList));
} }
static Predicate<String> parsePredicate(List<String> l) { static Predicate<String> parsePredicate(List<String> l) {
@ -1430,14 +1459,16 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
return l.stream().map(f -> f.isEmpty() ? "//" : f).collect(Collectors.toList()); return l.stream().map(f -> f.isEmpty() ? "//" : f).collect(Collectors.toList());
} }
private boolean ignorePrivilegesPredicateTest(String action) { private boolean ignoreIndexPrivilegesPredicateTest(String action) {
Collection<String> privileges = null; if (ignoreIndexPrivilegesPredicate.test(action)) return true;
if (AuthorizationService.isIndexAction(action)) { Collection<String> privileges = IndexPrivilege.findPrivilegesThatGrant(action);
privileges = IndexPrivilege.findPrivilegesThatGrant(action); return privileges != null && privileges.stream().anyMatch((s) -> ignoreIndexPrivilegesPredicate.test(s));
} else if (ClusterPrivilegeResolver.isClusterAction(action)) {
privileges = ClusterPrivilegeResolver.findPrivilegesThatGrant(action, null, null);
} }
return privileges != null ? privileges.stream().anyMatch((s) -> ignorePrivilegesPredicate.test(s)) : false;
private boolean ignoreClusterPrivilegesPredicateTest(String action) {
if (ignoreClusterPrivilegesPredicate.test(action)) return true;
Collection<String> privileges = ClusterPrivilegeResolver.findPrivilegesThatGrant(action, null, null);
return privileges != null && privileges.stream().anyMatch((s) -> ignoreClusterPrivilegesPredicate.test(s));
} }
/** /**
@ -1448,8 +1479,8 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
Predicate<AuditEventMetaInfo> ignorePredicate() { Predicate<AuditEventMetaInfo> ignorePredicate() {
return eventInfo -> eventInfo.principal != null && ignorePrincipalsPredicate.test(eventInfo.principal) return eventInfo -> eventInfo.principal != null && ignorePrincipalsPredicate.test(eventInfo.principal)
&& eventInfo.realm != null && ignoreRealmsPredicate.test(eventInfo.realm) && eventInfo.realm != null && ignoreRealmsPredicate.test(eventInfo.realm)
&& eventInfo.action != null && (ignorePrivilegesPredicate.test(eventInfo.action) || && eventInfo.action != null && (ignoreIndexPrivilegesPredicateTest(eventInfo.action) &&
ignorePrivilegesPredicateTest(eventInfo.action)) ignoreClusterPrivilegesPredicateTest(eventInfo.action))
&& eventInfo.roles.get().allMatch(role -> role != null && ignoreRolesPredicate.test(role)) && eventInfo.roles.get().allMatch(role -> role != null && ignoreRolesPredicate.test(role))
&& eventInfo.indices.get().allMatch(index -> index != null && ignoreIndicesPredicate.test(index)); && eventInfo.indices.get().allMatch(index -> index != null && ignoreIndicesPredicate.test(index));
} }
@ -1457,8 +1488,8 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
@Override @Override
public String toString() { public String toString() {
return "[users]:" + ignorePrincipalsPredicate.toString() + "&[realms]:" + ignoreRealmsPredicate.toString() + "&[roles]:" return "[users]:" + ignorePrincipalsPredicate.toString() + "&[realms]:" + ignoreRealmsPredicate.toString() + "&[roles]:"
+ ignoreRolesPredicate.toString() + "&[indices]:" + ignoreIndicesPredicate.toString() + "&[actions]:" + ignoreRolesPredicate.toString() + "&[indices]:" + ignoreIndicesPredicate.toString() + "&[index privileges]:"
+ ignorePrivilegesPredicate.toString(); + ignoreIndexPrivilegesPredicate.toString() + "&[cluster privileges]:" + ignoreClusterPrivilegesPredicate.toString();
} }
} }

View file

@ -62,6 +62,8 @@ import java.util.stream.Collectors;
import static org.elasticsearch.xpack.security.audit.logfile.LoggingAuditTrail.PRINCIPAL_ROLES_FIELD_NAME; import static org.elasticsearch.xpack.security.audit.logfile.LoggingAuditTrail.PRINCIPAL_ROLES_FIELD_NAME;
import static org.elasticsearch.xpack.security.authc.ApiKeyServiceTests.Utils.createApiKeyAuthentication; import static org.elasticsearch.xpack.security.authc.ApiKeyServiceTests.Utils.createApiKeyAuthentication;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.hasToString;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@ -125,10 +127,17 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
final List<String> filteredIndices = randomNonEmptyListOfFilteredNames(); final List<String> filteredIndices = randomNonEmptyListOfFilteredNames();
settingsBuilder.putList("xpack.security.audit.logfile.events.ignore_filters.indicesPolicy.indices", filteredIndices); settingsBuilder.putList("xpack.security.audit.logfile.events.ignore_filters.indicesPolicy.indices", filteredIndices);
// filter by privileges // filter by privileges
final List<String> filteredActions = randomNonEmptyListOfFilteredActions(); final boolean clusterActionsFilter = randomBoolean();
final List<String> filteredActions = clusterActionsFilter? randomNonEmptyListOfFilteredClusterActions() :
randomNonEmptyListOfFilteredIndexActions();
final List<String> filteredPrivileges = randomNonEmptyListOfFilteredPrivileges(filteredActions); final List<String> filteredPrivileges = randomNonEmptyListOfFilteredPrivileges(filteredActions);
settingsBuilder.putList("xpack.security.audit.logfile.events.ignore_filters.privilegesPolicy.privileges", if (clusterActionsFilter) {
settingsBuilder.putList("xpack.security.audit.logfile.events.ignore_filters.privilegesPolicy.cluster_privileges",
randomBoolean() ? filteredPrivileges : filteredActions); randomBoolean() ? filteredPrivileges : filteredActions);
} else {
settingsBuilder.putList("xpack.security.audit.logfile.events.ignore_filters.privilegesPolicy.index_privileges",
randomBoolean() ? filteredPrivileges : filteredActions);
}
final LoggingAuditTrail auditTrail = new LoggingAuditTrail(settingsBuilder.build(), clusterService, logger, threadContext); final LoggingAuditTrail auditTrail = new LoggingAuditTrail(settingsBuilder.build(), clusterService, logger, threadContext);
@ -216,10 +225,17 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
final List<String> filteredIndices = randomNonEmptyListOfFilteredNames(); final List<String> filteredIndices = randomNonEmptyListOfFilteredNames();
settingsBuilder.putList("xpack.security.audit.logfile.events.ignore_filters.completeFilterPolicy.indices", filteredIndices); settingsBuilder.putList("xpack.security.audit.logfile.events.ignore_filters.completeFilterPolicy.indices", filteredIndices);
// filter by privileges // filter by privileges
final List<String> filteredActions = randomNonEmptyListOfFilteredActions(); final boolean clusterActionsFilter = randomBoolean();
final List<String> filteredActions = clusterActionsFilter? randomNonEmptyListOfFilteredClusterActions() :
randomNonEmptyListOfFilteredIndexActions();
final List<String> filteredPrivileges = randomNonEmptyListOfFilteredPrivileges(filteredActions); final List<String> filteredPrivileges = randomNonEmptyListOfFilteredPrivileges(filteredActions);
settingsBuilder.putList("xpack.security.audit.logfile.events.ignore_filters.completeFilterPolicy.privileges", if (clusterActionsFilter) {
settingsBuilder.putList("xpack.security.audit.logfile.events.ignore_filters.completeFilterPolicy.cluster_privileges",
randomBoolean() ? filteredPrivileges : filteredActions); randomBoolean() ? filteredPrivileges : filteredActions);
} else {
settingsBuilder.putList("xpack.security.audit.logfile.events.ignore_filters.completeFilterPolicy.index_privileges",
randomBoolean() ? filteredPrivileges : filteredActions);
}
final LoggingAuditTrail auditTrail = new LoggingAuditTrail(settingsBuilder.build(), clusterService, logger, threadContext); final LoggingAuditTrail auditTrail = new LoggingAuditTrail(settingsBuilder.build(), clusterService, logger, threadContext);
@ -342,10 +358,17 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
settingsBuilder.putList("xpack.security.audit.logfile.events.ignore_filters.completeFilterPolicy.indices", filteredIndices); settingsBuilder.putList("xpack.security.audit.logfile.events.ignore_filters.completeFilterPolicy.indices", filteredIndices);
filteredIndices.remove(""); filteredIndices.remove("");
// filter by privileges // filter by privileges
final List<String> filteredActions = randomNonEmptyListOfFilteredActions(); final boolean clusterActionsFilter = randomBoolean();
final List<String> filteredActions = clusterActionsFilter? randomNonEmptyListOfFilteredClusterActions() :
randomNonEmptyListOfFilteredIndexActions();
final List<String> filteredPrivileges = randomNonEmptyListOfFilteredPrivileges(filteredActions); final List<String> filteredPrivileges = randomNonEmptyListOfFilteredPrivileges(filteredActions);
settingsBuilder.putList("xpack.security.audit.logfile.events.ignore_filters.completeFilterPolicy.privileges", if (clusterActionsFilter) {
settingsBuilder.putList("xpack.security.audit.logfile.events.ignore_filters.completeFilterPolicy.cluster_privileges",
randomBoolean() ? filteredPrivileges : filteredActions); randomBoolean() ? filteredPrivileges : filteredActions);
} else {
settingsBuilder.putList("xpack.security.audit.logfile.events.ignore_filters.completeFilterPolicy.index_privileges",
randomBoolean() ? filteredPrivileges : filteredActions);
}
final LoggingAuditTrail auditTrail = new LoggingAuditTrail(settingsBuilder.build(), clusterService, logger, threadContext); final LoggingAuditTrail auditTrail = new LoggingAuditTrail(settingsBuilder.build(), clusterService, logger, threadContext);
@ -1885,6 +1908,21 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
threadContext.stashContext(); threadContext.stashContext();
} }
public void testBothClusterAndIndexFiltersExist() throws Exception {
final Logger logger = CapturingLogger.newCapturingLogger(Level.INFO, null);
final ThreadContext threadContext = new ThreadContext(Settings.EMPTY);
// create complete filter policy
final Settings.Builder settingsBuilder = Settings.builder().put(settings);
settingsBuilder.putList("xpack.security.audit.logfile.events.ignore_filters.privilegesPolicy.cluster_privileges",
"monitor");
settingsBuilder.putList("xpack.security.audit.logfile.events.ignore_filters.privilegesPolicy.index_privileges",
"read");
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
() -> new LoggingAuditTrail(settingsBuilder.build(), clusterService, logger, threadContext));
assertThat(e, hasToString(containsString("Both Index and Cluster privilege ignore filters are set for policy " +
"[privilegesPolicy]. Please update your configuration settings and remove one of these filters to avoid ambiguity.")));
}
private <T> List<T> randomListFromLengthBetween(List<T> l, int min, int max) { private <T> List<T> randomListFromLengthBetween(List<T> l, int min, int max) {
assert (min >= 0) && (min <= max) && (max <= l.size()); assert (min >= 0) && (min <= max) && (max <= l.size());
final int len = randomIntBetween(min, max); final int len = randomIntBetween(min, max);
@ -1919,7 +1957,7 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
return filtered; return filtered;
} }
private List<String> randomNonEmptyListOfFilteredActions() { private List<String> randomNonEmptyListOfFilteredIndexActions() {
final List<String> filtered = new ArrayList<>(4); final List<String> filtered = new ArrayList<>(4);
final String[] actionPatterns = { final String[] actionPatterns = {
"internal:transport/proxy/indices:*", "internal:transport/proxy/indices:*",
@ -1940,11 +1978,24 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
"indices:admin/flush*", "indices:admin/flush*",
"indices:admin/synced_flush", "indices:admin/synced_flush",
"indices:admin/forcemerge*", "indices:admin/forcemerge*",
"indices:admin/index_template/*",
"indices:admin/data_stream/*",
"indices:admin/template/*",};
Random random = random();
for (int i = 0; i < randomIntBetween(1, 4); i++) {
Object name = actionPatterns[random.nextInt(actionPatterns.length)];
filtered.add((String)name);
}
return filtered;
}
private List<String> randomNonEmptyListOfFilteredClusterActions() {
final List<String> filtered = new ArrayList<>(4);
final String[] actionPatterns = {
"cluster:admin/xpack/security/*", "cluster:admin/xpack/security/*",
"cluster:admin/xpack/security/saml/*", "cluster:admin/xpack/security/saml/*",
"cluster:admin/xpack/security/oidc/*", "cluster:admin/xpack/security/oidc/*",
"cluster:admin/xpack/security/token/*", "cluster:admin/xpack/security/token/*",
"cluster:admin/xpack/security/api_key/*",
"cluster:monitor/*", "cluster:monitor/*",
"cluster:monitor/xpack/ml/*", "cluster:monitor/xpack/ml/*",
"cluster:monitor/text_structure/*", "cluster:monitor/text_structure/*",
@ -1952,8 +2003,6 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
"cluster:monitor/xpack/watcher/*", "cluster:monitor/xpack/watcher/*",
"cluster:monitor/xpack/rollup/*", "cluster:monitor/xpack/rollup/*",
"cluster:*", "cluster:*",
"indices:admin/index_template/*",
"indices:admin/data_stream/*",
"cluster:admin/xpack/ml/*", "cluster:admin/xpack/ml/*",
"cluster:admin/data_frame/*", "cluster:admin/data_frame/*",
"cluster:monitor/data_frame/*", "cluster:monitor/data_frame/*",
@ -1962,7 +2011,6 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
"cluster:admin/xpack/watcher/*", "cluster:admin/xpack/watcher/*",
"cluster:monitor/nodes/liveness", "cluster:monitor/nodes/liveness",
"cluster:monitor/state", "cluster:monitor/state",
"indices:admin/template/*",
"cluster:admin/component_template/*", "cluster:admin/component_template/*",
"cluster:admin/ingest/pipeline/*", "cluster:admin/ingest/pipeline/*",
"cluster:admin/xpack/rollup/*", "cluster:admin/xpack/rollup/*",

View file

@ -272,8 +272,8 @@ public class LoggingAuditTrailTests extends ESTestCase {
LoggingAuditTrail.INCLUDE_EVENT_SETTINGS, LoggingAuditTrail.EXCLUDE_EVENT_SETTINGS, LoggingAuditTrail.INCLUDE_EVENT_SETTINGS, LoggingAuditTrail.EXCLUDE_EVENT_SETTINGS,
LoggingAuditTrail.INCLUDE_REQUEST_BODY, LoggingAuditTrail.FILTER_POLICY_IGNORE_PRINCIPALS, LoggingAuditTrail.INCLUDE_REQUEST_BODY, LoggingAuditTrail.FILTER_POLICY_IGNORE_PRINCIPALS,
LoggingAuditTrail.FILTER_POLICY_IGNORE_REALMS, LoggingAuditTrail.FILTER_POLICY_IGNORE_ROLES, LoggingAuditTrail.FILTER_POLICY_IGNORE_REALMS, LoggingAuditTrail.FILTER_POLICY_IGNORE_ROLES,
LoggingAuditTrail.FILTER_POLICY_IGNORE_INDICES, LoggingAuditTrail.FILTER_POLICY_IGNORE_PRIVILEGES, LoggingAuditTrail.FILTER_POLICY_IGNORE_INDICES, LoggingAuditTrail.FILTER_POLICY_IGNORE_INDEX_PRIVILEGES,
Loggers.LOG_LEVEL_SETTING)); LoggingAuditTrail.FILTER_POLICY_IGNORE_CLUSTER_PRIVILEGES, Loggers.LOG_LEVEL_SETTING));
when(clusterService.getClusterSettings()).thenReturn(clusterSettings); when(clusterService.getClusterSettings()).thenReturn(clusterSettings);
commonFields = new LoggingAuditTrail.EntryCommonFields(settings, localNode).commonFields; commonFields = new LoggingAuditTrail.EntryCommonFields(settings, localNode).commonFields;
threadContext = new ThreadContext(Settings.EMPTY); threadContext = new ThreadContext(Settings.EMPTY);
@ -345,11 +345,11 @@ public class LoggingAuditTrailTests extends ESTestCase {
Settings settings5 = Settings.builder() Settings settings5 = Settings.builder()
.putList(prefix + "ignore_filters.filter2.users", Arrays.asList("tom", "cruise")) .putList(prefix + "ignore_filters.filter2.users", Arrays.asList("tom", "cruise"))
.putList(prefix + "ignore_filters.filter2.privileges", Arrays.asList("read", "/foo")).build(); .putList(prefix + "ignore_filters.filter2.index_privileges", Arrays.asList("read", "/foo")).build();
assertThat(LoggingAuditTrail.FILTER_POLICY_IGNORE_PRINCIPALS.getConcreteSettingForNamespace("filter2").get(settings5), assertThat(LoggingAuditTrail.FILTER_POLICY_IGNORE_PRINCIPALS.getConcreteSettingForNamespace("filter2").get(settings5),
containsInAnyOrder("tom", "cruise")); containsInAnyOrder("tom", "cruise"));
e = expectThrows(IllegalArgumentException.class, e = expectThrows(IllegalArgumentException.class,
() -> LoggingAuditTrail.FILTER_POLICY_IGNORE_PRIVILEGES.getConcreteSettingForNamespace("filter2").get(settings5)); () -> LoggingAuditTrail.FILTER_POLICY_IGNORE_INDEX_PRIVILEGES.getConcreteSettingForNamespace("filter2").get(settings5));
assertThat(e, hasToString(containsString("invalid pattern [/foo]"))); assertThat(e, hasToString(containsString("invalid pattern [/foo]")));
} }