Update the audit logfile list of system users (#55578)

Out of the box "access granted" audit events are not logged
for system users. The list of system users was stale and included
only the _system and _xpack users. This commit expands this list
with _xpack_security and _async_search, effectively reducing the
auditing noise by not logging the audit events of these system
users out of the box.

Closes #37924
This commit is contained in:
Albert Zaharovits 2020-04-22 21:59:31 +03:00 committed by GitHub
parent c370b83bd7
commit 82ed0ab420
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 80 additions and 7 deletions

View File

@ -210,6 +210,10 @@ public class User implements ToXContentObject {
output.writeBoolean(false); // last user written, regardless of bwc, does not have an inner user
}
public static boolean isInternal(User user) {
return SystemUser.is(user) || XPackUser.is(user) || XPackSecurityUser.is(user) || AsyncSearchUser.is(user);
}
/** Write just the given {@link User}, but not the inner {@link #authenticatedUser}. */
private static void writeUser(User user, StreamOutput output) throws IOException {
output.writeBoolean(false); // not a system user

View File

@ -35,9 +35,7 @@ import org.elasticsearch.transport.TransportRequest;
import org.elasticsearch.xpack.core.security.authc.Authentication;
import org.elasticsearch.xpack.core.security.authc.AuthenticationToken;
import org.elasticsearch.xpack.core.security.support.Automatons;
import org.elasticsearch.xpack.core.security.user.SystemUser;
import org.elasticsearch.xpack.core.security.user.User;
import org.elasticsearch.xpack.core.security.user.XPackUser;
import org.elasticsearch.xpack.security.Security;
import org.elasticsearch.xpack.security.audit.AuditLevel;
import org.elasticsearch.xpack.security.audit.AuditTrail;
@ -446,7 +444,7 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
public void accessGranted(String requestId, Authentication authentication, String action, TransportRequest msg,
AuthorizationInfo authorizationInfo) {
final User user = authentication.getUser();
final boolean isSystem = SystemUser.is(user) || XPackUser.is(user);
final boolean isSystem = User.isInternal(user);
if ((isSystem && events.contains(SYSTEM_ACCESS_GRANTED)) || ((isSystem == false) && events.contains(ACCESS_GRANTED))) {
final Optional<String[]> indices = indices(msg);
if (eventFilterPolicyRegistry.ignorePredicate().test(new AuditEventMetaInfo(Optional.of(user),
@ -475,8 +473,7 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
assert eventType == ACCESS_DENIED || eventType == AuditLevel.ACCESS_GRANTED || eventType == SYSTEM_ACCESS_GRANTED;
final String[] indices = index == null ? null : new String[] { index };
final User user = authentication.getUser();
final boolean isSystem = SystemUser.is(user) || XPackUser.is(user);
if (isSystem && eventType == ACCESS_GRANTED) {
if (User.isInternal(user) && eventType == ACCESS_GRANTED) {
eventType = SYSTEM_ACCESS_GRANTED;
}
if (events.contains(eventType)) {

View File

@ -9,6 +9,7 @@ import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.layout.PatternLayout;
import org.elasticsearch.action.IndicesRequest;
import org.elasticsearch.action.bulk.BulkItemRequest;
import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.cluster.node.DiscoveryNode;
import org.elasticsearch.cluster.service.ClusterService;
@ -37,8 +38,12 @@ import org.elasticsearch.xpack.core.security.audit.logfile.CapturingLogger;
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.user.AsyncSearchUser;
import org.elasticsearch.xpack.core.security.user.SystemUser;
import org.elasticsearch.xpack.core.security.user.User;
import org.elasticsearch.xpack.core.security.user.XPackSecurityUser;
import org.elasticsearch.xpack.core.security.user.XPackUser;
import org.elasticsearch.xpack.security.audit.AuditLevel;
import org.elasticsearch.xpack.security.audit.AuditTrail;
import org.elasticsearch.xpack.security.audit.AuditUtil;
import org.elasticsearch.xpack.core.security.authz.AuthorizationEngine.AuthorizationInfo;
@ -571,11 +576,78 @@ public class LoggingAuditTrailTests extends ESTestCase {
assertEmptyLog(logger);
}
public void testSystemAccessGranted() throws Exception {
final TransportRequest request = randomBoolean() ? new MockRequest(threadContext) : new MockIndicesRequest(threadContext);
final String[] expectedRoles = randomArray(0, 4, String[]::new, () -> randomBoolean() ? null : randomAlphaOfLengthBetween(1, 4));
final AuthorizationInfo authorizationInfo = () -> Collections.singletonMap(PRINCIPAL_ROLES_FIELD_NAME, expectedRoles);
final User systemUser = randomFrom(SystemUser.INSTANCE, XPackUser.INSTANCE, XPackSecurityUser.INSTANCE, AsyncSearchUser.INSTANCE);
final Authentication authentication = new Authentication(systemUser, new RealmRef("_reserved", "test", "foo"), null);
final String requestId = randomRequestId();
auditTrail.accessGranted(requestId, authentication, "_action", request, authorizationInfo);
// system user
assertEmptyLog(logger);
auditTrail.explicitIndexAccessEvent(requestId, randomFrom(AuditLevel.ACCESS_GRANTED, AuditLevel.SYSTEM_ACCESS_GRANTED),
authentication, "_action", randomFrom(randomAlphaOfLengthBetween(1, 4), null),
BulkItemRequest.class.getName(),
request.remoteAddress(),
authorizationInfo);
// system user
assertEmptyLog(logger);
// enable system user for access granted events
settings = Settings.builder()
.put(settings)
.put("xpack.security.audit.logfile.events.include", "system_access_granted")
.build();
auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext);
auditTrail.accessGranted(requestId, authentication, "_action", request, authorizationInfo);
MapBuilder<String, String> checkedFields = new MapBuilder<>(commonFields);
MapBuilder<String, String[]> checkedArrayFields = new MapBuilder<>();
checkedFields.put(LoggingAuditTrail.EVENT_TYPE_FIELD_NAME, LoggingAuditTrail.TRANSPORT_ORIGIN_FIELD_VALUE)
.put(LoggingAuditTrail.EVENT_ACTION_FIELD_NAME, "access_granted")
.put(LoggingAuditTrail.ACTION_FIELD_NAME, "_action")
.put(LoggingAuditTrail.REQUEST_NAME_FIELD_NAME, request.getClass().getSimpleName())
.put(LoggingAuditTrail.REQUEST_ID_FIELD_NAME, requestId);
checkedArrayFields.put(PRINCIPAL_ROLES_FIELD_NAME, (String[]) authorizationInfo.asMap().get(PRINCIPAL_ROLES_FIELD_NAME));
subject(authentication, checkedFields);
restOrTransportOrigin(request, threadContext, checkedFields);
indicesRequest(request, checkedFields, checkedArrayFields);
opaqueId(threadContext, checkedFields);
forwardedFor(threadContext, checkedFields);
assertMsg(logger, checkedFields.immutableMap(), checkedArrayFields.immutableMap());
clearLog();
String index = randomFrom(randomAlphaOfLengthBetween(1, 4), null);
auditTrail.explicitIndexAccessEvent(requestId, randomFrom(AuditLevel.ACCESS_GRANTED, AuditLevel.SYSTEM_ACCESS_GRANTED),
authentication, "_action", index, BulkItemRequest.class.getName(), request.remoteAddress(), authorizationInfo);
checkedFields = new MapBuilder<>(commonFields);
checkedArrayFields = new MapBuilder<>();
checkedFields.put(LoggingAuditTrail.EVENT_TYPE_FIELD_NAME, LoggingAuditTrail.TRANSPORT_ORIGIN_FIELD_VALUE)
.put(LoggingAuditTrail.EVENT_ACTION_FIELD_NAME, "access_granted")
.put(LoggingAuditTrail.ACTION_FIELD_NAME, "_action")
.put(LoggingAuditTrail.REQUEST_NAME_FIELD_NAME, BulkItemRequest.class.getName())
.put(LoggingAuditTrail.REQUEST_ID_FIELD_NAME, requestId);
checkedArrayFields.put(PRINCIPAL_ROLES_FIELD_NAME, (String[]) authorizationInfo.asMap().get(PRINCIPAL_ROLES_FIELD_NAME));
subject(authentication, checkedFields);
restOrTransportOrigin(request, threadContext, checkedFields);
opaqueId(threadContext, checkedFields);
forwardedFor(threadContext, checkedFields);
if (index != null) {
checkedArrayFields.put(LoggingAuditTrail.INDICES_FIELD_NAME, new String[]{index});
}
assertMsg(logger, checkedFields.immutableMap(), checkedArrayFields.immutableMap());
}
public void testAccessGrantedInternalSystemAction() throws Exception {
final TransportRequest request = randomBoolean() ? new MockRequest(threadContext) : new MockIndicesRequest(threadContext);
final String[] expectedRoles = randomArray(0, 4, String[]::new, () -> randomBoolean() ? null : randomAlphaOfLengthBetween(1, 4));
final AuthorizationInfo authorizationInfo = () -> Collections.singletonMap(PRINCIPAL_ROLES_FIELD_NAME, expectedRoles);
final Authentication authentication = new Authentication(SystemUser.INSTANCE, new RealmRef("_reserved", "test", "foo"), null);
final User systemUser = randomFrom(SystemUser.INSTANCE, XPackUser.INSTANCE, XPackSecurityUser.INSTANCE, AsyncSearchUser.INSTANCE);
final Authentication authentication = new Authentication(systemUser, new RealmRef("_reserved", "test", "foo"), null);
final String requestId = randomRequestId();
auditTrail.accessGranted(requestId, authentication, "internal:_action", request, authorizationInfo);
assertEmptyLog(logger);
@ -591,7 +663,7 @@ public class LoggingAuditTrailTests extends ESTestCase {
final MapBuilder<String, String[]> checkedArrayFields = new MapBuilder<>();
checkedFields.put(LoggingAuditTrail.EVENT_TYPE_FIELD_NAME, LoggingAuditTrail.TRANSPORT_ORIGIN_FIELD_VALUE)
.put(LoggingAuditTrail.EVENT_ACTION_FIELD_NAME, "access_granted")
.put(LoggingAuditTrail.PRINCIPAL_FIELD_NAME, SystemUser.INSTANCE.principal())
.put(LoggingAuditTrail.PRINCIPAL_FIELD_NAME, systemUser.principal())
.put(LoggingAuditTrail.PRINCIPAL_REALM_FIELD_NAME, "_reserved")
.put(LoggingAuditTrail.ACTION_FIELD_NAME, "internal:_action")
.put(LoggingAuditTrail.REQUEST_NAME_FIELD_NAME, request.getClass().getSimpleName())