Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,14 @@ The Security plugin supports the following audit log settings:

- `plugins.security.audit.config.cert_alias` (Static): An alias to the certificate used for audit log access.

- `plugins.security.audit.config.body_logging_exclusions` (Dynamic): A list of action group names or raw action/path patterns for which request body logging is suppressed. Default is `[]` (empty, log all bodies). See [Body logging exclusions]({{site.url}}{{site.baseurl}}/security/audit-logs/index/#body-logging-exclusions) for details.

- `plugins.security.audit.config.action_groups.<NAME>` (Static): Defines named groups of action/path patterns for use with `body_logging_exclusions`. Each group is a comma-separated string of transport action patterns and/or REST paths. Supports wildcards.

- `plugins.security.audit.config.log4j.enable_mdc_routing` (Static): Enables MDC (Mapped Diagnostic Context) routing for the Log4j audit sink. When enabled, audit events set MDC keys (`audit_category`, `audit_action`, `audit_user`, `audit_request_type`) that can be used by Log4j routing appenders. Default is `false`.

- `plugins.security.audit.enable_standalone` (Static): Enables standalone audit logging mode for clusters running without fine-grained access control (SSL-only or security-disabled modes). Must be set to `true` alongside `plugins.security.audit.type` to activate standalone audit. Default is `false`.

- `plugins.security.audit.config.pemkey_filepath` (Static): The `/config` relative file path to the Privacy Enhanced Mail (PEM) key used for audit logging.

- `plugins.security.audit.config.pemkey_content` (Static): The Base64-encoded content of the PEM key used for audit logging. This is an alternative to `...config.pemkey_filepath`.
Expand Down Expand Up @@ -237,6 +245,8 @@ The Security plugin supports the following audit log settings:

- `opendistro_security.audit.config.disabled_transport_categories` (Dynamic): A list of transport layer categories to be ignored by the logger. Valid values are `AUTHENTICATED` and `GRANTED_PRIVILEGES`.

The dynamic audit filter settings and all `plugins.security.audit.compliance.*` settings are marked with `Setting.Property.Sensitive`. This means only security admin users can view or modify their values via the cluster settings API; values are masked for non-admin users. The `plugins.security.audit.config.body_logging_exclusions` and `plugins.security.audit.config.action_groups.<NAME>` settings are exceptions and are not marked sensitive.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs #6392 for the SSL-only read path, so it can't merge before that.

The role wording is incorrect regardless of #6392. The settings filter isn't role-aware. After #6392, SSL-only returns the non-secret config to any caller (no roles exist there), and FGAC keeps the whole audit.* subtree filtered for everyone. There's no "admins can view, non-admins masked" behavior.

Suggest something like: "These settings are registered Setting.Property.Sensitive, which keeps their values out of diagnostics and logs. In standalone SSL-only mode the non-secret dynamic config (…config.* and …compliance.*) is readable via GET _cluster/settings; credential-bearing sink settings (endpoint/route credentials, PEM keys, salt) stay hidden. body_logging_exclusions and action_groups.<NAME> aren't marked sensitive."


## Hostname verification and DNS lookup settings

The Security plugin supports the following hostname verification and DNS lookup settings:
Expand Down
190 changes: 181 additions & 9 deletions _security/audit-logs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@

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:

- **Standard mode** (default): Requires the Security plugin with fine-grained access control (FGAC) enabled. Configuration is managed through the `audit.yml` file in the security index and the REST API.
- **Standalone mode**: Works without FGAC---in SSL-only mode (`plugins.security.ssl_only: true`) or with security disabled (`plugins.security.disabled: true`). Configuration is managed entirely through `opensearch.yml` and dynamic cluster settings. See [Standalone audit logging]({{site.url}}{{site.baseurl}}/security/audit-logs/standalone/) for details.

### Enabling audit logging (standard mode)

Audit logging is disabled by default. To enable audit logging:

1. Add the following line to `opensearch.yml` on each node:
Expand All @@ -39,9 +46,7 @@

2. Restart each node.

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**.

An alternative is to specify initial settings for audit logging in the `audit.yml` and `opensearch.yml` files (which file depends on the setting---see [Audit log settings](#audit-log-settings)). Thereafter, you can use Dashboards or the [Audit logs]({{site.url}}{{site.baseurl}}/security/access-control/api/#audit-logs) API to manage and update settings.
After this initial setup, 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](#audit-log-settings)). You can also use the [Audit logs]({{site.url}}{{site.baseurl}}/security/access-control/api/#audit-logs) API to manage and update settings.


## Tracked events
Expand All @@ -59,6 +64,11 @@
`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 | No | A REST-layer request was received and processed. Generated in [standalone audit logging]({{site.url}}{{site.baseurl}}/security/audit-logs/standalone/) mode only.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

REQUEST_AUDIT has origin=REST but request_layer=TRANSPORT internally and can be suppressed via disabled_transport_categories. "No" is fine for a REST-origin event, but a footnote would be more accurate. Non-blocking.

`TRANSPORT_AUDIT` | No | Yes | A transport-layer request was received on a node. Generated in [standalone audit logging]({{site.url}}{{site.baseurl}}/security/audit-logs/standalone/) 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.


## Audit log settings
Expand Down Expand Up @@ -260,11 +270,30 @@

### Settings in opensearch.yml

The following settings are stored in the `opensearch.yml` file.
The following settings are stored in the `opensearch.yml` file. The audit filter and compliance settings---for example, `log_request_body`, `resolve_indices`, `disabled_categories`, and the `plugins.security.audit.compliance.*` settings---are dynamic: they can be changed at runtime using the [Cluster settings API]({{site.url}}{{site.baseurl}}/api-reference/cluster-api/cluster-settings/) without a node restart. Most of these dynamic settings are also marked as sensitive, meaning only security admin users can view or modify them via the cluster settings API (`body_logging_exclusions` and `action_groups.<NAME>` are exceptions and are not sensitive). Other audit settings---such as `action_groups.<NAME>`, `log4j.enable_mdc_routing`, `config.index`, the thread pool settings, and the sink connection settings---are static and require a node restart.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as the security-settings.md note: needs #6392, and "only security admin users can view or modify them via the cluster settings API" is incorrect in either mode (SSL-only is readable by any caller; FGAC is filtered for everyone). Reword to describe Property.Sensitive instead of role-based masking.

Also, action_groups.<NAME> is listed here as a dynamic setting but it's static (groupSetting(..., NodeScope)) — the next sentence already says so. Drop it from this parenthetical; only body_logging_exclusions is a dynamic non-sensitive exception.


#### Enable or disable audit logging

```yml
plugins.security.audit.enabled: true
```
{% include copy.html %}

Enables or disables audit logging globally. Default is `true`. This setting is dynamic and can be toggled at runtime:

```json
PUT _cluster/settings
{
"persistent": {
"plugins.security.audit.enabled": false
}
}
```
{% include copy.html %}

#### Exclude categories

You can configure disabled categories in `opensearch.yml` using the `plugins.security.audit.config` prefix. This is useful for non-fine-grained access control (FGAC) modes (SSL-only or security-disabled) for which the `audit.yml` security index is not available:
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) where the `audit.yml` security index is not available:

```yml
plugins.security.audit.config.disabled_categories:
Expand All @@ -273,7 +302,7 @@
```
{% include copy.html %}

The layer-specific settings (`disabled_rest_categories` and `disabled_transport_categories`) may be deprecated in a future version. Use the unified `disabled_categories` setting instead.
The following layer-specific settings (`disabled_rest_categories` and `disabled_transport_categories`) are on a deprecation path and could be removed in a future release. Use the unified `disabled_categories` setting instead.
{: .warning}

The layer-specific settings are also available:
Expand All @@ -288,12 +317,155 @@
```
{% include copy.html %}

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.
When both `disabled_categories` and the layer-specific settings are configured, they work in tandem---a category is disabled on a given layer if it appears in either setting. A deprecation warning is logged when both are configured, encouraging migration to `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 indices/fields, and the compliance ignore-users settings).
{: .note}

#### Body logging exclusions

Request body logging is valuable for compliance but can be expensive at scale. For example, a cluster performing 100,000+ bulk writes per second generates enormous audit volume---most of it redundant data payloads. The `log_request_body: false` toggle is all-or-nothing: it either logs all bodies or none.

Body logging exclusions give operators granular control: suppress request bodies for high-volume operations (like bulk ingestion) while still capturing bodies for searches, index creation, and admin operations that matter for investigation.

##### How it works

Each audit event's action name and REST path are matched against a set of exclusion patterns. When a match is found, the request body field is omitted from the audit event---all other fields (user, IP address, indices, timestamp, etc.) are preserved.

Check warning on line 333 in _security/audit-logs/index.md

View workflow job for this annotation

GitHub Actions / style-job

[vale] reported by reviewdog 🐶 [OpenSearch.LatinismsElimination] Using 'etc.' is unnecessary. Remove. Raw Output: {"message": "[OpenSearch.LatinismsElimination] Using 'etc.' is unnecessary. Remove.", "location": {"path": "_security/audit-logs/index.md", "range": {"start": {"line": 333, "column": 231}}}, "severity": "WARNING"}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The : / / / * split reads like it drives matching, but in the code it's only used for the warning heuristic — matching is a single combined WildcardMatcher tested per layer. Outcome you describe is right, just the framing. Non-blocking.


Matching uses two identifiers per request:

- **Transport action** --- The internal action name (for example, `indices:data/write/bulk[s][p]`). This is matched for transport-layer audit events.
- **REST path** --- The HTTP request path (for example, `/_bulk`). This is matched for REST-layer audit events. REST paths always start with `/`.

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 and/or REST paths, defined statically in `opensearch.yml`. The group name is user-chosen---pick any name that is meaningful for your operations:

```yml
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/*"
```
{% include copy.html %}

Each action group maps a name to a comma-separated list of patterns. Patterns can be:

- Transport action patterns (contain `:`) --- for example, `indices:data/write/bulk*`
- REST path patterns (start with `/`) --- for example, `/_bulk`
- Wildcard patterns (contain `*`) --- for example, `indices:data/write/*`

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. It is dynamic and can be changed at runtime:

```yml
plugins.security.audit.config.body_logging_exclusions:
- BULK
```
{% include copy.html %}

Or update at runtime without a restart:

```json
PUT _cluster/settings
{
"persistent": {
"plugins.security.audit.config.body_logging_exclusions": ["BULK", "SEARCH"]
}
}
```
{% include copy.html %}

Each entry in the list is processed as follows:

1. If the entry matches a defined action group name, that group's patterns are expanded.
2. If it does not match any group name, the entry is treated as a raw pattern (literal or wildcard).

A warning is logged for entries that don't look like an action pattern (no `:`), REST path (no `/`), or wildcard (no `*`), since they are unlikely to match any action.

##### Bulk request behavior

When `resolve_bulk_requests: true` is configured (logging individual bulk sub-items), the exclusion check uses the parent bulk action string. This means that excluding the `BULK` group suppresses bodies for **all** sub-items (index, update, delete) within that bulk request. You cannot selectively 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: Complete configuration

```yml
# 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 via _cluster/settings)
plugins.security.audit.config.body_logging_exclusions:
- BULK
```
{% include copy.html %}

With this configuration:
- Bulk write requests: body is **not** logged (excluded)
- Search requests: body **is** logged (not excluded)
- Index creation: body **is** logged (not excluded)
- Monitoring requests: body **is** logged (not excluded, unless you add `MONITORING` to exclusions)

To add search exclusions at runtime:

```json
PUT _cluster/settings
{
"persistent": {
"plugins.security.audit.config.body_logging_exclusions": ["BULK", "SEARCH"]
}
}
```
{% include copy.html %}

To clear all exclusions (resume logging all bodies):

```json
PUT _cluster/settings
{
"persistent": {
"plugins.security.audit.config.body_logging_exclusions": []
}
}
```
{% include copy.html %}

#### Log4j MDC routing

When using the `log4j` audit sink, you can enable MDC (Mapped Diagnostic Context) routing to allow Log4j to route audit events to different appenders based on event properties:

```yml
plugins.security.audit.config.log4j.enable_mdc_routing: true
```
{% include copy.html %}

When enabled, the following MDC keys are set on each audit event:

- `audit_category` --- The audit event category (for example, `REQUEST_AUDIT`, `GRANTED_PRIVILEGES`)
- `audit_action` --- The action name
- `audit_user` --- The effective user
- `audit_request_type` --- The request type

This allows you to configure Log4j routing appenders in your `log4j2.properties` to split audit logs by category, user, or any other MDC key.

This is a static setting and requires a node restart.
{: .note}


#### Configure the audit log index name

By default, the Security plugin stores audit events in a daily rolling index named `auditlog-YYYY.MM.dd`:
By default, the Security plugin stores audit events in a daily rolling index named `security-auditlog-YYYY.MM.dd`:

```yml
plugins.security.audit.config.index: myauditlogindex
Expand Down Expand Up @@ -328,7 +500,7 @@

## 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.
To disable audit logs after they've been enabled, remove the `plugins.security.audit.type: internal_opensearch` setting from `opensearch.yml`, or set `plugins.security.audit.enabled` to `false` via the cluster settings API.

## Audit user account manipulation

Expand Down
Loading
Loading