# Audit

Documentation owner: module `audit`; documentation version: `2026.117`.
Source: `content/modules/audit/2026.117/README.mdx` at commit `eaf7a020437971baeee95e87eaf963636040ac71`.

## Introduction

The Audit module receives audit events from internal clients (LdapClient, EntraID, JdbcClient) and persists them to a configurable storage backend. It provides a tamper-evident record of all data changes performed by users via pipes.

Audit events are published to an internal event bus address. The module subscribes to this address and writes each event through the configured writer. Failed writes are logged as warnings but do not fail the originating operation.

## Configuration

:::note
**Module name:** `AuditModule`
:::

### Properties

| Name | Description | Default | Mandatory |
| --- | --- | --- | --- |
| `writer` | Storage backend. One of: `jsonlines`, `stdout`, `logger` | `jsonlines` | No |
| `path` | File path for JSON Lines output. Required when `writer` is `jsonlines`. |  | Yes |

### Example

```json
{
  "name": "AuditModule",
  "config": {
    "writer": "jsonlines",
    "path": "/var/log/fortified/audit.jsonl"
  }
}
```

### Writers

| Writer      | Description                                                                            |
| ----------- | -------------------------------------------------------------------------------------- |
| `jsonlines` | Appends one JSON event per line to the configured file path. Default.                  |
| `stdout`    | Writes JSON events to standard output. Useful for container environments.              |
| `logger`    | Writes events through the platform logger at INFO level under the `AUDIT` logger name. |

:::caution
**Logger writer: log4j2 configuration required**

The `logger` writer logs at INFO level under the named logger `AUDIT`. The default `log4j2.xml` shipped with the server does not include an entry for this logger, so events fall through to the Root logger (level `WARN`) and are silently suppressed.

Add the following entry to `config/log4j2.xml` to enable output:

```xml
<AsyncLogger name="AUDIT" level="INFO"/>
```

This is especially important in Docker-based deployments where audit visibility relies on container log output.
:::

## Log format

Events are stored as JSON Lines — one JSON object per line. Each event includes:

| Field            | Type     | Description                                                        |
| ---------------- | -------- | ------------------------------------------------------------------ |
| `timestamp`      | ISO-8601 | When the operation occurred                                        |
| `correlation_id` | string   | Trace ID from the originating request                              |
| `operation`      | string   | One of: `create`, `read`, `update`, `delete`, `search`             |
| `client_type`    | string   | Client that performed the operation (e.g. `ldap`, `entra`, `jdbc`) |
| `data_source`    | string   | Target data source name                                            |
| `entity_type`    | string   | Type of object affected                                            |
| `entity_id`      | string   | Identifier of the affected object                                  |
| `principal`      | object   | Acting principal with `subject` and optional `attributes` fields   |
| `pipe`           | string   | Name of the pipe that initiated the operation                      |
| `changes`        | array    | Changed values represented by `name`, `action`, and `value`        |

### Example event

```json
{"timestamp":"2026-04-14T10:23:01.452Z","correlation_id":"a1b2c3","operation":"update","client_type":"ldap","data_source":"default","entity_type":"inetOrgPerson","entity_id":"uid=alice,ou=users,dc=example,dc=com","principal":{"subject":"admin@example.com","attributes":{"role":"operator"}},"pipe":"update-user","changes":[{"name":"mail","action":"replace","value":"alice@example.com"}]}
```

## Per-client audit configuration

Each client module that supports audit logging accepts an `audit` block in its configuration. All flags default to `false`.

### LdapClient

```json
"audit": {
  "create": true,
  "update": true,
  "delete": true
}
```

### EntraID

```json
"audit": {
  "create": true,
  "update": true,
  "delete": true
}
```

### JdbcClient

```json
"audit": {
  "create": true,
  "update": true,
  "delete": true,
  "read": true
}
```

## AuditContext

Callers pass an `AuditContext` alongside operations to supply principal identity and correlation context.

| Field        | Description                                                                          |
| ------------ | ------------------------------------------------------------------------------------ |
| `traceId`    | Correlation ID, reused from the existing `trace_id` concept                          |
| `subject`    | Identity of the acting principal (e.g. `user@example.com`). Defaults to `anonymous`. |
| `attributes` | Additional principal attributes (e.g. role, tenant)                                  |

The platform resolves `AuditContext` in this priority order:

1. Explicit `AuditContext` passed by the caller
2. Context derived from the current session
3. Default: `anonymous` principal with the current trace ID
