Skip to content
Closed
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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ release.

### Logs

### Audit

- Introduce Audit-Logging signal and related specification sections.
([#5059](https://github.com/open-telemetry/opentelemetry-specification/pull/5059))
([#6](https://github.com/apeirora/opentelemetry-specification/pull/6))

### Baggage

### Profiles
Expand Down
373 changes: 373 additions & 0 deletions oteps/0267-audit-logging.md

Large diffs are not rendered by default.

163 changes: 163 additions & 0 deletions specification/audit/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
<!--- Hugo front matter used to generate the website version of this page:
linkTitle: Audit Logging
path_base_for_github_subdir:
from: tmp/otel/specification/audit/_index.md
to: audit/README.md
--->

# OpenTelemetry Audit Logging

**Status**: [Development](../document-status.md)

<details>
<summary>Table of Contents</summary>

<!-- toc -->

- [OpenTelemetry Audit Logging](#opentelemetry-audit-logging)
- [Introduction](#introduction)
- [Why a Dedicated Audit Logging Signal?](#why-a-dedicated-audit-logging-signal)
- [Compliance Use Cases](#compliance-use-cases)
- [Signal Overview](#signal-overview)
- [Relationship to the Log Signal](#relationship-to-the-log-signal)
- [Specifications](#specifications)
- [References](#references)

<!-- tocstop -->

</details>

## Introduction

Audit logging is a compliance-critical signal that records
security-relevant events for regulatory and accountability purposes.
Compliance frameworks such as ISO 27001, SOC 2, PCI-DSS, and HIPAA
require that audit records be delivered without loss, modification, or
sampling to a tamper-protected audit sink.

The OpenTelemetry Audit Logging signal provides a purpose-built pipeline
with the delivery and integrity guarantees that compliance frameworks
demand. It extends OpenTelemetry's unified observability approach to
the domain of security and compliance auditing.

## Why a Dedicated Audit Logging Signal?

The existing OpenTelemetry [Log signal](../logs/README.md) is designed
for general-purpose observability. Its pipeline is intentionally subject
to behaviours that are incompatible with audit logging:

- **Sampling** – processors and exporters may drop records for
performance reasons.
- **Back-pressure shedding** – SDK queues may overflow and silently
discard records.
- **Transformation** – processors may modify, redact, or aggregate
records before export.

For audit logging, every record MUST be delivered to the designated audit
sink without modification or loss. A feature flag on a `LogRecord` cannot
fulfil this requirement because it still shares the existing pipeline and
inherits all the above behaviours.

A dedicated Audit Logging signal provides:

- A purpose-built SDK pipeline with no sampling, no transformation, and
at-least-once delivery semantics.
- A distinct OTLP endpoint (`/v1/audit`) so the audit sink can be
isolated from the observability backend, enabling independent access
control and QoS policies.
- A dedicated data model with mandatory integrity fields.
- Clear separation of audit records from operational logs, as required
by ISO 27001 Annex A and similar frameworks.

## Compliance Use Cases

The following table illustrates representative audit events and the
compliance drivers that motivate them:

| Actor | Audit event | Compliance driver |
|-----------------|-------------------------------|------------------------------|
| End user | Successful / failed login | ISO 27001 A.8.15, SOC 2 CC6 |
| End user | Access to sensitive data | GDPR Art. 30, HIPAA §164.312 |
| Operator | Configuration change | ISO 27001 A.8.15 |
| Service account | Elevated-privilege action | ISO 27001 A.5.18 |
| Service | Outbound call to external API | PCI-DSS Req. 10 |
| Runtime | Antivirus / IDs rule fired | ISO 27001 A.8.16 |

## Signal Overview

The Audit Logging signal is modelled structurally after the Log signal.
It reuses the OTLP `LogRecord` as its wire-format transport and adds a
small set of mandatory fields that satisfy compliance requirements.

```
Application code
AuditLogger.emit(AuditRecord) ──► returns AuditReceipt
│ RecordId (caller-generated)
AuditProvider (no sampling, no dropping)
│ └── AuditRecordProcessor (enrich only – never redact or drop)
│ ├── Simple processor (sync, default)
│ ├── Batching processor (async, high-volume)
│ └── Signing processor (adds IntegrityValue)
AuditExporter ──► Tier-2 Collector (optional) ──► Audit sinks
or ──► Audit sink directly │
│ (OpenSearch, Splunk, S3 WORM …)
└── returns AuditReceipt
(RecordId + IntegrityHash + SinkTimestamp)
```

The principal API components are:

- **AuditProvider** – the entry point of the API. It provides named
`AuditLogger` instances and MUST NOT expose a sampler configuration
option. See [Audit Logging API](./api.md#auditprovider).
- **AuditLogger** – emits `AuditRecord`s and returns an `AuditReceipt`
once the sink has acknowledged the record.
See [Audit Logging API](./api.md#auditlogger).

The principal data components are:

- **AuditRecord** – the audit event payload containing mandatory fields
for actor, action, outcome, timestamps, and optional integrity
metadata. See [Audit Record Data Model](./data-model.md#auditrecord-definition).
- **AuditReceipt** – proof-of-delivery returned by the sink, containing
a unique record identifier and a SHA-256 integrity hash.
See [Audit Record Data Model](./data-model.md#auditreceipt-definition).

## Relationship to the Log Signal

The Audit Logging signal is **independent** of the Log signal. Audit
records MUST NOT be routed through the standard `LoggerProvider`
pipeline.

An application or instrumentation library MAY emit both an `AuditRecord`
(for compliance) and a regular `LogRecord` (for observability) for the
same event. The two records travel through independent pipelines to
independent backends.

The OTLP wire format reuses the `LogRecord` protobuf message as the
payload carrier. The following OTLP envelope layers apply:

| OTLP layer | Role in audit logging |
|------------------------|--------------------------------------------------------|
| `Resource` | Emitting service / host; integrity attrs on Resource. |
| `LogRecord` | Carries AuditRecord via dedicated fields + Attributes. |
| `Attributes` | Mandatory and optional `audit.*` semantic attributes. |
| `InstrumentationScope` | **Not applicable.** MUST be left empty by exporters. |

## Specifications

- [Audit Logging API](./api.md)
- [Audit Logging SDK](./sdk.md)
- [Audit Record Data Model](./data-model.md)
- [Audit Logging Collector (Tier-2)](./collector.md)

## References

- [OTEP 0267 – Audit Logging Signal](../../oteps/0267-audit-logging.md)
- [OTEP 0092 – OpenTelemetry Logs Vision](../../oteps/logs/0092-logs-vision.md)
- [OTEP 0097 – Log Data Model](../../oteps/logs/0097-log-data-model.md)
- [OTEP 0202 – Events and Logs API](../../oteps/0202-events-and-logs-api.md)
209 changes: 209 additions & 0 deletions specification/audit/api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
<!--- Hugo front matter used to generate the website version of this page:
linkTitle: API
weight: 1
--->

# Audit Logging API

**Status**: [Development](../document-status.md)

<details>
<summary>Table of Contents</summary>

<!-- toc -->

- [Audit Logging API](#audit-logging-api)
- [AuditProvider](#auditprovider)
- [AuditProvider operations](#auditprovider-operations)
- [Get an AuditLogger](#get-an-auditlogger)
- [AuditLogger](#auditlogger)
- [Emit an AuditRecord](#emit-an-auditrecord)
- [Optional and required parameters](#optional-and-required-parameters)
- [Concurrency requirements](#concurrency-requirements)
- [References](#references)
<!-- tocstop -->

</details>

The Audit Logging API provides application code with a means to emit
[`AuditRecord`s](./data-model.md#auditrecord-definition) that are guaranteed to
reach the configured audit sink without loss or modification.

The API consists of these main components:

- [**AuditProvider**](#auditprovider) – the entry point of the API.
Provides access to `AuditLogger` instances.
- [**AuditLogger**](#auditlogger) – emits `AuditRecord`s and returns
an [`AuditReceipt`](./data-model.md#auditreceipt-definition).

```mermaid
graph TD
A[AuditProvider] -->|Get| B(AuditLogger)
B -->|Emit| C(AuditRecord)
C -->|returns| D(AuditReceipt)
```

Unlike the [Logs API](../logs/api.md), the Audit Logging API:

- Does **not** provide an `Enabled` check: audit records are always
emitted regardless of configuration, because dropping audit records
is prohibited.
- Does **not** accept a sampling-related configuration: the pipeline
MUST NOT sample or drop records.
- Has `emit` return an [`AuditReceipt`](./data-model.md#auditreceipt-definition)
as proof-of-delivery once the sink acknowledges the record.

## AuditProvider

`AuditLogger`s are obtained from an `AuditProvider`.

The `AuditProvider` is expected to be accessed from a central place.
The API SHOULD provide a way to set and access a global default
`AuditProvider`.

The API MUST provide a No-op `AuditProvider` implementation that is
used when no SDK is installed. The No-op provider MUST return a No-op
`AuditLogger` whose `emit` method completes without error and returns a
No-op `AuditReceipt`.

### AuditProvider operations

The `AuditProvider` MUST provide the following function:

- Get an `AuditLogger`

#### Get an AuditLogger

This API MUST accept the following parameter:

- `name` (required): A string identifying the component, library, or
subsystem that is emitting audit records (for example,
`"com.example.auth"` or `"payment-service"`). The name is used as a
diagnostic label and is stored as an SDK-internal marker. It MUST NOT
be empty. If an empty string is provided, the SDK SHOULD log a
warning and use a fallback name rather than failing.

Note: unlike `LoggerProvider.GetLogger`, this `name` is NOT mapped
to an OTLP `InstrumentationScope`. See
[README – OTLP Envelope Layers](./README.md#relationship-to-the-log-signal).

This API MAY accept the following optional parameters:

- `version` (optional): A string specifying the version of the
emitting component (for example, `"1.2.3"`).
- `schema_url` (optional): A Schema URL to be recorded in emitted
records for semantic convention versioning.

The term *identical* applied to `AuditLogger`s describes instances
where all parameters are equal. The term *distinct* describes instances
where at least one parameter has a different value.

## AuditLogger

The `AuditLogger` is responsible for emitting `AuditRecord`s to the
audit pipeline.

The `AuditLogger` MUST provide a function to:

- [Emit an `AuditRecord`](#emit-an-auditrecord)

The `AuditLogger` MUST NOT provide an `Enabled` or sampling-related
function. Conditional emission is the sole responsibility of
application code; the SDK MUST NOT silently suppress records based on
any sampling or filtering configuration.

### Emit an AuditRecord

The effect of calling this API is to submit an `AuditRecord` to the
audit pipeline and to block until the audit sink acknowledges receipt,
returning an `AuditReceipt`.

The API MUST accept the following parameters:

- [`Timestamp`](./data-model.md#logrecord-field-usage) (required): the
time at which the auditable action occurred.
- [`EventName`](./data-model.md#logrecord-field-usage) (required): the
semantic name of the audit event.
- [`Attributes`](./data-model.md#audit-semantic-attributes) (required):
a map of key-value pairs that carries all audit-specific data.
The following attribute keys MUST be present and non-empty:

| Attribute key | Type | Description |
|--------------------|----------|-------------------------------------|
| `audit.actor.id` | `string` | Identity that performed the action. |
| `audit.actor.type` | `string` | `user`, `service`, or `system`. |
| `audit.action` | `string` | Verb describing what was done. |
| `audit.outcome` | `string` | `success`, `failure`, or `unknown`. |

The attribute key `audit.record.id` is also required in every
persisted record. If the caller omits it, the SDK MUST generate a
UUID v4 and inject it into `Attributes` before any further
processing. The value MUST be stable across retries of the same
event.

The API MUST accept the following optional parameters:

- [`ObservedTimestamp`](./data-model.md#logrecord-field-usage)
(optional): if not provided, the SDK MUST set it to the current time.
- [`Body`](./data-model.md#logrecord-field-usage) (optional): free-form
or structured event details.

Additional optional attributes MAY be provided in `Attributes`. See
the [Audit Record Data Model](./data-model.md#audit-semantic-attributes)
for the full list, which includes `audit.target.id`, `audit.target.type`,
`audit.source.id`, `audit.source.type`, `audit.integrity.value`,
`audit.sequence.number`,
`audit.prev.hash`, and `audit.schema.version`.

**Return value**: The API MUST return an
[`AuditReceipt`](./data-model.md#auditreceipt-definition) when the
audit sink acknowledges that the record has been persisted. The receipt
echoes the caller's `audit.record.id` and contains an `IntegrityHash`
and a `SinkTimestamp`.

**Delivery semantics**: `emit` is synchronous by default. It MUST block
the calling thread until the exporter receives a successful
acknowledgement from the audit sink. This guarantees at-least-once
delivery and provides the caller with a `RecordId` that can be logged
or stored for audit trail completeness.

An asynchronous variant MAY be provided by the SDK. An asynchronous
`emit`:

- MUST still guarantee at-least-once delivery through an internal
durable buffer.
- MUST NOT silently discard records on failure.
- MAY return a future, promise, or channel through which the
`AuditReceipt` will be delivered once the sink acknowledges the
record.

**Error handling**: If the audit sink cannot be reached and the SDK's
retry budget is exhausted, `emit` MUST surface a hard error to the
caller (for example, by raising an exception or returning an error
code). It MUST NOT return silently or return a partial / empty receipt.

## Optional and required parameters

Required parameters are those not marked optional in the
[Emit an AuditRecord](#emit-an-auditrecord) section. The API MUST be
structured to require these parameters (for example, as positional
arguments or a required record type).

For each optional parameter, the API MUST be structured to accept it,
but MUST NOT require the caller to provide it.

## Concurrency requirements

For languages that support concurrent execution, the Audit Logging API
provides the following guarantees:

- **AuditProvider** – all methods MUST be documented as safe for
concurrent use.
- **AuditLogger** – `emit` MUST be documented as safe for concurrent
use. Concurrent `emit` calls MUST be serialized internally by the SDK
so that records are enqueued in the order they are received.

## References

- [OTEP 0267 – Audit Logging Signal](../../oteps/0267-audit-logging.md)
- [OTEP 0202 – Events and Logs API](../../oteps/0202-events-and-logs-api.md)
Loading