Audit Logging client library provides unified API for logging and processing audit events. It’s uses conventional logging frameworks to process audit events.
-
logback 1.x
To start using Audit Logging it is necessary to:
-
Add dependencies
-
Create a configuration file
-
Call the API
In most cases, the logs will be sent to LogStash which needs to have a special input configured (see Configuration section).
To start using Audit Logging client it’s necessary to add the next dependencies.
<dependency>
<groupId>org.talend.daikon</groupId>
<artifactId>audit-logback</artifactId>
<version>${audit.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
Audit Logging client uses simple properties file for all its configuration (in future, if needed, yaml-based configuration may be implemented). It looks for the configuration file in the next places (in given order):
-
Location specified in
talend.logging.audit.config
system property -
In classpath root, file named
audit.properties
Here is an example of the configuration file.
If audit events are to be sent to LogStash as in this example, it has to have an additional input in its configuration:
input { http { response_headers => { "Access-Control-Allow-Origin" => "*" "Access-Control-Allow-Headers" => "Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With" "Access-Control-Allow-Methods" => "*" "Access-Control-Allow-Credentials" => "*" } port => 8057 type => "Audit" codec => "json" } }
Note
|
Platform Service team provides LogServer with LogStash which is pre-configured for audit logging. |
HTTP appenders (logback) share the following configuration:
Property | Description | Default Value |
---|---|---|
|
Optional (but recommended) HTTP connection timeout. |
|
|
Number of core threads in async mode (recommended to align it with max value). |
|
|
Encoding used to create the basic token and content-type header, it is not used to encode the event. |
|
|
How long to keep idle threads up in ms. |
|
|
Number of max threads in async mode (recommended to align it with max value). |
|
|
Optional password (requires an username) for basic authentication. |
|
|
Thread pool queue size. If negative it will be infinite, if zero it will be blocking when no thread is available, otherwise it is the number of allowed stacked events. |
|
|
Optional (but recommended) HTTP read timeout. |
|
|
Should current configuration be overridable with system properties. If |
|
|
Target server URL where event are pushed to. |
|
|
Optional username (requires a password) for basic authentication. |
|
From applications perspective the basic use case is logging an audit event. If it’s one of the standard audit events, then all that is necessary to do is to create an instance of StandardEventAuditLogger using AuditLoggerFactory:
StandardEventAuditLogger auditLogger = AuditLoggerFactory.getEventAuditLogger(StandardEventAuditLogger.class);
...
auditLogger.loginSuccess();
This code logs audit message corresponding to login success event attaching values from MDC.
If application needs to pass context explicitly rather than via MDC it can be done like this:
StandardEventAuditLogger auditLogger = AuditLoggerFactory.getEventAuditLogger(StandardEventAuditLogger.class);
...
Context ctx = ContextBuilder.create("user", "testuser").build();
auditLogger.loginSuccess(ctx);
For details, see Context and ContextBuilder.
If there’s an exception associated with audit event it can be passed as a parameter (some events require an exception as a parameter, but basically it can be passed to any event):
StandardEventAuditLogger auditLogger = AuditLoggerFactory.getEventAuditLogger(StandardEventAuditLogger.class);
...
} catch (Exception e) {
Context ctx = ContextBuilder.create("user", "testuser").build();
auditLogger.loginFail(ctx, ex);
...
}
Of course the context parameter doesn’t have to be there.
If application needs to log events which are not part of StandardEventAuditLogger it can extend this interface with new events:
public interface CustomEventAuditLogger extends StandardEventAuditLogger {
@AuditEvent(category = "activity", message = "Flow has failed", level = LogLevel.WARNING)
void flowFailed(Object... args);
}
AuditEvent is an annotation which defines event metadata.
Category parameter allows to group all events into few groups. Usually events fall into three categories: security, activity, failure. But any application is free to specify any string value as a category.
Log level is similar to the same concept from normal logging frameworks, but only has three values: INFO, WARNING or ERROR.
After defining new event the app needs to obtain an instance of this interface using the same factory method:
CustomEventAuditLogger auditLogger = AuditLoggerFactory.getEventAuditLogger(CustomEventAuditLogger.class);
...
Context ctx = ContextBuilder.create("flowId", "1234").build();
auditLogger.flowFailed(ctx);
We have defined in the AuditEvent the MDC common keys fields, all apps must use those keys for those actions {operation, resource, result} on user:
public interface CustomClass {
MDC.put(EventFields.USER, "user0");
MDC.put(EventFields.OPERATION, "create user");
MDC.put(EventFields.RESOURCE, "user");
MDC.put(EventFields.RESULT, "success");
...
}
For exceptional cases an application may log audit messages similarly to normal logging frameworks:
AuditLogger auditLogger = AuditLoggerFactory.getAuditLogger();
...
auditLogger.warning("security", "Account has been locked");
First parameter is audit event category. As with event APIs, a context and/or an exception may be passed as parameters.
If audit logging needs to be deactivated for some reason, it can be done by changing the configuration:
log.appender=none
Note
|
If application is running it needs to be restarted for this change to take effect. |
It is possible for an AbstractBackend
to disable log messages if it doesn’t need it (e.g. performance consideration).
To do that, the implementation of the AbstractBackend
have to override the method enableMessageFormat
in order to return false
(default value is true
- backward compatibility considerations).