You're viewing version 3.8 of the OpenSearch documentation. This version is no longer maintained. For the latest version, see the current documentation. For information about OpenSearch version maintenance, see Release Schedule and Maintenance Policy.
Audit logs
Table of contents
Audit logs let you track access to your OpenSearch cluster and are useful for compliance purposes or in the aftermath of a security breach. You can configure the categories to be logged, the detail level of the logged messages, and where to store the logs.
OpenSearch supports two audit logging modes. The following table describes each mode and how it is configured.
| Mode | Requirements | Configuration |
|---|---|---|
| Standard (default) | The Security plugin with fine-grained access control (FGAC) enabled. | The audit.yml file in the security index and the REST API. |
| Standalone | No FGAC. Runs in SSL-only mode (plugins.security.ssl_only: true) or with security disabled (plugins.security.disabled: true). | opensearch.yml and dynamic cluster settings. |
For more information about standalone mode, see Standalone audit logging.
Enabling audit logging (standard mode)
Audit logging is disabled by default. To enable audit logging:
-
Add the following line to
opensearch.ymlon each node:plugins.security.audit.type: internal_opensearchThis setting stores audit logs on the current cluster. For other storage options, see Audit Log Storage Types.
-
Restart each node.
Audit logging requires two settings: a storage type (plugins.security.audit.type) in opensearch.yml and config.enabled: true in audit.yml. The audit.yml file provided by the Security plugin sets config.enabled to true by default, so audit logging can appear to be enabled in a new cluster. Until you specify a storage type, the Security plugin cannot create a storage endpoint for the audit log, so it does not record any events and logs a warning at startup that no default storage is available.
After this initial setup, you can use OpenSearch Dashboards to manage your audit log categories and other settings. In OpenSearch Dashboards, select Security and then Audit logs. Alternatively, you can specify settings for audit logging in the audit.yml and opensearch.yml files (which file depends on the setting—see Audit log settings). You can also use the Audit log APIs to manage and update settings.
Tracked events
Audit logging records events in two ways: HTTP requests (REST) and the transport layer. The following table provides descriptions of tracked events and whether or not they are logged on the REST or transport layer.
| Event | Logged on REST | Logged on transport | Description |
|---|---|---|---|
FAILED_LOGIN | Yes | Yes | The credentials of a request could not be validated, most likely because the user does not exist or the password is incorrect. |
AUTHENTICATED | Yes | Yes | A user successfully authenticated. |
MISSING_PRIVILEGES | No | Yes | The user does not have the required permissions to make the request. |
GRANTED_PRIVILEGES | No | Yes | A user made a successful request to OpenSearch. |
SSL_EXCEPTION | Yes | Yes | An attempt was made to access OpenSearch without a valid SSL/TLS certificate. |
opensearch_SECURITY_INDEX_ATTEMPT | No | Yes | An attempt was made to modify the Security plugin internal user and privileges index without the required permissions or TLS admin certificate. |
BAD_HEADERS | Yes | Yes | An attempt was made to spoof a request to OpenSearch with the Security plugin internal headers. |
CLUSTER_SETTINGS_CHANGED | No | Yes | A persistent or transient cluster setting was changed. Disabled by default. |
INDEX_SETTINGS_CHANGED | No | Yes | An index setting was changed. Disabled by default. |
REQUEST_AUDIT | Yes | Yes | A REST request was received and processed. Generated in standalone audit logging mode only. For more information about suppressing this event, see Suppressing REQUEST_AUDIT events. |
TRANSPORT_AUDIT | No | Yes | A transport-layer request was received on a node. Generated in standalone audit logging mode only. |
RESOURCE_ACCESS_GRANTED | No | Yes | Access to a shared resource was granted. Disabled by default. |
RESOURCE_ACCESS_DENIED | No | Yes | Access to a shared resource was denied. Disabled by default. |
RESOURCE_SHARING_CHANGED | No | Yes | A resource sharing configuration was changed. Disabled by default. |
REQUEST_AUDIT originates from a REST request (audit_request_origin: REST), but the event itself is recorded with audit_request_layer: TRANSPORT. As a result, it can be suppressed by any of disabled_categories, disabled_transport_categories, or disabled_rest_categories—adding REQUEST_AUDIT to any one of these settings suppresses the event.
Audit log settings
The following default log settings work well for most use cases. However, you can change settings to save storage space or adapt the information to your exact needs.
Settings in audit.yml
The following settings are stored in the audit.yml file.
Exclude categories
To exclude categories, list them in the following setting:
config:
audit:
disabled_rest_categories: <disabled categories>
disabled_transport_categories: <disabled categories>
For example:
config:
audit:
disabled_rest_categories:
- AUTHENTICATED
- GRANTED_PRIVILEGES
disabled_transport_categories: [ GRANTED_PRIVILEGES ]
Alternatively, you can use the unified disabled_categories setting to disable categories on both layers simultaneously:
config:
audit:
disabled_categories:
- AUTHENTICATED
- GRANTED_PRIVILEGES
When disabled_categories is configured alongside disabled_rest_categories or disabled_transport_categories, a category is disabled on a given layer if it appears in either the unified setting or the layer-specific setting.
A deprecation warning is logged when disabled_categories is configured alongside layer-specific settings, encouraging migration to disabled_categories only.
For example, the following configuration disables AUTHENTICATED on both layers (using disabled_categories) and disables SSL_EXCEPTION on the REST layer only:
config:
audit:
disabled_categories:
- AUTHENTICATED
disabled_rest_categories:
- SSL_EXCEPTION
By default, the CLUSTER_SETTINGS_CHANGED and INDEX_SETTINGS_CHANGED categories are disabled on the transport layer. To enable them, remove them from disabled_transport_categories:
config:
audit:
disabled_transport_categories:
- AUTHENTICATED
- GRANTED_PRIVILEGES
If you want to log events in all categories, use NONE:
config:
audit:
disabled_rest_categories: NONE
disabled_transport_categories: NONE
Disable REST or the transport layer
By default, the Security plugin logs events on both REST and the transport layer. You can disable either type:
config:
audit:
enable_rest: false
enable_transport: false
Disable request body logging
By default, the Security plugin includes the body of the request (if available) for both REST and the transport layer. If you do not want or need the request body, you can disable it:
config:
audit:
log_request_body: false
Log index names
By default, the Security plugin logs all indexes affected by a request. Because index names can be aliases and contain wildcards/date patterns, the Security plugin logs the index name that the user submitted and the actual index name to which it resolves.
For example, if you use an alias or a wildcard, the audit event might look like:
audit_trace_indices: [
"human*"
],
audit_trace_resolved_indices: [
"humanresources"
]
You can disable this feature by setting:
config:
audit:
resolve_indices: false
This feature is only disabled if config.audit.log_request_body is also set to false.
Configure bulk request handling
Bulk requests can contain many indexing operations. By default, the Security plugin only logs the single bulk request, not each individual operation.
The Security plugin can be configured to log each indexing operation as a separate event:
config:
audit:
resolve_bulk_requests: true
This change can create an extremely large number of events in the audit logs, so we don’t recommend enabling this setting if you frequently use the _bulk API.
Exclude requests
To exclude certain requests from being logged, configure actions for transport requests, HTTP request paths (REST), or both:
config:
audit:
ignore_requests: ["indices:data/read/*", "SearchRequest"]
Exclude users
By default, the Security plugin logs events from all users but excludes the internal OpenSearch Dashboards server user kibanaserver. You can exclude other users:
config:
audit:
ignore_users:
- kibanaserver
- admin
If requests from all users should be logged, use NONE:
config:
audit:
ignore_users: NONE
Exclude headers
You can exclude sensitive headers from being included in the logs—for example, the Authorization: header:
config:
audit:
exclude_sensitive_headers: true
Settings in opensearch.yml
The following settings are stored in the opensearch.yml file. How they are applied at runtime depends on the audit logging mode:
-
In standalone mode (SSL-only or security-disabled), most audit filter and compliance settings can be changed at runtime using the Cluster Settings API without a node restart. These settings include
log_request_body,resolve_indices,disabled_categories,enable_rest,enable_transport,ignore_users, andignore_requests. -
In standard mode with FGAC, the audit configuration is stored in
audit.yml, and the correspondingplugins.security.audit.config.*andplugins.security.audit.compliance.*cluster settings do not update it. APUT _cluster/settingsrequest can succeed without changing the audit configuration. Thebody_logging_exclusionssetting is the exception: in FGAC mode, you can update it using the Cluster Settings API.
Some audit settings are static and require a node restart: action_groups.<NAME>, log4j.enable_mdc_routing, config.index, the thread pool settings, and the sink connection settings.
Updating a dynamic audit setting requires a role listed in plugins.security.restapi.roles_enabled when FGAC is enabled. This restriction is not enforced in SSL-only or security-disabled mode. The body_logging_exclusions setting can be updated without the elevated role.
The following table describes the audit settings that a caller can read using GET _cluster/settings in each mode.
| Mode | Audit settings visible in settings responses |
|---|---|
| Standalone, SSL-only | Any caller can read the non-secret dynamic audit configuration (plugins.security.audit.config.* and plugins.security.audit.compliance.*). Credential-bearing sink settings remain hidden. |
| Standalone, security disabled | No plugins.security.audit.* settings are filtered, so sink credentials and PEM content may be visible. |
| FGAC | The entire plugins.security.audit.* subtree is filtered for all callers. This filtering is not role based. |
The plugins.security.audit.enabled runtime toggle applies only to standalone audit logging. See Standalone audit logging for instructions.
Exclude categories
You can configure disabled categories in opensearch.yml using the plugins.security.audit.config prefix. This is useful for non-FGAC modes (SSL-only or security-disabled), in which the audit.yml security index is not available:
plugins.security.audit.config.disabled_categories:
- AUTHENTICATED
- GRANTED_PRIVILEGES
The layer-specific settings disabled_rest_categories and disabled_transport_categories are deprecated. Use the unified disabled_categories setting instead.
The layer-specific settings are also available:
plugins.security.audit.config.disabled_rest_categories:
- AUTHENTICATED
- GRANTED_PRIVILEGES
plugins.security.audit.config.disabled_transport_categories:
- AUTHENTICATED
- GRANTED_PRIVILEGES
When both disabled_categories and the layer-specific settings are configured, a category is disabled on a given layer if it appears in either setting. A deprecation warning is also logged, recommending that you use disabled_categories only.
The disabled_categories settings suppress only REST and transport categories. They do not affect COMPLIANCE_* categories, which are governed solely by the compliance settings (compliance.enabled, the watched indexes and fields, and the compliance ignore-users settings).
Body logging exclusions
Use body_logging_exclusions to suppress request bodies for specific actions or REST paths while continuing to log bodies for all other requests. The log_request_body setting applies to every request, so it cannot exclude high-volume operations such as bulk ingestion selectively.
All expanded action-group patterns and raw exclusion patterns form a single combined wildcard matcher. For each audit layer, this matcher is tested against the corresponding identifier described in the following table. When a match is found, the request body field is omitted from the audit event. All other fields, such as the user, IP address, indexes, and timestamp, are preserved.
| Identifier | Description | Matched for |
|---|---|---|
| Transport action | The internal action name (for example, indices:data/write/bulk[s][p]). | Transport-layer audit events. |
| REST path | The HTTP request path (for example, /_bulk). REST paths always start with /. | REST-layer audit events. |
Both identifiers support wildcard patterns using * (for example, indices:data/write/bulk* matches indices:data/write/bulk[s][p]).
Configuring action groups
Action groups are named collections of action patterns, REST paths, or both, defined statically in opensearch.yml. You choose the group name, so use any name that is meaningful for your operations:
plugins.security.audit.config.action_groups.BULK: "indices:data/write/bulk*,/_bulk"
plugins.security.audit.config.action_groups.SEARCH: "indices:data/read/search*,/_search"
plugins.security.audit.config.action_groups.INDEX_ADMIN: "indices:admin/*"
Each action group maps a name to a comma-separated list of literal or wildcard patterns, such as indices:data/write/bulk*, /_bulk, or indices:data/write/*. All patterns use the same matcher; characters such as :, /, and * do not assign a pattern to a particular audit layer.
Action groups are static settings and require a node restart to change. The group names themselves are case-sensitive.
Configuring body logging exclusions
The body_logging_exclusions setting references action group names or raw patterns. To set the initial exclusions, configure the setting in opensearch.yml:
plugins.security.audit.config.body_logging_exclusions:
- BULK
The setting is dynamic, so you can also update the exclusions at runtime without restarting the cluster:
PUT _cluster/settings
{
"persistent": {
"plugins.security.audit.config.body_logging_exclusions": ["BULK", "SEARCH"]
}
}
Each entry in the list is processed as follows:
- If the entry matches a defined action group name, that group’s patterns are expanded.
- If it does not match any group name, the entry is treated as a raw pattern (literal or wildcard).
For entries that do not match a defined group name, a warning is logged if the entry contains no :, does not start with /, and contains no *, since it is unlikely to match an action or REST path. Note that this check looks for a leading / only, not a / anywhere in the entry: an entry such as _bulk/items contains a / but does not start with one, so the warning is still logged for it. This check only determines whether to log a warning; the entry is still included in the combined matcher.
Bulk requests
When resolve_bulk_requests: true is configured (logging individual bulk sub-items), the exclusion check uses the parent bulk action string. As a result, excluding the BULK group suppresses bodies for every sub-item (index, update, and delete) within that bulk request. You cannot keep index-item bodies while dropping delete-item bodies within the same bulk request.
Interaction with log_request_body
Body logging exclusions only apply when log_request_body is true. If log_request_body is false, no bodies are logged regardless of the exclusion configuration.
Example configuration
The following configuration defines three action groups and excludes the request bodies of bulk requests:
# opensearch.yml
# Define action groups (static, requires restart)
plugins.security.audit.config.action_groups.BULK: "indices:data/write/bulk*,/_bulk"
plugins.security.audit.config.action_groups.SEARCH: "indices:data/read/search*,/_search"
plugins.security.audit.config.action_groups.MONITORING: "cluster:monitor/*,indices:monitor/*"
# Initial exclusions (can be updated at runtime using _cluster/settings)
plugins.security.audit.config.body_logging_exclusions:
- BULK
The following table describes whether the request body is logged for each request type when you use this configuration.
| Request type | Request body logged |
|---|---|
| Bulk write | No, because the BULK group is excluded. |
| Search | Yes. |
| Index creation | Yes. |
| Monitoring | Yes, unless you add MONITORING to the exclusions. |
To add search exclusions at runtime, send the following request:
PUT _cluster/settings
{
"persistent": {
"plugins.security.audit.config.body_logging_exclusions": ["BULK", "SEARCH"]
}
}
To clear all exclusions (resume logging all bodies):
PUT _cluster/settings
{
"persistent": {
"plugins.security.audit.config.body_logging_exclusions": []
}
}
Log4j MDC routing
When using the log4j audit sink, enable Mapped Diagnostic Context (MDC) routing so that Log4j routes audit events to different appenders based on event properties:
plugins.security.audit.config.log4j.enable_mdc_routing: true
When enabled, the following MDC keys are set on each audit event:
audit_category— The audit event category (for example,REQUEST_AUDITorGRANTED_PRIVILEGES)audit_action— The action nameaudit_user— The effective useraudit_request_type— The request type
Use Log4j routing appenders in log4j2.properties to split audit logs by category, user, or any other MDC key.
This is a static setting and requires a node restart.
Configure the audit log index name
By default, the Security plugin stores audit events in a daily rolling index named security-auditlog-YYYY.MM.dd:
plugins.security.audit.config.index: myauditlogindex
Use a date pattern in the index name to configure daily, weekly, or monthly rolling indexes:
plugins.security.audit.config.index: "'auditlog-'YYYY.MM.dd"
For a reference on the date pattern format, see the Joda DateTimeFormat documentation.
(Advanced) Tune the thread pool
The Search plugin logs events asynchronously, which minimizes the performance impact on your cluster. The plugin uses a fixed thread pool to log events:
plugins.security.audit.config.threadpool.size: <integer>
The default setting is 10. Setting this value to 0 disables the thread pool, which means the plugin logs events synchronously. To set the maximum queue length per thread:
plugins.security.audit.config.threadpool.max_queue_len: 100000
Disabling audit logs
To disable audit logs after they’ve been enabled, remove the plugins.security.audit.type: internal_opensearch setting from opensearch.yml, or switch off the Enable audit logging check box in OpenSearch Dashboards. The plugins.security.audit.enabled runtime toggle, set using the Cluster Settings API, applies only to standalone audit logging; see Standalone audit logging for instructions.
Audit user account manipulation
To enable audit logging on changes to a security index, such as changes to roles mappings and role creation or deletion, use the following settings in the compliance: portion of the audit log configuration, as shown in the following example:
_meta:
type: "audit"
config_version: 2
config:
# enable/disable audit logging
enabled: true
...
compliance:
# enable/disable compliance
enabled: true
# Log updates to internal security changes
internal_config: true
# Log only metadata of the document for write events
write_metadata_only: false
# Log only diffs for document updates
write_log_diffs: true
# List of indices to watch for write events. Wildcard patterns are supported
# write_watched_indices: ["twitter", "logs-*"]
write_watched_indices: [".opendistro_security"]