# Audit trail

This page describes how to set up an audit trail, a feature available in Aerospike Enterprise Edition (EE), and Federal Edition (FE).

## Audit logging system

_Audit logs_ are specialized log files that receive only security- or compliance-related events specified in the log stream. They are designed for security, compliance, and accountability. They track specific, user-centric activities that are critical to an organization’s security posture and regulatory requirements. These logs provide a detailed, chronological record of who did what, where, and when, making them a crucial tool for forensic analysis and legal defense.

An _audit trail_ is the complete chronological sequence of records that shows how a system, process, or resource was accessed and changed over time. It is the end-to-end history of activities, pieced together from audit logs. Audit logs are raw entries, individual events. The audit trail is the organized timeline that lets you reconstruct what actually happened.

For example:

-   Audit logs might record individual entries like _userX_ logged in, _userX_ deleted file A, _userX_ logged out.
-   The audit trail is the storyline built from these logs: _On Sept 9 at 10:12, userX logged in from IP 1.2.3.4, deleted file A at 10:13, and logged out at 10:15._

The following diagram shows the entire audit logging process in the Aerospike logging framework:

 ![Audit logging pipeline](https://aerospike.com/docs/_astro/audit_pipeline.CtFgawkE_20xyQi.png)

Figure 1: Aerospike logging pipeline

1.  The system generates a logged event.
2.  Events are aggregated into a log stream, which is the live, in-memory sequence of logs.
3.  From the stream, events are dispatched to one or more log sinks. Audit trail messages can be logged to a file, a console, or syslog.
4.  The audit log is available for analysis.

### Best practice configuration setup

The following configuration illustrates best practices for setting up an audit log. Audit trail messages can be sent to any type of supported log sink such as `file`, `console`, or `syslog`. Key configuration features include:

-   Security enabled: audit logging is enabled when security is in use. See [Enable access control](https://aerospike.com/docs/database/manage/security/rbac/#enable-access-control).
-   [File sink](https://aerospike.com/docs/database/reference/config#logging__file): Writes to `/var/log/aerospike/audit.log` for local inspection.
-   [Syslog sink](https://aerospike.com/docs/database/reference/config#logging__syslog): Forwards to your syslog daemon for aggregation/monitoring (SIEM-friendly).
-   [Console sink](https://aerospike.com/docs/database/reference/config#logging__console) (optional): Helpful if running Aerospike in Docker/Kubernetes where stdout is aggregated.
-   [Logging context](https://aerospike.com/docs/database/manage/logging/logs#logging-contexts): Specifies the server module where the log messages originated, such as `tls`, `drv_ssd`, or `fabric`.
-   [Severity level](https://aerospike.com/docs/database/manage/logging/logs#severity-level-details): Determines how much information is logged.

```plaintext
# =============================

# Aerospike audit logging setup

# =============================

service {

    # Other service-level settings...

}

security {

   # Other security-level settings...

}

logging {

    # Local file sink for audit logs

    file /var/log/aerospike/audit.log {

        context audit info           # Capture audit events at info+ level

    }

    # Syslog sink for centralized monitoring

    syslog {

        facility local0

        tag aerospike-audit

        context audit info           # Send only audit events

    }

    # Console sink (optional, useful in containers)

    console {

        context audit info

    }

}
```

## Required roles and permissions

To configure or view audit logs, you must have the appropriate roles and permissions.

### Role and permission to dynamically configure audit logging

To _set up_ or _change_ which events are logged to the audit trail, you need a high-level administrative role on the Aerospike cluster.

Required role or privilege: `sys-admin` (or a custom role with equivalent global configuration privileges). This privilege is required to:

-   Configure which events are logged to the audit trail.
    
-   Configure a syslog log sink in the logging section to ship the audit data.
    

### Roles and permission to view or read audit logs

Once the audit log is configured, the logs are written as files on the server or shipped via the `syslog` protocol to an external system. Viewing these logs is a matter of Operating System (OS) permissions or Log Management System access, not Aerospike database access control.

-   For instructions about how to add and configure Aerospike filtering and parsing rules for supported 3rd-party log ingestion tools, see [3rd-party log analysis tools](https://aerospike.com/docs/database/observe/log-analysis/#_top).

## Set up audit logging

The following steps demonstrate how to set up a logging pipeline to create files you can use for an audit trail.

Before editing the configuration file, `aerospike.conf`, decide the following:

-   What do you need to audit?
    -   Do you care about all security-related events, like user creation, role grants, and authentication attempts?
    -   Do you want to limit logging to specific event types, like failed logins or privilege changes?
-   Which log sinks do you need?
    -   Local file (default: /var/log/aerospike/audit.log)
    -   Syslog (centralized logging, often used in production for security monitoring)
    -   Console (useful for containers or testing environments)
-   What are your retention and compliance requirements?
    -   How long do you need to keep audit logs?
    -   Do you need to rotate logs or prepare for secure archival?
-   Do you need to consider performance implications?
    -   Audit logging adds overhead. Audit logging by default is less verbose, using configurations like [report-data-op](https://aerospike.com/docs/database/reference/config#security__report-data-op) logs more information but can impact performance.
    -   Do audit logs need to be stored locally, shipped off-cluster, or both?

1.  Enable audit logging.
    
    Audit logging is enabled automatically when the security configuration section is used.
    
    ```plaintext
    security {
    
    }
    ```
    
2.  Add the event types you want to audit.
    
    You can filter audit events by type. In the following example, the `log` subsection defines the events you want to audit.
    
    ```plaintext
    security {
    
        log {
    
            report-authentication true # report successful authentication and login attempts.
    
            report-user-admin true # report successful user admin operations.
    
            report-sys-admin true # report operations made with the sys-admin permission.
    
            report-violation true # report operations failed due to violating security checks e.g. permissions, quotas, authentication, etc.
    
            report-data-op test demoset # report successful data transactions on set "demoset" in namespace "test"
    
        }
    
    }
    ```
    
3.  Integrate with logging system.
    
    You can send Aerospike audit logs to one or more destinations, according to your specific requirements. The following example sends audit logs to both a file and syslog.
    
    -   `context audit info` ensures only audit events at `info` severity level and above are captured.
    -   The `audit` context log messages are sent to the local0 syslog facility and tagged with “aerospike-audit.”
    
    ```plaintext
    logging {
    
       file /var/log/aerospike/audit.log {
    
           context audit info
    
       }
    
       syslog {
    
           facility local0
    
           tag aerospike-audit
    
           context audit info
    
       }
    
    }
    ```
    
4.  Secure the audit logs.
    
    -   Set restrictive permissions (`chmod 600`) so only Aerospike or security admins can read audit logs.
    -   If using syslog, verify that TLS or secure forwarding is in place.
    -   Consider rotating logs daily with [`logrotate`](https://aerospike.com/docs/database/manage/logging/rotation/).
5.  Activate your changes with a [rolling restart](https://aerospike.com/docs/database/manage/cluster/quiesce-node/#rolling-upgrade-procedure), and verify audit logging.
    
    1.  Run a simple admin action, such as creating a test user and role with the following command.
        
        ```plaintext
        aql -c "create user audit_test password pass roles read"
        ```
        
    2.  Check your audit log (`/var/log/aerospike/audit.log`) or syslog for the event.
        
    3.  Confirm the format (JSON-like structured events) matches what your SIEM or monitoring system expects.
        

::: note
Prior to Database 6.3.0, you log to syslog with the following configuration:

```plaintext
security {

    syslog {

        local 0 # write to "local0" facility

        # write audit trail messages to the default syslog facility

        report-authentication true

        report-user-admin true

        report-sys-admin true

        report-violation true

        report-data-op test demoset # report successful data transactions on set "demoset" in namespace "test"

    }

}
```
:::

## Log lines

Aerospike log lines contain default information followed by detailed audit trail entries when those entries are present.

### Default log line

Each Aerospike log line starts with the following elements:

`DATE-TIME: LOG-LEVEL (LOGGING-CONTEXT): (FILE:LINE) MESSAGE`

The date-time substring has the [strftime](https://www.man7.org/linux/man-pages/man3/strftime.3.html) format `%b %d %Y %T %Z`.

-   Aerospike sends regular log lines when an event occurs.
-   Ticker log lines are printed at regular intervals defined by [`ticker-interval`](https://aerospike.com/docs/database/reference/config/#service__ticker-interval), which is 10 seconds by default. Ticker log lines contain everything that occurred during the previous interval, and they can be identified by the `ticker.c` entry that follows the logging context.

For example:

```plaintext
Jul 25 2025 01:11:31 GMT: INFO (info): (ticker.c:577) {test} data-usage: used-bytes 0 avail-pct 99 cache-read-pct 0.00

Jul 25 2025 01:11:36 GMT: INFO (drv_ssd): (drv_ssd.c:2128) {test} /opt/aerospike/data/test.dat: used-bytes 0 free-wblocks 511 write-q 0 write (0,0.0) defrag-q 0 defrag-read (0,0.0) defrag-write (0,0.0)
```

The [Database log reference](https://aerospike.com/docs/database/reference/logs) describes many log lines in detail.

### Detailed audit log entries

Audit log messages have the following format:

```plaintext
RESULT_TAG | client: CLIENT_IP:PORT: | authenticated user: USERNAME | action: ACTION_TAG | detail: DETAIL_STRING
```

Each placeholder contains specific information about the event, as described in the following tables. It is important to understand these components so you can interpret audit logs effectively.

#### _RESULT\_TAG_ placeholder descriptions

| `RESULT_TAG` (log string) | Description |
| --- | --- |
| [`permitted`](https://aerospike.com/docs/database/reference/logs#security__584953753) | Requested operation or access was allowed by the security policies. |
| `not authenticated` | Session or connection has not been authenticated, or authentication is missing or invalid. |
| [`role violation`](https://aerospike.com/docs/database/reference/logs#security__186298844) | Authenticated user does not have the necessary roles or permissions for the requested operation. |
| `not whitelisted` | Client’s IP address is not on the allowlist for the user’s roles. |
| `quota exceeded` | User or role has exceeded their allocated transaction (read/write) quota. |
| [`forbidden password`](https://aerospike.com/docs/database/reference/logs#security__610794822) | User tried to set a password to one that was recently used, or tried to set a password on a _nopassword_ PKI user. |
| [`authentication failed (user)`](https://aerospike.com/docs/database/reference/logs#security__1430509598) | Authentication failed, typically because the specified user was not found or is invalid. |
| [`authentication failed (credential)`](https://aerospike.com/docs/database/reference/logs#security__610794822) | Authentication failed due to an invalid or incorrect credential, such as a password or token. |
| [`authentication failed (password)`](https://aerospike.com/docs/database/reference/logs#security__610794822) | Authentication failed, specifically due to an incorrect password. |
| `authentication failed (session expired)` | Authentication failed because the provided session token has expired. |
| `LDAP not configured` | LDAP authentication failed because LDAP is not configured on the server. |
| `LDAP setup failed` | LDAP authentication failed due to an issue during the LDAP setup or initialization. |
| `LDAP TLS setup failed` | LDAP authentication failed due to an error in setting up the TLS connection for LDAP. |
| `LDAP authentication failed` | LDAP authentication failed because of incorrect LDAP credentials, or user not found in LDAP. |
| `LDAP role query failed` | After successful LDAP authentication, the query to retrieve the user’s roles from LDAP failed. |
| `UNEXPECTED RESULT` | Undefined or unexpected result code was encountered. |

#### _client_ placeholder descriptions

_client_ is normally the IP address and port of the client attempting the operation that generated the log statement.

| `client` | Description |
| --- | --- |
| `CLIENT_IP:PORT` | This is the most common event information, used when the connecting client is known. |
| `UNKNOWN` | The literal value `UNKNOWN` may be used if the client is unknown. |
| `N/A` | The literal value `N/A` is used when the client connection is not relevant to the logged event. For example, when user-based quota usage is periodically logged. |

#### _authenticated user_ placeholder descriptions

_authenticated user_ is usually the username that attempted the operation triggering the log.

| `authenticated user` | Description |
| --- | --- |
| `USERNAME` | Username of the user that triggered the log. |
| `NONE` | The literal value `NONE` is used if the user is not known or unauthenticated. |

#### _action_ placeholder descriptions

_action_ describes the event, such as a command or operation, that triggered the log.

| `action` | Description | Associated command |
| --- | --- | --- |
| `authentication` | used when authentication fails or succeeds |  |
| `info request` | Logs failed authentication events for info requests | Any info command that fails authentication |
| `login` | used when a login fails or succeeds |  |
| `INFO_COMMAND_NAME` | Name of the info command triggering the log. Can be any entry in the [Info command reference](https://aerospike.com/docs/database/reference/info) | Any info command |
| `write` | used for write operations including expression writes and masked-write violations | `writes` / `exp write` |
| `replace` | record replace operations, including masked-replace violations | `writes` |
| `modify` | used when modifying a bin, including masked-modify violations | `modify` |
| `delete` | used for record deletes, bin deletes, and delete\_all operations; also used for masked-delete violations | delete, delete\_all |
| `udf apply` | used when a UDF is applied to a record; also used for masked UDF operation violations | `apply` |
| `query` | used for queries | `query` |
| `udf query` | used for queries with UDFs | `query` |
| `masking` | used when a masking rule is created, updated, or deleted or when masking rules are displayed | `masking`, `masking-show` |
| `UNEXPECTED ACTION` | The literal value `UNEXPECTED ACTION`. used when an invalid action is encountered internally |  |

#### _detail_ placeholder description

`detail` varies according to the type of operation that generated the log. The following sections describe the possible formats of _detail_.

##### Data operations

used with read, write, delete, and query operations.

```plaintext
{NAMESPACE|SET_NAME} [I|INTEGER_KEY_VAL]

{NAMESPACE|SET_NAME} [S|STRING_KEY_VAL]

{NAMESPACE|SET_NAME} [B|HEX_KEY_VAL]

{NAMESPACE|SET_NAME} [?|HEX_KEY_VAL]

{NAMESPACE|SET_NAME} [D|HEX_DIGEST_VAL]

{NAMESPACE|SET_NAME} (if no key/digest string can be formed)

example: {ns1|set1} [S|key1]
```

##### Quotas

When the audit trail logs an exceeded quota, the detail string hold throughput information for the job that exceeded that quota. Example: `rps=800,read-quota=400`

| Format | Description |
| --- | --- |
| `NONE` | Literal value `NONE` used when called from `as_security_check_rps` and the user is not authenticated. |
| `rps=RPS_OF_THE_JOB,write-quota=WRITE_QUOTA` | used when a write quota is exceeded by a query, both values are unsigned integers in decimal format |
| `rps=RPS_OF_THE_JOB,read-quota=read_quota_QUOTA` | used when a read quota is exceeded by a query, both values are unsigned integers in decimal format |
| `quota=RPS` | used when a quota is violated by an operation. `rps` is an unsigned integer |

##### Info requests and commands

When an info command fails to authenticate, the detail string is the literal value `NONE`. Otherwise the detail string is the info command as it was received by the server. For example: `bins/test` for the [bins command in the Info command reference](https://aerospike.com/docs/database/reference/info#bins)

##### Login logging

When the audit trail logs a login, detail displays the username that logged in.

Format: `user=USERNAME[;roles=ROLE,...]` Example: `user=bobby;roles=user-admin,data-admin`

##### Auth and user admin commands

In the case of auth failure (`log_auth_failure`), auth success (`log_auth_success`), and user-admin commands (`log_user_admin`), detail displays information about the user affected.

General format: `[user=USERNAME;][roles=ROLE,...;][role=ROLE;][privs=PERM_CODE_TAG[{NAMESPACE[|SET_NAME]}],...;][whitelist=VALUE;][read-quota=UINT32_VALUE;][write-quota=UINT32_VALUE]`

| Component | Format/Description | Notes |
| --- | --- | --- |
| Overall | Concatenation of following components, semicolon-separated | Each \[…\] part is optional and only appears if the corresponding field is present in the request. Trailing semicolon is removed. |
| `user` | `user=USERNAME` | Username from the request. |
| `roles` | `roles=ROLE1,ROLE2,...` | Comma-separated list of roles. |
|  | `roles=NONE` | If no roles are specified or applicable. `NONE` is a literal value, not replaced. |
|  | `roles=PARSE ERROR` | If parsing of roles fails. `PARSE ERROR` is a literal value, not replaced. |
| `role` | `role=ROLE_NAME` | Single role name. |
| `privs` | `privs=PRIV_STR1,PRIV_STR2,...` | Comma-separated list of privileges. |
| `priv_str` | `PERM_CODE_TAG[{NAMESPACE[|SET_NAME]}]` | Format for an individual privilege string. |
| `PERM_CODE_TAG` | Short string such as `u`, `r`, `w` | Represents the permission code from `perm_code_tag()`. Possible perm codes are defined in the definition of the `perm_code_tag` function in the reference information section. |
| Scope | `{NAMESPACE[|SET_NAME]}` | Optional scope: namespace, and possibly set name |
| `whitelist` | `whitelist=WHITELIST_STR` | Whitelist string |
| `read-quota` | `read-quota=QUOTA_VAL` | Read quota value (unsigned integer) |
| `write-quota` | `write-quota=QUOTA_VAL` | Write quota value (unsigned integer) |

Example detail string:

```plaintext
user=bob;privs=u{NAMESPACE1\|SET1},w{NAMESPACE2\|SET2};read-quota=300
```

##### Masking operations

When masking rules are created, modified, or deleted, the detail string includes information about the masking rule:

Format: `ns=NAMESPACE;set=SET;bin=BIN;type=string;function=FUNCTION_TYPE;value=VALUE;position=POSITION;length=LENGTH`

Acceptable values are the printable ASCII characters 33-126 excluding `=`,`;`, and `:`. If violated, some Aerospike features and tools may not function properly.

| Component | Format/Description | Notes |
| --- | --- | --- |
| `ns` | `ns=NAMESPACE` | Namespace where the masking rule applies |
| `set` | `set=SET` | Set where the masking rule applies |
| `bin` | `bin=BIN` | Bin where the masking rule applies |
| `type` | `type=string` | Data type (always `string` for masking rules) |
| `function` | `function=redact` supports value, position and length. `function=constant` supports value | Masking function type |
| `value` | `value=VALUE` | Replacement character for redaction (default `*`) or constant value |
| `position` | `position=POSITION` | Start position for redaction (integer, negative for counting from end) |
| `length` | `length=LENGTH` | Number of characters to mask (optional, omitted if masking to end) |

**Example detail strings:**

```plaintext
ns=banking;set=customers;bin=ssn;type=string;function=redact;value=*;position=0;length=7

ns=banking;set=customers;bin=email;type=string;function=constant;value=redacted@example.com
```

When unauthorized users attempt to modify or read masked bins, the detail string includes information about the violation. For example, `masking: blocked modifying masked bin:'BIN_NAME'` or `masking: blocked deleting masked bin:'BIN_NAME'`.

**Example: Successfully add or drop a masking rule**

When a user with the masking-admin privilege adds or drops a masking rule it gets logged in the audit context.

```text
Oct 02 2025 16:34:48 GMT: INFO (audit): (security.c:7583) permitted | client: 127.0.0.1:54122 | authenticated user: bob | action: masking | detail: ns=test;set=users;bin=ssn;type=string;function=remove

Oct 02 2025 16:34:48 GMT: INFO (audit): (security.c:7583) permitted | client: 127.0.0.1:54122 | authenticated user: bob | action: masking | detail: ns=test;set=users;bin=ssn;type=string;function=redact;value=*;position=-4
```

**Example: Unauthorized attempt to add or drop a masking rule**

```text
Oct 08 2025 02:53:26 GMT: INFO (audit): (security.c:7583) role violation | client: 127.0.0.1:35488 | authenticated user: dave | action: masking | detail: namespace=test;set=users;bin=ssn;type=string;function=remove
```

**Example: Failed attempt to write a masked bin**

When a user attempts to change the contents of a masked bin without write-masked permissions, the write is blocked:

-   Returns an error code `81 ROLE_VIOLATION`
    
    Example in the C client:
    
    ```text
    81, '127.0.0.1:3000 AEROSPIKE_ROLE_VIOLATION', 'src/main/aerospike/as_command.c', 1710, False
    ```
    
-   Logs the role violation to the audit log
    
    ```text
    Oct 02 2025 16:44:30 GMT: INFO (audit): (security.c:7583) role violation | client: 127.0.0.1:58914 | authenticated user: alice | action: delete | detail: masking: blocked deleting masked bin:'age'
    
    Oct 02 2025 16:44:35 GMT: INFO (audit): (security.c:7583) role violation | client: 127.0.0.1:52380 | authenticated user: alice | action: modify | detail: masking: blocked modifying masked bin:'age'
    
    Oct 02 2025 16:50:05 GMT: INFO (audit): (security.c:7583) role violation | client: 127.0.0.1:56890 | authenticated user: bob | action: replace | detail: masking: blocked replacing masked bin:'ssn'
    
    Oct 02 2025 16:50:08 GMT: INFO (audit): (security.c:7583) role violation | client: 127.0.0.1:57034 | authenticated user: alice | action: udf apply | detail: masking: blocked operation on masked bin:'ssn'
    ```
    

### Parsing audit log messages

Log messages are plain text descriptions of attempted security actions, whether or not the action succeeded, and any user that was involved.

Namespaces and sets are in braces: `{NAMESPACE|SET}` or just `{NAMESPACE}`

Custom role privileges are letter codes that correspond to Aerospike pre-defined privileges, and are followed by `{NAMESPACE|SET}` scoping if applicable.

The letter codes are:

-   `r` = read
-   `rw` = read-write
-   `rwf` = read-write-udf
-   `t` = truncate
-   `w` = write
-   `d` = data-admin (a global privilege, scoping not applicable).
-   `fa` = udf-admin (a global privilege, scoping not applicable).
-   `ia` = sindex-admin (a global privilege, scoping not applicable).
-   `s` = sys-admin (a global privilege, scoping not applicable).
-   `u` = user-admin (a global privilege, scoping not applicable).
-   `ma` = masking-admin (a global privilege, scoping not applicable).
-   `rm` = read-masked (can be scoped to namespace or set).
-   `wm` = write-masked (can be scoped to namespace or set).

For example:

-   `rw{}` indicates read-write privileges across all namespaces.
-   `r{test},rw{ns2}` indicates read privileges for the `test` namespace and read-write privileges for the `ns2` namespace.
-   `u,rwf{test|demoset}` indicates user-admin privileges as well as read-write-udf privileges for `demoset` in the `test` namespace.

If the key is stored, key data is logged with successfully-authenticated data transactions and data transactions that fail due to role violations. If the key is not stored, the digest is logged. The eventual success or failure of the transaction does not affect this behavior, since logging happens at the point at which authentication is checked.

Stored key data appears as follows:

-   `[S|mykey]` if the key is a string.
-   `[I|78654]` if the key is an integer.
-   `[B|AA C5 48]` if the key is a blob of bytes.

If the key is not stored, the digest is logged as a string:

-   `[D|567895f996dd7dd3832222b57cd4a3031ecc6e24]`

Example audit trail output, logging context is 'audit'

```text
Sep 01 2021 18:37:56 GMT: INFO (audit): (security.c:7608) permitted | client: 127.0.0.1:51378 | authenticated user: user2 | action: login | detail: user=user2

Sep 01 2021 18:37:56 GMT: INFO (audit): (security.c:7608) permitted | client: 127.0.0.1:51380 | authenticated user: user2 | action: authentication | detail: user=user2

Sep 01 2021 18:37:56 GMT: INFO (audit): (security.c:7608) permitted | client: 127.0.0.1:51380 | authenticated user: user2 | action: read | detail: {test|eg-set} [D|1142f0217ababf9fda5b1a4de66e6e8d4e51765e]
```