瀏覽代碼

Emit trace.id into audit logs (#82849)

since #74210 ES is emitting trace.id into its logs, but it did not emit it into audit logs.
This commit adds trace.id into audit logging.
Przemyslaw Gomulka 3 年之前
父節點
當前提交
533f6e0eb8

+ 5 - 0
docs/changelog/82849.yaml

@@ -0,0 +1,5 @@
+pr: 82849
+summary: Emit `trace.id` into audit logs
+area: "Audit"
+type: enhancement
+issues: []

+ 9 - 6
x-pack/docs/en/security/auditing/event-types.asciidoc

@@ -6,7 +6,7 @@ When you are <<enable-audit-logging,auditing security events>>, a single client
 request might generate multiple audit events, across multiple cluster nodes.
 request might generate multiple audit events, across multiple cluster nodes.
 The common `request.id` attribute can be used to correlate the associated events.
 The common `request.id` attribute can be used to correlate the associated events.
 
 
-Use the <<xpack-sa-lf-events-include,`xpack.security.audit.logfile.events.include`>> 
+Use the <<xpack-sa-lf-events-include,`xpack.security.audit.logfile.events.include`>>
 setting in `elasticsearch.yml` to specify the kind of events you want to include
 setting in `elasticsearch.yml` to specify the kind of events you want to include
 in the auditing output.
 in the auditing output.
 
 
@@ -534,8 +534,8 @@ The following list shows attributes that are common to all audit event types:
 In addition, if `event.type` equals <<security-config-change,`security_config_change`>>,
 In addition, if `event.type` equals <<security-config-change,`security_config_change`>>,
 the `event.action` attribute takes one of the following values:
 the `event.action` attribute takes one of the following values:
 `put_user`, `change_password`, `put_role`, `put_role_mapping`,
 `put_user`, `change_password`, `put_role`, `put_role_mapping`,
-`change_enable_user`, `change_disable_user`, `put_privileges`, `create_apikey`, 
-`delete_user`, `delete_role`, `delete_role_mapping`, `invalidate_apikeys` or 
+`change_enable_user`, `change_disable_user`, `put_privileges`, `create_apikey`,
+`delete_user`, `delete_role`, `delete_role_mapping`, `invalidate_apikeys` or
 `delete_privileges`.
 `delete_privileges`.
 
 
 `request.id`      ::    A synthetic identifier that can be used to correlate the events
 `request.id`      ::    A synthetic identifier that can be used to correlate the events
@@ -557,9 +557,12 @@ show more details about the requesting client:
                         `transport` (request was received on the transport channel),
                         `transport` (request was received on the transport channel),
                         or `local_node` (the local node issued the request).
                         or `local_node` (the local node issued the request).
 `opaque_id`       ::    The value of the `X-Opaque-Id` HTTP header (if present) of
 `opaque_id`       ::    The value of the `X-Opaque-Id` HTTP header (if present) of
-                        the request associated with this event. This header can
-                        be used freely by the client to mark API calls, as it has
-                        no semantics in Elasticsearch.
+                        the request associated with this event.
+                        See more: <<x-opaque-id, `X-Opaque-Id` HTTP header - API conventions>>
+`trace_id`        ::    The identifier extracted from the `traceparent` HTTP header
+                        (if present) of the request associated with this event.
+                        It allows to surface audit logs into the Trace Logs feature
+                        of Elastic APM.
 `x_forwarded_for` ::    The verbatim value of the `X-Forwarded-For` HTTP request
 `x_forwarded_for` ::    The verbatim value of the `X-Forwarded-For` HTTP request
                         header (if present) of the request associated with the
                         header (if present) of the request associated with the
                         audit event. This header is commonly added by proxies
                         audit event. This header is commonly added by proxies

+ 2 - 0
x-pack/plugin/core/src/main/config/log4j2.properties

@@ -37,6 +37,7 @@ appender.audit_rolling.layout.pattern = {\
                 %varsNotEmpty{, "request.name":"%enc{%map{request.name}}{JSON}"}\
                 %varsNotEmpty{, "request.name":"%enc{%map{request.name}}{JSON}"}\
                 %varsNotEmpty{, "indices":%map{indices}}\
                 %varsNotEmpty{, "indices":%map{indices}}\
                 %varsNotEmpty{, "opaque_id":"%enc{%map{opaque_id}}{JSON}"}\
                 %varsNotEmpty{, "opaque_id":"%enc{%map{opaque_id}}{JSON}"}\
+                %varsNotEmpty{, "trace.id":"%enc{%map{trace.id}}{JSON}"}\
                 %varsNotEmpty{, "x_forwarded_for":"%enc{%map{x_forwarded_for}}{JSON}"}\
                 %varsNotEmpty{, "x_forwarded_for":"%enc{%map{x_forwarded_for}}{JSON}"}\
                 %varsNotEmpty{, "transport.profile":"%enc{%map{transport.profile}}{JSON}"}\
                 %varsNotEmpty{, "transport.profile":"%enc{%map{transport.profile}}{JSON}"}\
                 %varsNotEmpty{, "rule":"%enc{%map{rule}}{JSON}"}\
                 %varsNotEmpty{, "rule":"%enc{%map{rule}}{JSON}"}\
@@ -76,6 +77,7 @@ appender.audit_rolling.layout.pattern = {\
 # "request.name" if the event is in connection to a transport message this is the name of the request class, similar to how rest requests are identified by the url path (internal)
 # "request.name" if the event is in connection to a transport message this is the name of the request class, similar to how rest requests are identified by the url path (internal)
 # "indices" the array of indices that the "action" is acting upon
 # "indices" the array of indices that the "action" is acting upon
 # "opaque_id" opaque value conveyed by the "X-Opaque-Id" request header
 # "opaque_id" opaque value conveyed by the "X-Opaque-Id" request header
+# "trace_id" an identifier conveyed by the part of "traceparent" request header
 # "x_forwarded_for" the addresses from the "X-Forwarded-For" request header, as a verbatim string value (not an array)
 # "x_forwarded_for" the addresses from the "X-Forwarded-For" request header, as a verbatim string value (not an array)
 # "transport.profile" name of the transport profile in case this is a "connection_granted" or "connection_denied" event
 # "transport.profile" name of the transport profile in case this is a "connection_granted" or "connection_denied" event
 # "rule" name of the applied rule if the "origin.type" is "ip_filter"
 # "rule" name of the applied rule if the "origin.type" is "ip_filter"

+ 30 - 52
x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/audit/logfile/LoggingAuditTrail.java

@@ -180,6 +180,7 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
     public static final String TRANSPORT_PROFILE_FIELD_NAME = "transport.profile";
     public static final String TRANSPORT_PROFILE_FIELD_NAME = "transport.profile";
     public static final String RULE_FIELD_NAME = "rule";
     public static final String RULE_FIELD_NAME = "rule";
     public static final String OPAQUE_ID_FIELD_NAME = "opaque_id";
     public static final String OPAQUE_ID_FIELD_NAME = "opaque_id";
+    public static final String TRACE_ID_FIELD_NAME = "trace.id";
     public static final String X_FORWARDED_FOR_FIELD_NAME = "x_forwarded_for";
     public static final String X_FORWARDED_FOR_FIELD_NAME = "x_forwarded_for";
     // the fields below are used exclusively for "security_config_change" type of events, and show the configuration
     // the fields below are used exclusively for "security_config_change" type of events, and show the configuration
     // object taking effect; it could be creating a new, or updating an existing configuration
     // object taking effect; it could be creating a new, or updating an existing configuration
@@ -457,8 +458,7 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
                 .withAuthentication(authentication)
                 .withAuthentication(authentication)
                 .withRestOrigin(request)
                 .withRestOrigin(request)
                 .withRequestBody(request)
                 .withRequestBody(request)
-                .withOpaqueId(threadContext)
-                .withXForwardedFor(threadContext)
+                .withThreadContext(threadContext)
                 .build();
                 .build();
         }
         }
     }
     }
@@ -486,8 +486,7 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
                     .withAuthentication(authentication)
                     .withAuthentication(authentication)
                     .withRestOrTransportOrigin(transportRequest, threadContext)
                     .withRestOrTransportOrigin(transportRequest, threadContext)
                     .with(INDICES_FIELD_NAME, indices.orElse(null))
                     .with(INDICES_FIELD_NAME, indices.orElse(null))
-                    .withOpaqueId(threadContext)
-                    .withXForwardedFor(threadContext)
+                    .withThreadContext(threadContext)
                     .build();
                     .build();
             }
             }
         }
         }
@@ -506,8 +505,7 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
                     .withRequestId(requestId)
                     .withRequestId(requestId)
                     .withRestOrTransportOrigin(transportRequest, threadContext)
                     .withRestOrTransportOrigin(transportRequest, threadContext)
                     .with(INDICES_FIELD_NAME, indices.orElse(null))
                     .with(INDICES_FIELD_NAME, indices.orElse(null))
-                    .withOpaqueId(threadContext)
-                    .withXForwardedFor(threadContext)
+                    .withThreadContext(threadContext)
                     .build();
                     .build();
             }
             }
         }
         }
@@ -523,8 +521,7 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
                 .withRestOrigin(request)
                 .withRestOrigin(request)
                 .withRequestBody(request)
                 .withRequestBody(request)
                 .withRequestId(requestId)
                 .withRequestId(requestId)
-                .withOpaqueId(threadContext)
-                .withXForwardedFor(threadContext)
+                .withThreadContext(threadContext)
                 .build();
                 .build();
         }
         }
     }
     }
@@ -543,8 +540,7 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
                     .withRequestId(requestId)
                     .withRequestId(requestId)
                     .withRestOrTransportOrigin(transportRequest, threadContext)
                     .withRestOrTransportOrigin(transportRequest, threadContext)
                     .with(INDICES_FIELD_NAME, indices.orElse(null))
                     .with(INDICES_FIELD_NAME, indices.orElse(null))
-                    .withOpaqueId(threadContext)
-                    .withXForwardedFor(threadContext);
+                    .withThreadContext(threadContext);
                 if (token instanceof ServiceAccountToken) {
                 if (token instanceof ServiceAccountToken) {
                     logEntryBuilder.with(SERVICE_TOKEN_NAME_FIELD_NAME, ((ServiceAccountToken) token).getTokenName());
                     logEntryBuilder.with(SERVICE_TOKEN_NAME_FIELD_NAME, ((ServiceAccountToken) token).getTokenName());
                 }
                 }
@@ -562,8 +558,7 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
                 .withRestOrigin(request)
                 .withRestOrigin(request)
                 .withRequestBody(request)
                 .withRequestBody(request)
                 .withRequestId(requestId)
                 .withRequestId(requestId)
-                .withOpaqueId(threadContext)
-                .withXForwardedFor(threadContext)
+                .withThreadContext(threadContext)
                 .build();
                 .build();
         }
         }
     }
     }
@@ -581,8 +576,7 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
                     .withRequestId(requestId)
                     .withRequestId(requestId)
                     .withRestOrTransportOrigin(transportRequest, threadContext)
                     .withRestOrTransportOrigin(transportRequest, threadContext)
                     .with(INDICES_FIELD_NAME, indices.orElse(null))
                     .with(INDICES_FIELD_NAME, indices.orElse(null))
-                    .withOpaqueId(threadContext)
-                    .withXForwardedFor(threadContext)
+                    .withThreadContext(threadContext)
                     .build();
                     .build();
             }
             }
         }
         }
@@ -600,8 +594,7 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
                 .withRestOrigin(request)
                 .withRestOrigin(request)
                 .withRequestBody(request)
                 .withRequestBody(request)
                 .withRequestId(requestId)
                 .withRequestId(requestId)
-                .withOpaqueId(threadContext)
-                .withXForwardedFor(threadContext);
+                .withThreadContext(threadContext);
             if (token instanceof ServiceAccountToken) {
             if (token instanceof ServiceAccountToken) {
                 logEntryBuilder.with(SERVICE_TOKEN_NAME_FIELD_NAME, ((ServiceAccountToken) token).getTokenName());
                 logEntryBuilder.with(SERVICE_TOKEN_NAME_FIELD_NAME, ((ServiceAccountToken) token).getTokenName());
             }
             }
@@ -630,8 +623,7 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
                     .withRequestId(requestId)
                     .withRequestId(requestId)
                     .withRestOrTransportOrigin(transportRequest, threadContext)
                     .withRestOrTransportOrigin(transportRequest, threadContext)
                     .with(INDICES_FIELD_NAME, indices.orElse(null))
                     .with(INDICES_FIELD_NAME, indices.orElse(null))
-                    .withOpaqueId(threadContext)
-                    .withXForwardedFor(threadContext)
+                    .withThreadContext(threadContext)
                     .build();
                     .build();
             }
             }
         }
         }
@@ -650,8 +642,7 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
                 .withRestOrigin(request)
                 .withRestOrigin(request)
                 .withRequestBody(request)
                 .withRequestBody(request)
                 .withRequestId(requestId)
                 .withRequestId(requestId)
-                .withOpaqueId(threadContext)
-                .withXForwardedFor(threadContext)
+                .withThreadContext(threadContext)
                 .build();
                 .build();
         }
         }
     }
     }
@@ -687,8 +678,7 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
                     .withAuthentication(authentication)
                     .withAuthentication(authentication)
                     .withRestOrTransportOrigin(msg, threadContext)
                     .withRestOrTransportOrigin(msg, threadContext)
                     .with(INDICES_FIELD_NAME, indices.orElse(null))
                     .with(INDICES_FIELD_NAME, indices.orElse(null))
-                    .withOpaqueId(threadContext)
-                    .withXForwardedFor(threadContext)
+                    .withThreadContext(threadContext)
                     .with(authorizationInfo.asMap())
                     .with(authorizationInfo.asMap())
                     .build();
                     .build();
             }
             }
@@ -795,8 +785,7 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
                     .withRequestId(requestId)
                     .withRequestId(requestId)
                     .withAuthentication(authentication)
                     .withAuthentication(authentication)
                     .with(INDICES_FIELD_NAME, indices)
                     .with(INDICES_FIELD_NAME, indices)
-                    .withOpaqueId(threadContext)
-                    .withXForwardedFor(threadContext)
+                    .withThreadContext(threadContext)
                     .with(authorizationInfo.asMap());
                     .with(authorizationInfo.asMap());
                 final InetSocketAddress restAddress = RemoteHostHeader.restRemoteAddress(threadContext);
                 final InetSocketAddress restAddress = RemoteHostHeader.restRemoteAddress(threadContext);
                 if (restAddress != null) {
                 if (restAddress != null) {
@@ -841,8 +830,7 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
                     .withRestOrTransportOrigin(transportRequest, threadContext)
                     .withRestOrTransportOrigin(transportRequest, threadContext)
                     .with(INDICES_FIELD_NAME, indices.orElse(null))
                     .with(INDICES_FIELD_NAME, indices.orElse(null))
                     .with(authorizationInfo.asMap())
                     .with(authorizationInfo.asMap())
-                    .withOpaqueId(threadContext)
-                    .withXForwardedFor(threadContext)
+                    .withThreadContext(threadContext)
                     .build();
                     .build();
             }
             }
         }
         }
@@ -857,8 +845,7 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
                 .withRestOrigin(request)
                 .withRestOrigin(request)
                 .withRequestBody(request)
                 .withRequestBody(request)
                 .withRequestId(requestId)
                 .withRequestId(requestId)
-                .withOpaqueId(threadContext)
-                .withXForwardedFor(threadContext)
+                .withThreadContext(threadContext)
                 .build();
                 .build();
         }
         }
     }
     }
@@ -876,8 +863,7 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
                     .withRequestId(requestId)
                     .withRequestId(requestId)
                     .withRestOrTransportOrigin(transportRequest, threadContext)
                     .withRestOrTransportOrigin(transportRequest, threadContext)
                     .with(INDICES_FIELD_NAME, indices.orElse(null))
                     .with(INDICES_FIELD_NAME, indices.orElse(null))
-                    .withOpaqueId(threadContext)
-                    .withXForwardedFor(threadContext)
+                    .withThreadContext(threadContext)
                     .build();
                     .build();
             }
             }
         }
         }
@@ -906,8 +892,7 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
                     .withRestOrTransportOrigin(transportRequest, threadContext)
                     .withRestOrTransportOrigin(transportRequest, threadContext)
                     .withAuthentication(authentication)
                     .withAuthentication(authentication)
                     .with(INDICES_FIELD_NAME, indices.orElse(null))
                     .with(INDICES_FIELD_NAME, indices.orElse(null))
-                    .withOpaqueId(threadContext)
-                    .withXForwardedFor(threadContext)
+                    .withThreadContext(threadContext)
                     .build();
                     .build();
             }
             }
         }
         }
@@ -925,8 +910,7 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
                 .with(ORIGIN_ADDRESS_FIELD_NAME, NetworkAddress.format(inetAddress))
                 .with(ORIGIN_ADDRESS_FIELD_NAME, NetworkAddress.format(inetAddress))
                 .with(TRANSPORT_PROFILE_FIELD_NAME, profile)
                 .with(TRANSPORT_PROFILE_FIELD_NAME, profile)
                 .with(RULE_FIELD_NAME, rule.toString())
                 .with(RULE_FIELD_NAME, rule.toString())
-                .withOpaqueId(threadContext)
-                .withXForwardedFor(threadContext)
+                .withThreadContext(threadContext)
                 .build();
                 .build();
         }
         }
     }
     }
@@ -943,8 +927,7 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
                 .with(ORIGIN_ADDRESS_FIELD_NAME, NetworkAddress.format(inetAddress))
                 .with(ORIGIN_ADDRESS_FIELD_NAME, NetworkAddress.format(inetAddress))
                 .with(TRANSPORT_PROFILE_FIELD_NAME, profile)
                 .with(TRANSPORT_PROFILE_FIELD_NAME, profile)
                 .with(RULE_FIELD_NAME, rule.toString())
                 .with(RULE_FIELD_NAME, rule.toString())
-                .withOpaqueId(threadContext)
-                .withXForwardedFor(threadContext)
+                .withThreadContext(threadContext)
                 .build();
                 .build();
         }
         }
     }
     }
@@ -979,8 +962,7 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
                     .withRestOrTransportOrigin(transportRequest, threadContext)
                     .withRestOrTransportOrigin(transportRequest, threadContext)
                     .with(INDICES_FIELD_NAME, indices.orElse(null))
                     .with(INDICES_FIELD_NAME, indices.orElse(null))
                     .with(authorizationInfo.asMap())
                     .with(authorizationInfo.asMap())
-                    .withOpaqueId(threadContext)
-                    .withXForwardedFor(threadContext)
+                    .withThreadContext(threadContext)
                     .build();
                     .build();
             }
             }
         }
         }
@@ -1016,8 +998,7 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
                     .withRestOrTransportOrigin(transportRequest, threadContext)
                     .withRestOrTransportOrigin(transportRequest, threadContext)
                     .with(INDICES_FIELD_NAME, indices.orElse(null))
                     .with(INDICES_FIELD_NAME, indices.orElse(null))
                     .with(authorizationInfo.asMap())
                     .with(authorizationInfo.asMap())
-                    .withOpaqueId(threadContext)
-                    .withXForwardedFor(threadContext)
+                    .withThreadContext(threadContext)
                     .build();
                     .build();
             }
             }
         }
         }
@@ -1045,8 +1026,7 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
                 .withRestOrigin(request)
                 .withRestOrigin(request)
                 .withRequestBody(request)
                 .withRequestBody(request)
                 .withRequestId(requestId)
                 .withRequestId(requestId)
-                .withOpaqueId(threadContext)
-                .withXForwardedFor(threadContext)
+                .withThreadContext(threadContext)
                 .build();
                 .build();
         }
         }
     }
     }
@@ -1473,20 +1453,18 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
             return this;
             return this;
         }
         }
 
 
-        LogEntryBuilder withOpaqueId(ThreadContext threadContext) {
-            final String opaqueId = threadContext.getHeader(Task.X_OPAQUE_ID_HTTP_HEADER);
-            if (opaqueId != null) {
-                logEntry.with(OPAQUE_ID_FIELD_NAME, opaqueId);
-            }
+        LogEntryBuilder withThreadContext(ThreadContext threadContext) {
+            setThreadContextField(threadContext, AuditTrail.X_FORWARDED_FOR_HEADER, X_FORWARDED_FOR_FIELD_NAME);
+            setThreadContextField(threadContext, Task.X_OPAQUE_ID_HTTP_HEADER, OPAQUE_ID_FIELD_NAME);
+            setThreadContextField(threadContext, Task.TRACE_ID, TRACE_ID_FIELD_NAME);
             return this;
             return this;
         }
         }
 
 
-        LogEntryBuilder withXForwardedFor(ThreadContext threadContext) {
-            final String xForwardedFor = threadContext.getHeader(AuditTrail.X_FORWARDED_FOR_HEADER);
-            if (xForwardedFor != null) {
-                logEntry.with(X_FORWARDED_FOR_FIELD_NAME, xForwardedFor);
+        private void setThreadContextField(ThreadContext threadContext, String threadContextFieldName, String auditLogFieldName) {
+            final String fieldValue = threadContext.getHeader(threadContextFieldName);
+            if (fieldValue != null) {
+                logEntry.with(auditLogFieldName, fieldValue);
             }
             }
-            return this;
         }
         }
 
 
         LogEntryBuilder withAuthentication(Authentication authentication) {
         LogEntryBuilder withAuthentication(Authentication authentication) {

+ 54 - 7
x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/audit/logfile/LoggingAuditTrailTests.java

@@ -325,6 +325,9 @@ public class LoggingAuditTrailTests extends ESTestCase {
         if (randomBoolean()) {
         if (randomBoolean()) {
             threadContext.putHeader(Task.X_OPAQUE_ID_HTTP_HEADER, randomAlphaOfLengthBetween(1, 4));
             threadContext.putHeader(Task.X_OPAQUE_ID_HTTP_HEADER, randomAlphaOfLengthBetween(1, 4));
         }
         }
+        if (randomBoolean()) {
+            threadContext.putHeader(Task.TRACE_ID, randomAlphaOfLength(32));
+        }
         if (randomBoolean()) {
         if (randomBoolean()) {
             threadContext.putHeader(
             threadContext.putHeader(
                 AuditTrail.X_FORWARDED_FOR_HEADER,
                 AuditTrail.X_FORWARDED_FOR_HEADER,
@@ -1306,6 +1309,7 @@ public class LoggingAuditTrailTests extends ESTestCase {
         indicesRequest(request, checkedFields, checkedArrayFields);
         indicesRequest(request, checkedFields, checkedArrayFields);
         restOrTransportOrigin(request, threadContext, checkedFields);
         restOrTransportOrigin(request, threadContext, checkedFields);
         opaqueId(threadContext, checkedFields);
         opaqueId(threadContext, checkedFields);
+        traceId(threadContext, checkedFields);
         forwardedFor(threadContext, checkedFields);
         forwardedFor(threadContext, checkedFields);
         assertMsg(logger, checkedFields.map(), checkedArrayFields.map());
         assertMsg(logger, checkedFields.map(), checkedArrayFields.map());
 
 
@@ -1341,6 +1345,7 @@ public class LoggingAuditTrailTests extends ESTestCase {
             checkedFields.put(LoggingAuditTrail.REQUEST_BODY_FIELD_NAME, expectedMessage);
             checkedFields.put(LoggingAuditTrail.REQUEST_BODY_FIELD_NAME, expectedMessage);
         }
         }
         opaqueId(threadContext, checkedFields);
         opaqueId(threadContext, checkedFields);
+        traceId(threadContext, checkedFields);
         forwardedFor(threadContext, checkedFields);
         forwardedFor(threadContext, checkedFields);
         assertMsg(logger, checkedFields.map());
         assertMsg(logger, checkedFields.map());
 
 
@@ -1373,6 +1378,7 @@ public class LoggingAuditTrailTests extends ESTestCase {
         restOrTransportOrigin(request, threadContext, checkedFields);
         restOrTransportOrigin(request, threadContext, checkedFields);
         indicesRequest(request, checkedFields, checkedArrayFields);
         indicesRequest(request, checkedFields, checkedArrayFields);
         opaqueId(threadContext, checkedFields);
         opaqueId(threadContext, checkedFields);
+        traceId(threadContext, checkedFields);
         forwardedFor(threadContext, checkedFields);
         forwardedFor(threadContext, checkedFields);
         assertMsg(logger, checkedFields.map(), checkedArrayFields.map());
         assertMsg(logger, checkedFields.map(), checkedArrayFields.map());
 
 
@@ -1400,6 +1406,7 @@ public class LoggingAuditTrailTests extends ESTestCase {
         restOrTransportOrigin(request, threadContext, checkedFields);
         restOrTransportOrigin(request, threadContext, checkedFields);
         indicesRequest(request, checkedFields, checkedArrayFields);
         indicesRequest(request, checkedFields, checkedArrayFields);
         opaqueId(threadContext, checkedFields);
         opaqueId(threadContext, checkedFields);
+        traceId(threadContext, checkedFields);
         forwardedFor(threadContext, checkedFields);
         forwardedFor(threadContext, checkedFields);
         assertMsg(logger, checkedFields.map(), checkedArrayFields.map());
         assertMsg(logger, checkedFields.map(), checkedArrayFields.map());
 
 
@@ -1447,6 +1454,7 @@ public class LoggingAuditTrailTests extends ESTestCase {
             checkedFields.put(LoggingAuditTrail.URL_QUERY_FIELD_NAME, "foo=bar");
             checkedFields.put(LoggingAuditTrail.URL_QUERY_FIELD_NAME, "foo=bar");
         }
         }
         opaqueId(threadContext, checkedFields);
         opaqueId(threadContext, checkedFields);
+        traceId(threadContext, checkedFields);
         forwardedFor(threadContext, checkedFields);
         forwardedFor(threadContext, checkedFields);
         assertMsg(logger, checkedFields.map());
         assertMsg(logger, checkedFields.map());
 
 
@@ -1489,6 +1497,7 @@ public class LoggingAuditTrailTests extends ESTestCase {
             checkedFields.put(LoggingAuditTrail.URL_QUERY_FIELD_NAME, "bar=baz");
             checkedFields.put(LoggingAuditTrail.URL_QUERY_FIELD_NAME, "bar=baz");
         }
         }
         opaqueId(threadContext, checkedFields);
         opaqueId(threadContext, checkedFields);
+        traceId(threadContext, checkedFields);
         forwardedFor(threadContext, checkedFields);
         forwardedFor(threadContext, checkedFields);
         assertMsg(logger, checkedFields.map());
         assertMsg(logger, checkedFields.map());
 
 
@@ -1526,6 +1535,7 @@ public class LoggingAuditTrailTests extends ESTestCase {
         restOrTransportOrigin(request, threadContext, checkedFields);
         restOrTransportOrigin(request, threadContext, checkedFields);
         indicesRequest(request, checkedFields, checkedArrayFields);
         indicesRequest(request, checkedFields, checkedArrayFields);
         opaqueId(threadContext, checkedFields);
         opaqueId(threadContext, checkedFields);
+        traceId(threadContext, checkedFields);
         forwardedFor(threadContext, checkedFields);
         forwardedFor(threadContext, checkedFields);
         assertMsg(logger, checkedFields.map(), checkedArrayFields.map());
         assertMsg(logger, checkedFields.map(), checkedArrayFields.map());
     }
     }
@@ -1570,6 +1580,7 @@ public class LoggingAuditTrailTests extends ESTestCase {
             checkedFields.put(LoggingAuditTrail.URL_QUERY_FIELD_NAME, "_param=baz");
             checkedFields.put(LoggingAuditTrail.URL_QUERY_FIELD_NAME, "_param=baz");
         }
         }
         opaqueId(threadContext, checkedFields);
         opaqueId(threadContext, checkedFields);
+        traceId(threadContext, checkedFields);
         forwardedFor(threadContext, checkedFields);
         forwardedFor(threadContext, checkedFields);
         assertMsg(logger, checkedFields.map());
         assertMsg(logger, checkedFields.map());
     }
     }
@@ -1595,6 +1606,7 @@ public class LoggingAuditTrailTests extends ESTestCase {
         restOrTransportOrigin(request, threadContext, checkedFields);
         restOrTransportOrigin(request, threadContext, checkedFields);
         indicesRequest(request, checkedFields, checkedArrayFields);
         indicesRequest(request, checkedFields, checkedArrayFields);
         opaqueId(threadContext, checkedFields);
         opaqueId(threadContext, checkedFields);
+        traceId(threadContext, checkedFields);
         forwardedFor(threadContext, checkedFields);
         forwardedFor(threadContext, checkedFields);
         assertMsg(logger, checkedFields.map(), checkedArrayFields.map());
         assertMsg(logger, checkedFields.map(), checkedArrayFields.map());
 
 
@@ -1615,6 +1627,7 @@ public class LoggingAuditTrailTests extends ESTestCase {
         restOrTransportOrigin(request, threadContext, checkedFields);
         restOrTransportOrigin(request, threadContext, checkedFields);
         indicesRequest(request, checkedFields, checkedArrayFields);
         indicesRequest(request, checkedFields, checkedArrayFields);
         opaqueId(threadContext, checkedFields);
         opaqueId(threadContext, checkedFields);
+        traceId(threadContext, checkedFields);
         forwardedFor(threadContext, checkedFields);
         forwardedFor(threadContext, checkedFields);
         assertMsg(logger, checkedFields.map(), checkedArrayFields.map());
         assertMsg(logger, checkedFields.map(), checkedArrayFields.map());
 
 
@@ -1719,6 +1732,7 @@ public class LoggingAuditTrailTests extends ESTestCase {
         restOrTransportOrigin(request, threadContext, checkedFields);
         restOrTransportOrigin(request, threadContext, checkedFields);
         indicesRequest(request, checkedFields, checkedArrayFields);
         indicesRequest(request, checkedFields, checkedArrayFields);
         opaqueId(threadContext, checkedFields);
         opaqueId(threadContext, checkedFields);
+        traceId(threadContext, checkedFields);
         forwardedFor(threadContext, checkedFields);
         forwardedFor(threadContext, checkedFields);
         assertMsg(logger, checkedFields.map(), checkedArrayFields.map());
         assertMsg(logger, checkedFields.map(), checkedArrayFields.map());
         clearLog();
         clearLog();
@@ -1746,6 +1760,7 @@ public class LoggingAuditTrailTests extends ESTestCase {
         authentication(authentication, checkedFields);
         authentication(authentication, checkedFields);
         restOrTransportOrigin(request, threadContext, checkedFields);
         restOrTransportOrigin(request, threadContext, checkedFields);
         opaqueId(threadContext, checkedFields);
         opaqueId(threadContext, checkedFields);
+        traceId(threadContext, checkedFields);
         forwardedFor(threadContext, checkedFields);
         forwardedFor(threadContext, checkedFields);
         if (index != null) {
         if (index != null) {
             checkedArrayFields.put(LoggingAuditTrail.INDICES_FIELD_NAME, new String[] { index });
             checkedArrayFields.put(LoggingAuditTrail.INDICES_FIELD_NAME, new String[] { index });
@@ -1782,6 +1797,7 @@ public class LoggingAuditTrailTests extends ESTestCase {
         restOrTransportOrigin(request, threadContext, checkedFields);
         restOrTransportOrigin(request, threadContext, checkedFields);
         indicesRequest(request, checkedFields, checkedArrayFields);
         indicesRequest(request, checkedFields, checkedArrayFields);
         opaqueId(threadContext, checkedFields);
         opaqueId(threadContext, checkedFields);
+        traceId(threadContext, checkedFields);
         forwardedFor(threadContext, checkedFields);
         forwardedFor(threadContext, checkedFields);
         assertMsg(logger, checkedFields.map(), checkedArrayFields.map());
         assertMsg(logger, checkedFields.map(), checkedArrayFields.map());
     }
     }
@@ -1806,6 +1822,7 @@ public class LoggingAuditTrailTests extends ESTestCase {
         restOrTransportOrigin(request, threadContext, checkedFields);
         restOrTransportOrigin(request, threadContext, checkedFields);
         indicesRequest(request, checkedFields, checkedArrayFields);
         indicesRequest(request, checkedFields, checkedArrayFields);
         opaqueId(threadContext, checkedFields);
         opaqueId(threadContext, checkedFields);
+        traceId(threadContext, checkedFields);
         forwardedFor(threadContext, checkedFields);
         forwardedFor(threadContext, checkedFields);
         assertMsg(logger, checkedFields.map(), checkedArrayFields.map());
         assertMsg(logger, checkedFields.map(), checkedArrayFields.map());
 
 
@@ -1826,6 +1843,7 @@ public class LoggingAuditTrailTests extends ESTestCase {
         restOrTransportOrigin(request, threadContext, checkedFields);
         restOrTransportOrigin(request, threadContext, checkedFields);
         indicesRequest(request, checkedFields, checkedArrayFields);
         indicesRequest(request, checkedFields, checkedArrayFields);
         opaqueId(threadContext, checkedFields);
         opaqueId(threadContext, checkedFields);
+        traceId(threadContext, checkedFields);
         forwardedFor(threadContext, checkedFields);
         forwardedFor(threadContext, checkedFields);
         assertMsg(logger, checkedFields.map(), checkedArrayFields.map());
         assertMsg(logger, checkedFields.map(), checkedArrayFields.map());
 
 
@@ -1863,6 +1881,7 @@ public class LoggingAuditTrailTests extends ESTestCase {
         restOrTransportOrigin(request, threadContext, checkedFields);
         restOrTransportOrigin(request, threadContext, checkedFields);
         indicesRequest(request, checkedFields, checkedArrayFields);
         indicesRequest(request, checkedFields, checkedArrayFields);
         opaqueId(threadContext, checkedFields);
         opaqueId(threadContext, checkedFields);
+        traceId(threadContext, checkedFields);
         forwardedFor(threadContext, checkedFields);
         forwardedFor(threadContext, checkedFields);
         assertMsg(logger, checkedFields.map(), checkedArrayFields.map());
         assertMsg(logger, checkedFields.map(), checkedArrayFields.map());
 
 
@@ -1883,6 +1902,7 @@ public class LoggingAuditTrailTests extends ESTestCase {
         restOrTransportOrigin(request, threadContext, checkedFields);
         restOrTransportOrigin(request, threadContext, checkedFields);
         indicesRequest(request, checkedFields, checkedArrayFields);
         indicesRequest(request, checkedFields, checkedArrayFields);
         opaqueId(threadContext, checkedFields);
         opaqueId(threadContext, checkedFields);
+        traceId(threadContext, checkedFields);
         forwardedFor(threadContext, checkedFields);
         forwardedFor(threadContext, checkedFields);
         assertMsg(logger, checkedFields.map(), checkedArrayFields.map());
         assertMsg(logger, checkedFields.map(), checkedArrayFields.map());
 
 
@@ -1922,6 +1942,7 @@ public class LoggingAuditTrailTests extends ESTestCase {
             checkedFields.put(LoggingAuditTrail.URL_QUERY_FIELD_NAME, "_param=baz");
             checkedFields.put(LoggingAuditTrail.URL_QUERY_FIELD_NAME, "_param=baz");
         }
         }
         opaqueId(threadContext, checkedFields);
         opaqueId(threadContext, checkedFields);
+        traceId(threadContext, checkedFields);
         forwardedFor(threadContext, checkedFields);
         forwardedFor(threadContext, checkedFields);
         assertMsg(logger, checkedFields.map());
         assertMsg(logger, checkedFields.map());
 
 
@@ -1949,6 +1970,7 @@ public class LoggingAuditTrailTests extends ESTestCase {
         restOrTransportOrigin(request, threadContext, checkedFields);
         restOrTransportOrigin(request, threadContext, checkedFields);
         indicesRequest(request, checkedFields, checkedArrayFields);
         indicesRequest(request, checkedFields, checkedArrayFields);
         opaqueId(threadContext, checkedFields);
         opaqueId(threadContext, checkedFields);
+        traceId(threadContext, checkedFields);
         forwardedFor(threadContext, checkedFields);
         forwardedFor(threadContext, checkedFields);
         assertMsg(logger, checkedFields.map(), checkedArrayFields.map());
         assertMsg(logger, checkedFields.map(), checkedArrayFields.map());
 
 
@@ -1978,6 +2000,7 @@ public class LoggingAuditTrailTests extends ESTestCase {
         restOrTransportOrigin(request, threadContext, checkedFields);
         restOrTransportOrigin(request, threadContext, checkedFields);
         indicesRequest(request, checkedFields, checkedArrayFields);
         indicesRequest(request, checkedFields, checkedArrayFields);
         opaqueId(threadContext, checkedFields);
         opaqueId(threadContext, checkedFields);
+        traceId(threadContext, checkedFields);
         forwardedFor(threadContext, checkedFields);
         forwardedFor(threadContext, checkedFields);
         assertMsg(logger, checkedFields.map(), checkedArrayFields.map());
         assertMsg(logger, checkedFields.map(), checkedArrayFields.map());
 
 
@@ -1997,6 +2020,7 @@ public class LoggingAuditTrailTests extends ESTestCase {
         restOrTransportOrigin(request, threadContext, checkedFields);
         restOrTransportOrigin(request, threadContext, checkedFields);
         indicesRequest(request, checkedFields, checkedArrayFields);
         indicesRequest(request, checkedFields, checkedArrayFields);
         opaqueId(threadContext, checkedFields);
         opaqueId(threadContext, checkedFields);
+        traceId(threadContext, checkedFields);
         forwardedFor(threadContext, checkedFields);
         forwardedFor(threadContext, checkedFields);
         assertMsg(logger, checkedFields.map(), checkedArrayFields.map());
         assertMsg(logger, checkedFields.map(), checkedArrayFields.map());
 
 
@@ -2028,6 +2052,7 @@ public class LoggingAuditTrailTests extends ESTestCase {
             .put(LoggingAuditTrail.TRANSPORT_PROFILE_FIELD_NAME, profile)
             .put(LoggingAuditTrail.TRANSPORT_PROFILE_FIELD_NAME, profile)
             .put(LoggingAuditTrail.RULE_FIELD_NAME, "deny _all");
             .put(LoggingAuditTrail.RULE_FIELD_NAME, "deny _all");
         opaqueId(threadContext, checkedFields);
         opaqueId(threadContext, checkedFields);
+        traceId(threadContext, checkedFields);
         forwardedFor(threadContext, checkedFields);
         forwardedFor(threadContext, checkedFields);
         assertMsg(logger, checkedFields.map());
         assertMsg(logger, checkedFields.map());
 
 
@@ -2066,6 +2091,7 @@ public class LoggingAuditTrailTests extends ESTestCase {
             .put(LoggingAuditTrail.TRANSPORT_PROFILE_FIELD_NAME, profile)
             .put(LoggingAuditTrail.TRANSPORT_PROFILE_FIELD_NAME, profile)
             .put(LoggingAuditTrail.RULE_FIELD_NAME, "allow default:accept_all");
             .put(LoggingAuditTrail.RULE_FIELD_NAME, "allow default:accept_all");
         opaqueId(threadContext, checkedFields);
         opaqueId(threadContext, checkedFields);
+        traceId(threadContext, checkedFields);
         forwardedFor(threadContext, checkedFields);
         forwardedFor(threadContext, checkedFields);
         assertMsg(logger, checkedFields.map());
         assertMsg(logger, checkedFields.map());
     }
     }
@@ -2097,6 +2123,7 @@ public class LoggingAuditTrailTests extends ESTestCase {
         restOrTransportOrigin(request, threadContext, checkedFields);
         restOrTransportOrigin(request, threadContext, checkedFields);
         indicesRequest(request, checkedFields, checkedArrayFields);
         indicesRequest(request, checkedFields, checkedArrayFields);
         opaqueId(threadContext, checkedFields);
         opaqueId(threadContext, checkedFields);
+        traceId(threadContext, checkedFields);
         forwardedFor(threadContext, checkedFields);
         forwardedFor(threadContext, checkedFields);
         assertMsg(logger, checkedFields.map(), checkedArrayFields.map());
         assertMsg(logger, checkedFields.map(), checkedArrayFields.map());
 
 
@@ -2134,6 +2161,7 @@ public class LoggingAuditTrailTests extends ESTestCase {
         restOrTransportOrigin(request, threadContext, checkedFields);
         restOrTransportOrigin(request, threadContext, checkedFields);
         indicesRequest(request, checkedFields, checkedArrayFields);
         indicesRequest(request, checkedFields, checkedArrayFields);
         opaqueId(threadContext, checkedFields);
         opaqueId(threadContext, checkedFields);
+        traceId(threadContext, checkedFields);
         forwardedFor(threadContext, checkedFields);
         forwardedFor(threadContext, checkedFields);
         assertMsg(logger, checkedFields.map(), checkedArrayFields.map());
         assertMsg(logger, checkedFields.map(), checkedArrayFields.map());
 
 
@@ -2185,6 +2213,7 @@ public class LoggingAuditTrailTests extends ESTestCase {
         }
         }
         authentication(authentication, checkedFields);
         authentication(authentication, checkedFields);
         opaqueId(threadContext, checkedFields);
         opaqueId(threadContext, checkedFields);
+        traceId(threadContext, checkedFields);
         forwardedFor(threadContext, checkedFields);
         forwardedFor(threadContext, checkedFields);
         assertMsg(logger, checkedFields.map());
         assertMsg(logger, checkedFields.map());
 
 
@@ -2210,6 +2239,7 @@ public class LoggingAuditTrailTests extends ESTestCase {
         }
         }
         authentication(authentication, checkedFields);
         authentication(authentication, checkedFields);
         opaqueId(threadContext, checkedFields);
         opaqueId(threadContext, checkedFields);
+        traceId(threadContext, checkedFields);
         forwardedFor(threadContext, checkedFields);
         forwardedFor(threadContext, checkedFields);
         assertMsg(logger, checkedFields.map());
         assertMsg(logger, checkedFields.map());
     }
     }
@@ -2238,6 +2268,7 @@ public class LoggingAuditTrailTests extends ESTestCase {
         restOrTransportOrigin(request, threadContext, checkedFields);
         restOrTransportOrigin(request, threadContext, checkedFields);
         indicesRequest(request, checkedFields, checkedArrayFields);
         indicesRequest(request, checkedFields, checkedArrayFields);
         opaqueId(threadContext, checkedFields);
         opaqueId(threadContext, checkedFields);
+        traceId(threadContext, checkedFields);
         forwardedFor(threadContext, checkedFields);
         forwardedFor(threadContext, checkedFields);
         assertMsg(logger, checkedFields.map(), checkedArrayFields.map());
         assertMsg(logger, checkedFields.map(), checkedArrayFields.map());
 
 
@@ -2257,6 +2288,7 @@ public class LoggingAuditTrailTests extends ESTestCase {
         restOrTransportOrigin(request, threadContext, checkedFields);
         restOrTransportOrigin(request, threadContext, checkedFields);
         indicesRequest(request, checkedFields, checkedArrayFields);
         indicesRequest(request, checkedFields, checkedArrayFields);
         opaqueId(threadContext, checkedFields);
         opaqueId(threadContext, checkedFields);
+        traceId(threadContext, checkedFields);
         forwardedFor(threadContext, checkedFields);
         forwardedFor(threadContext, checkedFields);
         assertMsg(logger, checkedFields.map(), checkedArrayFields.map());
         assertMsg(logger, checkedFields.map(), checkedArrayFields.map());
     }
     }
@@ -2664,16 +2696,31 @@ public class LoggingAuditTrailTests extends ESTestCase {
     }
     }
 
 
     private static void opaqueId(ThreadContext threadContext, MapBuilder<String, String> checkedFields) {
     private static void opaqueId(ThreadContext threadContext, MapBuilder<String, String> checkedFields) {
-        final String opaqueId = threadContext.getHeader(Task.X_OPAQUE_ID_HTTP_HEADER);
-        if (opaqueId != null) {
-            checkedFields.put(LoggingAuditTrail.OPAQUE_ID_FIELD_NAME, opaqueId);
-        }
+        setFieldFromThreadContext(threadContext, checkedFields, Task.X_OPAQUE_ID_HTTP_HEADER, LoggingAuditTrail.OPAQUE_ID_FIELD_NAME);
+    }
+
+    private static void traceId(ThreadContext threadContext, MapBuilder<String, String> checkedFields) {
+        setFieldFromThreadContext(threadContext, checkedFields, Task.TRACE_ID, LoggingAuditTrail.TRACE_ID_FIELD_NAME);
     }
     }
 
 
     private static void forwardedFor(ThreadContext threadContext, MapBuilder<String, String> checkedFields) {
     private static void forwardedFor(ThreadContext threadContext, MapBuilder<String, String> checkedFields) {
-        final String forwardedFor = threadContext.getHeader(AuditTrail.X_FORWARDED_FOR_HEADER);
-        if (forwardedFor != null) {
-            checkedFields.put(LoggingAuditTrail.X_FORWARDED_FOR_FIELD_NAME, forwardedFor);
+        setFieldFromThreadContext(
+            threadContext,
+            checkedFields,
+            AuditTrail.X_FORWARDED_FOR_HEADER,
+            LoggingAuditTrail.X_FORWARDED_FOR_FIELD_NAME
+        );
+    }
+
+    private static void setFieldFromThreadContext(
+        ThreadContext threadContext,
+        MapBuilder<String, String> checkedFields,
+        String threadContextFieldName,
+        String logFieldName
+    ) {
+        final String value = threadContext.getHeader(threadContextFieldName);
+        if (value != null) {
+            checkedFields.put(logFieldName, value);
         }
         }
     }
     }