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:
parent
c370b83bd7
commit
82ed0ab420
|
@ -210,6 +210,10 @@ public class User implements ToXContentObject {
|
||||||
output.writeBoolean(false); // last user written, regardless of bwc, does not have an inner user
|
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}. */
|
/** Write just the given {@link User}, but not the inner {@link #authenticatedUser}. */
|
||||||
private static void writeUser(User user, StreamOutput output) throws IOException {
|
private static void writeUser(User user, StreamOutput output) throws IOException {
|
||||||
output.writeBoolean(false); // not a system user
|
output.writeBoolean(false); // not a system user
|
||||||
|
|
|
@ -35,9 +35,7 @@ import org.elasticsearch.transport.TransportRequest;
|
||||||
import org.elasticsearch.xpack.core.security.authc.Authentication;
|
import org.elasticsearch.xpack.core.security.authc.Authentication;
|
||||||
import org.elasticsearch.xpack.core.security.authc.AuthenticationToken;
|
import org.elasticsearch.xpack.core.security.authc.AuthenticationToken;
|
||||||
import org.elasticsearch.xpack.core.security.support.Automatons;
|
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.User;
|
||||||
import org.elasticsearch.xpack.core.security.user.XPackUser;
|
|
||||||
import org.elasticsearch.xpack.security.Security;
|
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;
|
||||||
|
@ -446,7 +444,7 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
|
||||||
public void accessGranted(String requestId, Authentication authentication, String action, TransportRequest msg,
|
public void accessGranted(String requestId, Authentication authentication, String action, TransportRequest msg,
|
||||||
AuthorizationInfo authorizationInfo) {
|
AuthorizationInfo authorizationInfo) {
|
||||||
final User user = authentication.getUser();
|
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))) {
|
if ((isSystem && events.contains(SYSTEM_ACCESS_GRANTED)) || ((isSystem == false) && events.contains(ACCESS_GRANTED))) {
|
||||||
final Optional<String[]> indices = indices(msg);
|
final Optional<String[]> indices = indices(msg);
|
||||||
if (eventFilterPolicyRegistry.ignorePredicate().test(new AuditEventMetaInfo(Optional.of(user),
|
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;
|
assert eventType == ACCESS_DENIED || eventType == AuditLevel.ACCESS_GRANTED || eventType == SYSTEM_ACCESS_GRANTED;
|
||||||
final String[] indices = index == null ? null : new String[] { index };
|
final String[] indices = index == null ? null : new String[] { index };
|
||||||
final User user = authentication.getUser();
|
final User user = authentication.getUser();
|
||||||
final boolean isSystem = SystemUser.is(user) || XPackUser.is(user);
|
if (User.isInternal(user) && eventType == ACCESS_GRANTED) {
|
||||||
if (isSystem && eventType == ACCESS_GRANTED) {
|
|
||||||
eventType = SYSTEM_ACCESS_GRANTED;
|
eventType = SYSTEM_ACCESS_GRANTED;
|
||||||
}
|
}
|
||||||
if (events.contains(eventType)) {
|
if (events.contains(eventType)) {
|
||||||
|
|
|
@ -9,6 +9,7 @@ import org.apache.logging.log4j.Level;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.apache.logging.log4j.core.layout.PatternLayout;
|
import org.apache.logging.log4j.core.layout.PatternLayout;
|
||||||
import org.elasticsearch.action.IndicesRequest;
|
import org.elasticsearch.action.IndicesRequest;
|
||||||
|
import org.elasticsearch.action.bulk.BulkItemRequest;
|
||||||
import org.elasticsearch.action.support.IndicesOptions;
|
import org.elasticsearch.action.support.IndicesOptions;
|
||||||
import org.elasticsearch.cluster.node.DiscoveryNode;
|
import org.elasticsearch.cluster.node.DiscoveryNode;
|
||||||
import org.elasticsearch.cluster.service.ClusterService;
|
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;
|
||||||
import org.elasticsearch.xpack.core.security.authc.Authentication.RealmRef;
|
import org.elasticsearch.xpack.core.security.authc.Authentication.RealmRef;
|
||||||
import org.elasticsearch.xpack.core.security.authc.AuthenticationToken;
|
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.SystemUser;
|
||||||
import org.elasticsearch.xpack.core.security.user.User;
|
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.AuditTrail;
|
||||||
import org.elasticsearch.xpack.security.audit.AuditUtil;
|
import org.elasticsearch.xpack.security.audit.AuditUtil;
|
||||||
import org.elasticsearch.xpack.core.security.authz.AuthorizationEngine.AuthorizationInfo;
|
import org.elasticsearch.xpack.core.security.authz.AuthorizationEngine.AuthorizationInfo;
|
||||||
|
@ -571,11 +576,78 @@ public class LoggingAuditTrailTests extends ESTestCase {
|
||||||
assertEmptyLog(logger);
|
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 {
|
public void testAccessGrantedInternalSystemAction() throws Exception {
|
||||||
final TransportRequest request = randomBoolean() ? new MockRequest(threadContext) : new MockIndicesRequest(threadContext);
|
final TransportRequest request = randomBoolean() ? new MockRequest(threadContext) : new MockIndicesRequest(threadContext);
|
||||||
final String[] expectedRoles = randomArray(0, 4, String[]::new, () -> randomBoolean() ? null : randomAlphaOfLengthBetween(1, 4));
|
final String[] expectedRoles = randomArray(0, 4, String[]::new, () -> randomBoolean() ? null : randomAlphaOfLengthBetween(1, 4));
|
||||||
final AuthorizationInfo authorizationInfo = () -> Collections.singletonMap(PRINCIPAL_ROLES_FIELD_NAME, expectedRoles);
|
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();
|
final String requestId = randomRequestId();
|
||||||
auditTrail.accessGranted(requestId, authentication, "internal:_action", request, authorizationInfo);
|
auditTrail.accessGranted(requestId, authentication, "internal:_action", request, authorizationInfo);
|
||||||
assertEmptyLog(logger);
|
assertEmptyLog(logger);
|
||||||
|
@ -591,7 +663,7 @@ public class LoggingAuditTrailTests extends ESTestCase {
|
||||||
final MapBuilder<String, String[]> checkedArrayFields = new MapBuilder<>();
|
final MapBuilder<String, String[]> checkedArrayFields = new MapBuilder<>();
|
||||||
checkedFields.put(LoggingAuditTrail.EVENT_TYPE_FIELD_NAME, LoggingAuditTrail.TRANSPORT_ORIGIN_FIELD_VALUE)
|
checkedFields.put(LoggingAuditTrail.EVENT_TYPE_FIELD_NAME, LoggingAuditTrail.TRANSPORT_ORIGIN_FIELD_VALUE)
|
||||||
.put(LoggingAuditTrail.EVENT_ACTION_FIELD_NAME, "access_granted")
|
.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.PRINCIPAL_REALM_FIELD_NAME, "_reserved")
|
||||||
.put(LoggingAuditTrail.ACTION_FIELD_NAME, "internal:_action")
|
.put(LoggingAuditTrail.ACTION_FIELD_NAME, "internal:_action")
|
||||||
.put(LoggingAuditTrail.REQUEST_NAME_FIELD_NAME, request.getClass().getSimpleName())
|
.put(LoggingAuditTrail.REQUEST_NAME_FIELD_NAME, request.getClass().getSimpleName())
|
||||||
|
|
Loading…
Reference in New Issue