From 9b7248688be5472587d1a42b6b92ac592605f19c Mon Sep 17 00:00:00 2001 From: Du Tran Date: Thu, 4 Jun 2026 21:37:31 +0300 Subject: [PATCH] Add tenant to audit log (#5709) Signed-off-by: Du Tran --- .../auditlog/impl/AbstractAuditLog.java | 38 ++++++++++++++++ .../security/auditlog/impl/AuditMessage.java | 7 +++ .../auditlog/impl/RequestResolver.java | 5 +++ .../integration/BasicAuditlogTest.java | 45 +++++++++++++++++++ 4 files changed, 95 insertions(+) diff --git a/src/main/java/org/opensearch/security/auditlog/impl/AbstractAuditLog.java b/src/main/java/org/opensearch/security/auditlog/impl/AbstractAuditLog.java index 8ba2c5d9f0..0a835cba82 100644 --- a/src/main/java/org/opensearch/security/auditlog/impl/AbstractAuditLog.java +++ b/src/main/java/org/opensearch/security/auditlog/impl/AbstractAuditLog.java @@ -173,6 +173,7 @@ public void logFailedLogin(String effectiveUser, boolean securityadmin, String i msg.addRestRequestInfo(request, auditConfigFilter); msg.addInitiatingUser(initiatingUser); msg.addEffectiveUser(effectiveUser); + msg.addTenant(getTenant(request)); msg.addIsAdminDn(securityadmin); save(msg); @@ -191,6 +192,7 @@ public void logSucceededLogin(String effectiveUser, boolean securityadmin, Strin msg.addRestRequestInfo(request, auditConfigFilter); msg.addInitiatingUser(initiatingUser); msg.addEffectiveUser(effectiveUser); + msg.addTenant(getTenant(request)); msg.addIsAdminDn(securityadmin); save(msg); } @@ -206,6 +208,7 @@ public void logMissingPrivileges(String privilege, String effectiveUser, Securit msg.addRemoteAddress(remoteAddress); msg.addRestRequestInfo(request, auditConfigFilter); msg.addEffectiveUser(effectiveUser); + msg.addTenant(getTenant(request)); msg.addPrivilege(privilege); save(msg); } @@ -220,6 +223,7 @@ public void logGrantedPrivileges(String effectiveUser, SecurityRequest request) msg.addRemoteAddress(getRemoteAddress()); msg.addRestRequestInfo(request, auditConfigFilter); msg.addEffectiveUser(effectiveUser); + msg.addTenant(getTenant(request)); save(msg); } @@ -240,6 +244,7 @@ public void logMissingPrivileges(String privilege, TransportRequest request, Tas getUser(), null, null, + getTenant(), remoteAddress, request, getThreadContextHeaders(), @@ -277,6 +282,7 @@ public void logGrantedPrivileges(String privilege, TransportRequest request, Tas getUser(), null, null, + getTenant(), remoteAddress, request, getThreadContextHeaders(), @@ -315,6 +321,7 @@ public void logIndexEvent(String privilege, TransportRequest request, Task task) getUser(), null, null, + getTenant(), remoteAddress, request, getThreadContextHeaders(), @@ -349,6 +356,7 @@ public void logBadHeaders(TransportRequest request, String action, Task task) { getUser(), null, null, + getTenant(), remoteAddress, request, getThreadContextHeaders(), @@ -381,6 +389,7 @@ public void logBadHeaders(SecurityRequest request) { msg.addRemoteAddress(remoteAddress); msg.addRestRequestInfo(request, auditConfigFilter); msg.addEffectiveUser(getUser()); + msg.addTenant(getTenant(request)); save(msg); } @@ -401,6 +410,7 @@ public void logSecurityIndexAttempt(TransportRequest request, String action, Tas getUser(), false, null, + getTenant(), remoteAddress, request, getThreadContextHeaders(), @@ -438,6 +448,7 @@ public void logSSLException(TransportRequest request, Throwable t, String action getUser(), false, null, + getTenant(), remoteAddress, request, getThreadContextHeaders(), @@ -472,6 +483,7 @@ public void logSSLException(SecurityRequest request, Throwable t) { msg.addRestRequestInfo(request, auditConfigFilter); msg.addException(t); msg.addEffectiveUser(getUser()); + msg.addTenant(getTenant(request)); save(msg); } @@ -503,6 +515,7 @@ public void logDocumentRead(String index, String id, ShardId shardId, Map getThreadContextHeaders() { return threadPool.getThreadContext().getHeaders(); } diff --git a/src/main/java/org/opensearch/security/auditlog/impl/AuditMessage.java b/src/main/java/org/opensearch/security/auditlog/impl/AuditMessage.java index 41d0228e74..ddabb0c137 100644 --- a/src/main/java/org/opensearch/security/auditlog/impl/AuditMessage.java +++ b/src/main/java/org/opensearch/security/auditlog/impl/AuditMessage.java @@ -90,6 +90,7 @@ public final class AuditMessage { public static final String CATEGORY = "audit_category"; public static final String REQUEST_EFFECTIVE_USER = "audit_request_effective_user"; public static final String REQUEST_INITIATING_USER = "audit_request_initiating_user"; + public static final String REQUEST_TENANT = "audit_request_tenant"; public static final String UTC_TIMESTAMP = "@timestamp"; public static final String CLUSTER_NAME = "audit_cluster_name"; @@ -198,6 +199,12 @@ public void addEffectiveUser(String user) { } } + public void addTenant(String tenant) { + if (tenant != null && !tenant.isEmpty()) { + auditInfo.put(REQUEST_TENANT, tenant); + } + } + public void addPath(String path) { if (path != null) { auditInfo.put(REST_REQUEST_PATH, path); diff --git a/src/main/java/org/opensearch/security/auditlog/impl/RequestResolver.java b/src/main/java/org/opensearch/security/auditlog/impl/RequestResolver.java index ea4289150e..b3347bead5 100644 --- a/src/main/java/org/opensearch/security/auditlog/impl/RequestResolver.java +++ b/src/main/java/org/opensearch/security/auditlog/impl/RequestResolver.java @@ -71,6 +71,7 @@ public static List resolve( final String effectiveUser, final Boolean securityadmin, final String initiatingUser, + final String tenant, final TransportAddress remoteAddress, final TransportRequest request, final Map headers, @@ -97,6 +98,7 @@ public static List resolve( effectiveUser, securityadmin, initiatingUser, + tenant, remoteAddress, action, privilege, @@ -137,6 +139,7 @@ public static List resolve( effectiveUser, securityadmin, initiatingUser, + tenant, remoteAddress, action, privilege, @@ -161,6 +164,7 @@ private static AuditMessage resolveInner( final String effectiveUser, final Boolean securityadmin, final String initiatingUser, + final String tenant, final TransportAddress remoteAddress, final String action, final String priv, @@ -181,6 +185,7 @@ private static AuditMessage resolveInner( final AuditMessage msg = new AuditMessage(category, cs, origin, Origin.TRANSPORT); msg.addInitiatingUser(initiatingUser); msg.addEffectiveUser(effectiveUser); + msg.addTenant(tenant); msg.addRemoteAddress(remoteAddress); msg.addAction(action); diff --git a/src/test/java/org/opensearch/security/auditlog/integration/BasicAuditlogTest.java b/src/test/java/org/opensearch/security/auditlog/integration/BasicAuditlogTest.java index 7a2e8c10c6..aa95569824 100644 --- a/src/test/java/org/opensearch/security/auditlog/integration/BasicAuditlogTest.java +++ b/src/test/java/org/opensearch/security/auditlog/integration/BasicAuditlogTest.java @@ -1008,4 +1008,49 @@ public void testSensitiveMethodRedaction() throws Exception { assertThat(TestAuditlogImpl.messages.size(), is(1)); Assert.assertTrue(TestAuditlogImpl.sb.toString().contains(expectedUpdateUserRequestBody)); } + + @Test + public void testTenantFieldOnAuthenticatedRestRequest() throws Exception { + final Settings settings = Settings.builder() + .put("plugins.security.audit.type", TestAuditlogImpl.class.getName()) + .put(ConfigConstants.OPENDISTRO_SECURITY_AUDIT_CONFIG_DISABLED_REST_CATEGORIES, "NONE") + .put(ConfigConstants.OPENDISTRO_SECURITY_AUDIT_CONFIG_DISABLED_TRANSPORT_CATEGORIES, "NONE") + .build(); + setup(settings); + + final List messages = TestAuditlogImpl.doThenWaitForMessages(() -> { + final HttpResponse response = rh.executeGetRequest( + "_search", + encodeBasicHeader("admin", "admin"), + new BasicHeader("securitytenant", "engineering_tenant") + ); + assertThat(response.getStatusCode(), equalTo(HttpStatus.SC_OK)); + }, 2); + + messages.forEach(message -> assertThat(message.toJson(), message.getAsMap().get(AuditMessage.REQUEST_TENANT), equalTo("engineering_tenant"))); + validateMsgs(messages); + } + + @Test + public void testTenantFieldOnFailedLogin() throws Exception { + final Settings settings = Settings.builder() + .put("plugins.security.audit.type", TestAuditlogImpl.class.getName()) + .put(ConfigConstants.OPENDISTRO_SECURITY_AUDIT_CONFIG_DISABLED_REST_CATEGORIES, "NONE") + .build(); + setup(settings); + + final List messages = TestAuditlogImpl.doThenWaitForMessages(() -> { + final HttpResponse response = rh.executeGetRequest( + "_search", + encodeBasicHeader("admin", "wrongpassword"), + new BasicHeader("securitytenant", "engineering_tenant") + ); + assertThat(response.getStatusCode(), equalTo(HttpStatus.SC_UNAUTHORIZED)); + }, 1); + + assertThat(messages.get(0).getCategory(), equalTo(AuditCategory.FAILED_LOGIN)); + assertThat(messages.get(0).getAsMap().get(AuditMessage.REQUEST_TENANT), equalTo("engineering_tenant")); + + validateMsgs(messages); + } }