mirror of
https://github.com/elastic/elasticsearch.git
synced 2025-04-25 15:47:23 -04:00
Support audit ignore policy by index privileges
Adding new audit ignore policy - privileges For example, following policy will filter out all events, which actions required privilege is either "read" or "delete": xpack.security.audit.logfile.events.ignore_filters: example: privileges: ["read", "delete"] Resolve: #60877 Related: #10836 Related: #37148
This commit is contained in:
parent
665749c6e9
commit
a918da10ff
4 changed files with 60 additions and 16 deletions
|
@ -153,8 +153,8 @@ not print audit events for users in these realms.
|
|||
// tag::xpack-sa-lf-events-ignore-privileges-tag[]
|
||||
`xpack.security.audit.logfile.events.ignore_filters.<policy_name>.privileges`::
|
||||
(<<dynamic-cluster-setting,Dynamic>>)
|
||||
A list of index privileges. The specified policy will
|
||||
not print audit events for actions with these minimal required privileges.
|
||||
A list of privileges. The specified policy will not print audit events for actions
|
||||
requiring any of these privileges.
|
||||
// end::xpack-sa-lf-events-ignore-privileges-tag[]
|
||||
|
||||
[[xpack-sa-lf-events-ignore-roles]]
|
||||
|
|
|
@ -70,6 +70,7 @@ import org.elasticsearch.xpack.core.security.authc.Authentication;
|
|||
import org.elasticsearch.xpack.core.security.authc.AuthenticationToken;
|
||||
import org.elasticsearch.xpack.core.security.authz.AuthorizationEngine.AuthorizationInfo;
|
||||
import org.elasticsearch.xpack.core.security.authz.RoleDescriptor;
|
||||
import org.elasticsearch.xpack.core.security.authz.privilege.ClusterPrivilegeResolver;
|
||||
import org.elasticsearch.xpack.core.security.authz.privilege.ConfigurableClusterPrivileges;
|
||||
import org.elasticsearch.xpack.core.security.authz.privilege.IndexPrivilege;
|
||||
import org.elasticsearch.xpack.core.security.support.Automatons;
|
||||
|
@ -78,6 +79,7 @@ import org.elasticsearch.xpack.security.Security;
|
|||
import org.elasticsearch.xpack.security.audit.AuditLevel;
|
||||
import org.elasticsearch.xpack.security.audit.AuditTrail;
|
||||
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.transport.filter.IPFilter;
|
||||
import org.elasticsearch.xpack.security.transport.filter.SecurityIpFilterRule;
|
||||
|
@ -1428,20 +1430,28 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
|
|||
return l.stream().map(f -> f.isEmpty() ? "//" : f).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private boolean ignorePrivilegesPredicateTest(String action) {
|
||||
Collection<String> privileges = null;
|
||||
if (AuthorizationService.isIndexAction(action)) {
|
||||
privileges = IndexPrivilege.findPrivilegesThatGrant(action);
|
||||
} else if (ClusterPrivilegeResolver.isClusterAction(action)) {
|
||||
privileges = ClusterPrivilegeResolver.findPrivilegesThatGrant(action, null, null);
|
||||
}
|
||||
return privileges != null ? privileges.stream().anyMatch((s) -> ignorePrivilegesPredicate.test(s)) : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* ANDs the predicates of this filter policy. The `indices` and `roles` fields
|
||||
* of an audit event are multi-valued and all values should match the filter
|
||||
* predicate of the corresponding field.
|
||||
*/
|
||||
Predicate<AuditEventMetaInfo> ignorePredicate() {
|
||||
return eventInfo -> {
|
||||
final Collection<String> privileges = IndexPrivilege.findPrivilegesThatGrant(eventInfo.action);
|
||||
return eventInfo.principal != null && ignorePrincipalsPredicate.test(eventInfo.principal)
|
||||
return eventInfo -> eventInfo.principal != null && ignorePrincipalsPredicate.test(eventInfo.principal)
|
||||
&& eventInfo.realm != null && ignoreRealmsPredicate.test(eventInfo.realm)
|
||||
&& eventInfo.action != null && ignorePrivilegesPredicate.test(privileges.size() > 0 ? privileges.iterator().next() : "")
|
||||
&& eventInfo.action != null && (ignorePrivilegesPredicate.test(eventInfo.action) ||
|
||||
ignorePrivilegesPredicateTest(eventInfo.action))
|
||||
&& eventInfo.roles.get().allMatch(role -> role != null && ignoreRolesPredicate.test(role))
|
||||
&& eventInfo.indices.get().allMatch(index -> index != null && ignoreIndicesPredicate.test(index));
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -572,7 +572,7 @@ public class AuthorizationService {
|
|||
return new IllegalArgumentException(message);
|
||||
}
|
||||
|
||||
private static boolean isIndexAction(String action) {
|
||||
public static boolean isIndexAction(String action) {
|
||||
return IndexPrivilege.ACTION_MATCHER.test(action);
|
||||
}
|
||||
|
||||
|
|
|
@ -31,12 +31,15 @@ import org.elasticsearch.xpack.core.security.authc.Authentication;
|
|||
import org.elasticsearch.xpack.core.security.authc.Authentication.RealmRef;
|
||||
import org.elasticsearch.xpack.core.security.authc.AuthenticationToken;
|
||||
import org.elasticsearch.xpack.core.security.authz.AuthorizationEngine.AuthorizationInfo;
|
||||
import org.elasticsearch.xpack.core.security.authz.privilege.ClusterPrivilegeResolver;
|
||||
import org.elasticsearch.xpack.core.security.authz.privilege.IndexPrivilege;
|
||||
import org.elasticsearch.xpack.core.security.user.SystemUser;
|
||||
import org.elasticsearch.xpack.core.security.user.User;
|
||||
import org.elasticsearch.xpack.security.audit.logfile.LoggingAuditTrail.AuditEventMetaInfo;
|
||||
import org.elasticsearch.xpack.security.audit.logfile.LoggingAuditTrailTests.MockRequest;
|
||||
import org.elasticsearch.xpack.security.audit.logfile.LoggingAuditTrailTests.RestContent;
|
||||
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.support.CacheInvalidatorRegistry;
|
||||
import org.elasticsearch.xpack.security.support.SecurityIndexManager;
|
||||
|
@ -57,7 +60,6 @@ import java.util.Optional;
|
|||
import java.util.Random;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.elasticsearch.xpack.core.security.authz.privilege.IndexPrivilege.findPrivilegesThatGrant;
|
||||
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.hamcrest.Matchers.is;
|
||||
|
@ -126,7 +128,7 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
|
|||
final List<String> filteredActions = randomNonEmptyListOfFilteredActions();
|
||||
final List<String> filteredPrivileges = randomNonEmptyListOfFilteredPrivileges(filteredActions);
|
||||
settingsBuilder.putList("xpack.security.audit.logfile.events.ignore_filters.privilegesPolicy.privileges",
|
||||
filteredPrivileges);
|
||||
randomBoolean() ? filteredPrivileges : filteredActions);
|
||||
|
||||
final LoggingAuditTrail auditTrail = new LoggingAuditTrail(settingsBuilder.build(), clusterService, logger, threadContext);
|
||||
|
||||
|
@ -217,7 +219,7 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
|
|||
final List<String> filteredActions = randomNonEmptyListOfFilteredActions();
|
||||
final List<String> filteredPrivileges = randomNonEmptyListOfFilteredPrivileges(filteredActions);
|
||||
settingsBuilder.putList("xpack.security.audit.logfile.events.ignore_filters.completeFilterPolicy.privileges",
|
||||
filteredPrivileges);
|
||||
randomBoolean() ? filteredPrivileges : filteredActions);
|
||||
|
||||
final LoggingAuditTrail auditTrail = new LoggingAuditTrail(settingsBuilder.build(), clusterService, logger, threadContext);
|
||||
|
||||
|
@ -343,7 +345,7 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
|
|||
final List<String> filteredActions = randomNonEmptyListOfFilteredActions();
|
||||
final List<String> filteredPrivileges = randomNonEmptyListOfFilteredPrivileges(filteredActions);
|
||||
settingsBuilder.putList("xpack.security.audit.logfile.events.ignore_filters.completeFilterPolicy.privileges",
|
||||
filteredPrivileges);
|
||||
randomBoolean() ? filteredPrivileges : filteredActions);
|
||||
|
||||
final LoggingAuditTrail auditTrail = new LoggingAuditTrail(settingsBuilder.build(), clusterService, logger, threadContext);
|
||||
|
||||
|
@ -1937,7 +1939,37 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
|
|||
"indices:admin/refresh*",
|
||||
"indices:admin/flush*",
|
||||
"indices:admin/synced_flush",
|
||||
"indices:admin/forcemerge*"};
|
||||
"indices:admin/forcemerge*",
|
||||
"cluster:admin/xpack/security/*",
|
||||
"cluster:admin/xpack/security/saml/*",
|
||||
"cluster:admin/xpack/security/oidc/*",
|
||||
"cluster:admin/xpack/security/token/*",
|
||||
"cluster:admin/xpack/security/api_key/*",
|
||||
"cluster:monitor/*",
|
||||
"cluster:monitor/xpack/ml/*",
|
||||
"cluster:monitor/text_structure/*",
|
||||
"cluster:monitor/data_frame/*",
|
||||
"cluster:monitor/xpack/watcher/*",
|
||||
"cluster:monitor/xpack/rollup/*",
|
||||
"cluster:*",
|
||||
"indices:admin/index_template/*",
|
||||
"indices:admin/data_stream/*",
|
||||
"cluster:admin/xpack/ml/*",
|
||||
"cluster:admin/data_frame/*",
|
||||
"cluster:monitor/data_frame/*",
|
||||
"cluster:monitor/transform/*",
|
||||
"cluster:admin/transform/*",
|
||||
"cluster:admin/xpack/watcher/*",
|
||||
"cluster:monitor/nodes/liveness",
|
||||
"cluster:monitor/state",
|
||||
"indices:admin/template/*",
|
||||
"cluster:admin/component_template/*",
|
||||
"cluster:admin/ingest/pipeline/*",
|
||||
"cluster:admin/xpack/rollup/*",
|
||||
"cluster:admin/xpack/ccr/*",
|
||||
"cluster:admin/ilm/*",
|
||||
"cluster:admin/slm/*",
|
||||
"cluster:admin/xpack/enrich/*"};
|
||||
Random random = random();
|
||||
for (int i = 0; i < randomIntBetween(1, 4); i++) {
|
||||
Object name = actionPatterns[random.nextInt(actionPatterns.length)];
|
||||
|
@ -1947,11 +1979,13 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
|
|||
}
|
||||
|
||||
private List<String> randomNonEmptyListOfFilteredPrivileges(List<String> listOfActions) {
|
||||
final List<String> filtered = new ArrayList<>(listOfActions.size());
|
||||
final List<String> filtered = new ArrayList<>();
|
||||
for (int i = 0; i < listOfActions.size(); i++) {
|
||||
Collection<String> privileges = findPrivilegesThatGrant(listOfActions.get(i));
|
||||
Collection<String> privileges = AuthorizationService.isIndexAction(listOfActions.get(i)) ?
|
||||
IndexPrivilege.findPrivilegesThatGrant(listOfActions.get(i)) :
|
||||
ClusterPrivilegeResolver.findPrivilegesThatGrant(listOfActions.get(i), null, null);
|
||||
assertNotNull(privileges);
|
||||
filtered.add(privileges.iterator().next());
|
||||
filtered.addAll(privileges);
|
||||
}
|
||||
return filtered;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue