From 7d04b0fbbf04fa365d70a355208d56e41d3dbfd4 Mon Sep 17 00:00:00 2001 From: Hilmar Falkenberg Date: Mon, 9 Feb 2026 10:50:31 +0100 Subject: [PATCH 01/21] GHA sync-fork Signed-off-by: Hilmar Falkenberg --- .github/workflows/sync-fork.yaml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 .github/workflows/sync-fork.yaml diff --git a/.github/workflows/sync-fork.yaml b/.github/workflows/sync-fork.yaml new file mode 100644 index 0000000000..de520f2bc0 --- /dev/null +++ b/.github/workflows/sync-fork.yaml @@ -0,0 +1,16 @@ +name: sync-fork +on: + schedule: + - cron: '4 2 * * 4,2' + workflow_dispatch: +jobs: + sync-fork: + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - run: gh repo sync $REPOSITORY -b $BRANCH_NAME + env: + GITHUB_TOKEN: ${{ secrets.SYNC_FORK_TOKEN }} + REPOSITORY: ${{ github.repository }} + BRANCH_NAME: ${{ github.ref_name }} From 56063dd2973181966beaf5e59fe2005b19c3b142 Mon Sep 17 00:00:00 2001 From: Hilmar Falkenberg Date: Wed, 3 Jun 2026 10:34:11 +0200 Subject: [PATCH 02/21] feat: add audit logging semantic conventions (OTEP 0267) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduces a new `audit.*` attribute namespace and accompanying documentation for the OpenTelemetry Audit Logging signal. The audit signal is a dedicated, lossless pipeline separate from the standard log/observability pipeline, required by compliance frameworks such as ISO 27001, SOC 2, PCI-DSS, and HIPAA. Files added: - model/audit/registry.yaml — all audit.* attribute definitions - model/audit/logs.yaml — audit.record attribute group with requirement levels - docs/audit/audit-logs.md — full documentation page incl. examples, SDK invariants, and compliance mapping - docs/registry/attributes/audit.md — registry attribute reference page Attribute groups defined: audit.record (record.id, schema.version) audit.actor (actor.id, actor.type, actor.name) audit.action (action, outcome) audit.target (target.id, target.type, target.name) audit.source (source.id, source.type) audit.integrity (integrity.value, integrity.algorithm, integrity.certificate) audit.sequence (sequence.number, prev.hash) Signed-off-by: Hilmar Falkenberg --- docs/audit/audit-logs.md | 358 ++++++++++++++++++++++++++++++ docs/registry/attributes/audit.md | 179 +++++++++++++++ model/audit/logs.yaml | 93 ++++++++ model/audit/registry.yaml | 317 ++++++++++++++++++++++++++ 4 files changed, 947 insertions(+) create mode 100644 docs/audit/audit-logs.md create mode 100644 docs/registry/attributes/audit.md create mode 100644 model/audit/logs.yaml create mode 100644 model/audit/registry.yaml diff --git a/docs/audit/audit-logs.md b/docs/audit/audit-logs.md new file mode 100644 index 0000000000..9c6d64b5bf --- /dev/null +++ b/docs/audit/audit-logs.md @@ -0,0 +1,358 @@ + + +# Semantic Conventions for Audit Logs + +**Status**: [Development][DocumentStatus] + + + +- [Motivation and compliance context](#motivation-and-compliance-context) +- [Signal separation](#signal-separation) +- [Recording an audit record](#recording-an-audit-record) + - [LogRecord fields](#logrecord-fields) + - [Event name](#event-name) + - [Attributes](#attributes) +- [Mandatory attributes](#mandatory-attributes) +- [Optional attribute groups](#optional-attribute-groups) + - [Actor enrichment](#actor-enrichment) + - [Target](#target) + - [Source / origin](#source--origin) + - [Integrity and tamper-evidence](#integrity-and-tamper-evidence) + - [Hash-chain ordering](#hash-chain-ordering) +- [AuditReceipt](#auditreceipt) +- [SDK invariants](#sdk-invariants) +- [Compliance mapping](#compliance-mapping) +- [Examples](#examples) + - [Successful login](#successful-login) + - [Privileged resource deletion with integrity](#privileged-resource-deletion-with-integrity) + + + +## Motivation and compliance context + +Compliance frameworks (ISO 27001, SOC 2, PCI-DSS, HIPAA) mandate that +security-relevant events are captured completely, without loss, and in a +tamper-evident form. The standard OpenTelemetry Log signal is intentionally +designed to allow sampling, back-pressure shedding, and record transformation +— behaviours that are incompatible with these requirements. + +The **Audit Logging signal** is a dedicated pipeline that provides: + +- Guaranteed delivery with at-least-once semantics. +- An `AuditReceipt` returned synchronously once the sink acknowledges. +- Cryptographic integrity via per-record HMAC or digital signature. +- An append-only hash chain that makes retroactive tampering detectable. +- Complete separation from the observability log pipeline. + +> [!IMPORTANT] +> +> **Do NOT** use the standard `Logger` API to emit audit records. +> Audit records MUST be emitted through the dedicated `AuditLogger` obtained +> from an `AuditProvider`. Routing audit records through the observability +> pipeline risks silent loss, sampling, and transformation — any of which +> constitutes a compliance violation. + +## Signal separation + +The audit signal uses the same `LogRecord` data structure as the standard log +signal, but travels through a completely separate pipeline: + +``` +Application code + │ + ▼ +AuditLogger.emit(AuditRecord) ──► returns AuditReceipt + │ (via AuditProvider) + ▼ +AuditRecordProcessor chain (additive-only; enrichment, no filtering) + │ + ▼ +AuditRecordExporter ──POST /v1/audit──► Audit sink / Tier-2 Collector +``` + +The exporter uses the OTLP `ExportLogsServiceRequest` payload with an +`audit: true` flag on the `ResourceLogs` message to distinguish audit traffic +from `/v1/logs` observability traffic. + +## Recording an audit record + +### LogRecord fields + +The following `LogRecord` fields are used by audit records: + +| Field | Requirement | Notes | +| --- | --- | --- | +| `Timestamp` | MUST | Time the auditable action occurred (nanoseconds UTC). | +| `ObservedTimestamp` | MUST | SDK sets this to the current wall-clock time if omitted by the caller. | +| `EventName` | MUST | Dot-separated, lowercase name (see [Event name](#event-name)). | +| `Body` | MAY | Free-form human-readable summary. MUST NOT duplicate mandatory attributes. | +| `SeverityNumber` | SHOULD NOT | Not meaningful for audit records. | +| `InstrumentationScope` | MUST NOT | Leave empty (or SDK name/version as a technical marker only). | + +### Event name + +The event name MUST follow the +[naming conventions](/docs/general/naming.md) and use the prefix `audit.` +followed by a dot-separated, lowercase description of the auditable action. + +Examples: `audit.user.login`, `audit.config.change`, `audit.resource.delete`, +`audit.permission.grant`. + +### Attributes + +All audit-specific data is carried as `LogRecord` attributes in the `audit.*` +namespace. + + + + + + +**Attributes:** + +| Key | Stability | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Value Type | Description | Example Values | +| --- | --- | --- | --- | --- | --- | +| [`audit.record.id`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Required` | string | A stable, globally unique identifier for this audit record. [1] | `3fa85f64-5717-4562-b3fc-2c963f66afa6` | +| [`audit.actor.id`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Required` | string | The stable identifier of the actor that performed the action. [2] | `u8472`; `svc-deployer`; `arn:aws:iam::123456789012:role/DeployRole` | +| [`audit.actor.type`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Required` | string | The category of principal that performed the action. | `user`; `service`; `system` | +| [`audit.action`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Required` | string | The auditable operation that was performed. [3] | `LOGIN`; `DELETE`; `GRANT`; `CONFIG_CHANGE` | +| [`audit.outcome`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Required` | string | The result of the auditable action. | `success`; `failure`; `unknown` | +| [`audit.integrity.algorithm`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Conditionally Required` [4] | string | The algorithm used to compute `audit.integrity.value`. | `ES256`; `EdDSA`; `HMAC-SHA256` | +| [`audit.source.id`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Recommended` [5] | string | A stable identifier for the source system or network endpoint. | `192.0.2.42`; `device-uuid-abcd1234` | +| [`audit.source.type`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Recommended` [6] | string | The category of origin that initiated the action. | `ip_address`; `device`; `service_mesh_node` | +| [`audit.target.id`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Recommended` [7] | string | The stable identifier of the resource that was the target of the action. | `document-42`; `arn:aws:s3:::my-bucket/key`; `/api/v1/users/9f81` | +| [`audit.target.type`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Recommended` [8] | string | The type or resource kind of the target. | `User`; `apps/v1/Deployment`; `finance.invoice` | +| [`audit.sequence.number`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Recommended` [9] | int | A monotonically increasing counter within a single audit stream. | `1`; `42`; `1000001` | +| [`audit.prev.hash`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Recommended` [10] | string | SHA-256 hex digest of the preceding record's `IntegrityHash`. | `a3f1c2e4...`; `000000...` | +| [`audit.actor.name`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Opt-In` | string | Human-readable display name of the actor. | `alice`; `alice@example.com` | +| [`audit.target.name`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Opt-In` | string | Human-readable name of the target resource. | `production-deploy` | +| [`audit.integrity.value`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Opt-In` | string | Base64url-encoded cryptographic signature or MAC. | `SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c` | +| [`audit.integrity.certificate`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Opt-In` | string | Reference to the key or certificate for `audit.integrity.value`. | `key-2024-01` | +| [`audit.schema.version`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Opt-In` | string | Audit schema version string. | `1.0.0` | + +**[1] `audit.record.id`:** The SDK MUST auto-generate a UUID v4 when the caller omits this field. +The value MUST remain identical across all retries of the same record. + +**[2] `audit.actor.id`:** SHOULD be a durable, opaque identifier (user-UUID, service account name, +or IAM principal ARN) that remains stable across sessions. Avoid mutable +display names or email addresses as the primary id. + +**[3] `audit.action`:** SHOULD be an uppercase verb. Well-known values: `LOGIN`, `LOGOUT`, `READ`, +`CREATE`, `UPDATE`, `DELETE`, `GRANT`, `REVOKE`, `EXPORT`, `IMPORT`, +`EXECUTE`, `APPROVE`, `REJECT`. Custom values MAY be used but SHOULD be +documented in the producing service's changelog. + +**[4] `audit.integrity.algorithm`:** Required as a **Resource attribute** when `audit.integrity.value` +is present on any record emitted from this resource. + +**[5] `audit.source.id`:** Recommended when the network origin or calling device is known and +meaningful for compliance review (e.g. PCI-DSS access logging). + +**[6] `audit.source.type`:** Recommended when `audit.source.id` is present. + +**[7] `audit.target.id`:** Recommended when the action is performed on a specific, identifiable +resource. + +**[8] `audit.target.type`:** Recommended when `audit.target.id` is present and the resource kind +adds meaningful context for audit review. + +**[9] `audit.sequence.number`:** Recommended when the emitting service maintains a monotonic +per-stream counter. Required when `audit.prev.hash` is present. + +**[10] `audit.prev.hash`:** Recommended when the emitting service implements a hash chain. +Requires `audit.sequence.number` to be present. Use the all-zeros string +for the very first record in a stream. + + + + + +--- + +`audit.actor.type` has the following list of well-known values. If one of them applies, then the respective value MUST be used; otherwise, a custom value MAY be used. + +| Value | Description | Stability | +| --- | --- | --- | +| `service` | An automated service or daemon acting on its own behalf. | ![Development](https://img.shields.io/badge/-development-blue) | +| `system` | An internal system component that is not externally authenticated. | ![Development](https://img.shields.io/badge/-development-blue) | +| `user` | A human user authenticated to the system. | ![Development](https://img.shields.io/badge/-development-blue) | + +--- + +`audit.outcome` has the following list of well-known values. If one of them applies, then the respective value MUST be used; otherwise, a custom value MAY be used. + +| Value | Description | Stability | +| --- | --- | --- | +| `failure` | The action was attempted but did not complete successfully. | ![Development](https://img.shields.io/badge/-development-blue) | +| `success` | The action completed successfully and produced its intended effect. | ![Development](https://img.shields.io/badge/-development-blue) | +| `unknown` | The outcome could not be determined at emit time (e.g. async operation). | ![Development](https://img.shields.io/badge/-development-blue) | + +## Mandatory attributes + +The five mandatory attributes MUST be present on every audit record. +Missing any of them is a hard error; the SDK MUST NOT silently drop the record. + +| Attribute | Auto-generated? | +| --- | --- | +| `audit.record.id` | Yes — SDK generates UUID v4 if absent. | +| `audit.actor.id` | No — caller MUST provide. | +| `audit.actor.type` | No — caller MUST provide. | +| `audit.action` | No — caller MUST provide. | +| `audit.outcome` | No — caller MUST provide. | + +## Optional attribute groups + +### Actor enrichment + +`audit.actor.name` provides a human-readable label for the actor, useful for +display in audit review UIs. It MUST NOT be used as the primary identifier; +use `audit.actor.id` for stable correlation. + +### Target + +`audit.target.id` and `audit.target.type` describe the resource acted upon. +Include them whenever the action has a specific, identifiable resource object. +For bulk operations, `audit.target.id` MAY hold a collection identifier. + +### Source / origin + +`audit.source.id` and `audit.source.type` record the network endpoint or +device from which the action originated. PCI-DSS Requirement 10 mandates +capturing the originating IP for all access to cardholder data environments; +use these attributes to satisfy that requirement. + +### Integrity and tamper-evidence + +The integrity triplet (`audit.integrity.value`, `audit.integrity.algorithm`, +`audit.integrity.certificate`) enables the audit sink to verify that a record +was not altered in transit. + +- `audit.integrity.algorithm` is a **Resource attribute** and MUST be the + same for all records emitted by a single service instance. +- `audit.integrity.value` is the per-record Base64url-encoded signature/MAC + over the canonical serialisation of the record (with `audit.integrity.value` + itself absent from the input). +- On acknowledgement, the sink returns an `AuditReceipt` containing an + `IntegrityHash` (SHA-256 of the persisted record). The emitter SHOULD + compute the same hash locally and compare; a mismatch MUST be treated as + a hard error. + +Compliant implementations SHOULD use asymmetric signing (`ES256` or `EdDSA`) +to allow the sink to verify without possessing the signing key. + +### Hash-chain ordering + +`audit.sequence.number` and `audit.prev.hash` together form an append-only +hash chain: + +``` +Record N: sequence.number=N, prev.hash=IntegrityHash(Record N-1) +Record N+1: sequence.number=N+1, prev.hash=IntegrityHash(Record N) +``` + +Any retroactive modification of Record N causes the `prev.hash` of Record N+1 +to become invalid, making the tampering detectable without re-signing. +Set `audit.prev.hash` to the all-zeros string for the very first record. + +## AuditReceipt + +`emit()` blocks until the audit sink acknowledges the record, then returns +an `AuditReceipt`: + +| Field | Type | Description | +| --- | --- | --- | +| `RecordId` | string | Echoes the caller's `audit.record.id`. | +| `IntegrityHash` | string | SHA-256 hex digest of the record as persisted by the sink. | +| `SinkTimestamp` | uint64 | Nanoseconds since UNIX epoch when the sink wrote the record. | + +The emitter SHOULD compute `SHA-256(canonical_record)` locally and compare to +`IntegrityHash`. A mismatch means the record was altered after transmission +and MUST be treated as a hard error. + +`emit()` MUST raise a hard error if the sink does not respond within the +configured timeout. It MUST NOT return successfully without a valid receipt. + +## SDK invariants + +The following invariants MUST be respected by every SDK implementation: + +| # | Invariant | +| --- | --- | +| 1 | `AuditProvider` MUST NOT accept sampler or sampling-rate configuration. | +| 2 | `emit()` MUST block until the sink acknowledges, or raise a hard error. | +| 3 | `emit()` MUST return a valid `AuditReceipt`. | +| 4 | The queue MUST be disk-backed or unbounded in-memory — **never** silently drops. | +| 5 | Processors are additive-only: MAY enrich; MUST NOT delete, filter, or transform. | +| 6 | Transport: `POST /v1/audit` with `audit: true` on `ResourceLogs`. | +| 7 | `partial_success` in a sink response MUST be treated as a hard `Failure`. | +| 8 | `InstrumentationScope` MUST be left empty. | +| 9 | SDK exposes metrics: `audit.records.emitted`, `audit.records.exported`, `audit.records.dropped`, `audit.queue.depth`, `audit.export.duration`. | +| 10 | Non-zero `audit.records.dropped` MUST trigger an operational alert. | + +## Compliance mapping + +| Requirement | Audit signal feature | +| --- | --- | +| ISO 27001 A.8.15 — Logging | All actions recorded; logs protected via integrity attributes. | +| ISO 27001 A.8.17 — Clock sync | SDK warns when `\|Timestamp − ObservedTimestamp\|` > 5 s. | +| SOC 2 CC7.2 — Anomaly detection | `audit.records.dropped` metric + operational alert. | +| PCI-DSS Req. 10.2 — Audit trails | Mandatory attributes cover all required fields; `audit.source.id` for IP. | +| PCI-DSS Req. 10.5 — Log protection | `audit.integrity.value` + `audit.prev.hash` hash chain. | +| HIPAA § 164.312(b) — Audit controls | `audit.actor.*` + `audit.target.*` cover ePHI access logging. | + +## Examples + +### Successful login + +```json +{ + "Timestamp": "2026-06-03T10:00:00.000000000Z", + "ObservedTimestamp": "2026-06-03T10:00:00.000100000Z", + "EventName": "audit.user.login", + "Attributes": { + "audit.record.id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "audit.actor.id": "u8472", + "audit.actor.type": "user", + "audit.actor.name": "alice", + "audit.action": "LOGIN", + "audit.outcome": "success", + "audit.source.id": "192.0.2.42", + "audit.source.type": "ip_address" + } +} +``` + +### Privileged resource deletion with integrity + +```json +{ + "Timestamp": "2026-06-03T10:05:00.000000000Z", + "ObservedTimestamp": "2026-06-03T10:05:00.000050000Z", + "EventName": "audit.resource.delete", + "Resource": { + "service.name": "billing-service", + "service.version": "3.1.0", + "audit.integrity.algorithm": "ES256", + "audit.integrity.certificate": "key-2024-01" + }, + "Attributes": { + "audit.record.id": "7c9e6679-7425-40de-944b-e07fc1f90ae7", + "audit.actor.id": "svc-deployer", + "audit.actor.type": "service", + "audit.action": "DELETE", + "audit.outcome": "success", + "audit.target.id": "invoice-8819", + "audit.target.type": "finance.invoice", + "audit.source.id": "device-uuid-abcd1234", + "audit.source.type": "device", + "audit.sequence.number": 42, + "audit.prev.hash": "a3f1c2e4b5d6a7f8e9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2", + "audit.integrity.value": "SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c", + "audit.schema.version": "1.0.0" + } +} +``` + +[DocumentStatus]: https://opentelemetry.io/docs/specs/otel/document-status diff --git a/docs/registry/attributes/audit.md b/docs/registry/attributes/audit.md new file mode 100644 index 0000000000..b3c4fc3084 --- /dev/null +++ b/docs/registry/attributes/audit.md @@ -0,0 +1,179 @@ + + + +# Audit + +- [Audit Record Attributes](#audit-record-attributes) +- [Audit Actor Attributes](#audit-actor-attributes) +- [Audit Action Attributes](#audit-action-attributes) +- [Audit Target Attributes](#audit-target-attributes) +- [Audit Source Attributes](#audit-source-attributes) +- [Audit Integrity Attributes](#audit-integrity-attributes) +- [Audit Sequence Attributes](#audit-sequence-attributes) + +## Audit Record Attributes + +Attributes that uniquely identify and version an audit record. + +**Attributes:** + +| Key | Stability | Value Type | Description | Example Values | +| --- | --- | --- | --- | --- | +| `audit.record.id` | ![Development](https://img.shields.io/badge/-development-blue) | string | A stable, globally unique identifier for this audit record. [1] | `3fa85f64-5717-4562-b3fc-2c963f66afa6` | +| `audit.schema.version` | ![Development](https://img.shields.io/badge/-development-blue) | string | The version of the audit semantic conventions schema used by this record. [2] | `1.0.0`; `1.2.0` | + +**[1] `audit.record.id`:** The SDK MUST auto-generate a UUID v4 when the caller omits this field. +The value MUST remain identical across all retries of the same record. +Records with the same `audit.record.id` and identical payload hash are +treated as idempotent duplicates by compliant sinks. + +**[2] `audit.schema.version`:** Follows semantic versioning (MAJOR.MINOR.PATCH). Receivers MAY use this +value to select an appropriate validation schema. + +## Audit Actor Attributes + +Attributes that identify the principal (human user, service, or automated system component) that initiated the auditable action. + +**Attributes:** + +| Key | Stability | Value Type | Description | Example Values | +| --- | --- | --- | --- | --- | +| `audit.actor.id` | ![Development](https://img.shields.io/badge/-development-blue) | string | The stable identifier of the actor that performed the action. [1] | `u8472`; `svc-deployer`; `arn:aws:iam::123456789012:role/DeployRole` | +| `audit.actor.name` | ![Development](https://img.shields.io/badge/-development-blue) | string | A human-readable display name or username of the actor. [2] | `alice`; `alice@example.com`; `Alice Smith` | +| `audit.actor.type` | ![Development](https://img.shields.io/badge/-development-blue) | string | The category of principal that performed the action. | `user`; `service`; `system` | + +**[1] `audit.actor.id`:** This SHOULD be an opaque, durable identifier (e.g. a user-UUID, service +account name, or IAM principal ARN) that remains stable across sessions. +Avoid using mutable display names or email addresses as the primary id. + +**[2] `audit.actor.name`:** MAY be a login name, email address, or display name. This value is +informational only; use `audit.actor.id` for stable identity correlation. + +--- + +`audit.actor.type` has the following list of well-known values. If one of them applies, then the respective value MUST be used; otherwise, a custom value MAY be used. + +| Value | Description | Stability | +| --- | --- | --- | +| `service` | An automated service or daemon acting on its own behalf. | ![Development](https://img.shields.io/badge/-development-blue) | +| `system` | An internal system component (scheduler, GC, background job) that is not externally authenticated. | ![Development](https://img.shields.io/badge/-development-blue) | +| `user` | A human user authenticated to the system. | ![Development](https://img.shields.io/badge/-development-blue) | + +## Audit Action Attributes + +Attributes that describe the operation performed by the actor. + +**Attributes:** + +| Key | Stability | Value Type | Description | Example Values | +| --- | --- | --- | --- | --- | +| `audit.action` | ![Development](https://img.shields.io/badge/-development-blue) | string | The auditable operation that was performed. [1] | `LOGIN`; `DELETE`; `GRANT`; `CONFIG_CHANGE` | +| `audit.outcome` | ![Development](https://img.shields.io/badge/-development-blue) | string | The result of the auditable action. | `success`; `failure`; `unknown` | + +**[1] `audit.action`:** SHOULD be an uppercase verb from a controlled vocabulary where possible. +Well-known values include `LOGIN`, `LOGOUT`, `READ`, `CREATE`, `UPDATE`, +`DELETE`, `GRANT`, `REVOKE`, `EXPORT`, `IMPORT`, `EXECUTE`, `APPROVE`, +`REJECT`. Custom values MAY be used when none of the well-known values +applies, but SHOULD be documented in the producing service's changelog. + +--- + +`audit.outcome` has the following list of well-known values. If one of them applies, then the respective value MUST be used; otherwise, a custom value MAY be used. + +| Value | Description | Stability | +| --- | --- | --- | +| `failure` | The action was attempted but did not complete successfully (e.g. authorization denied, validation error, resource not found). | ![Development](https://img.shields.io/badge/-development-blue) | +| `success` | The action completed successfully and produced its intended effect. | ![Development](https://img.shields.io/badge/-development-blue) | +| `unknown` | The outcome could not be determined at the time the event was emitted, for example because the operation is async. | ![Development](https://img.shields.io/badge/-development-blue) | + +## Audit Target Attributes + +Attributes that describe the resource or object that was acted upon. + +**Attributes:** + +| Key | Stability | Value Type | Description | Example Values | +| --- | --- | --- | --- | --- | +| `audit.target.id` | ![Development](https://img.shields.io/badge/-development-blue) | string | The stable identifier of the resource that was the target of the action. [1] | `document-42`; `arn:aws:s3:::my-bucket/key`; `/api/v1/users/9f81` | +| `audit.target.name` | ![Development](https://img.shields.io/badge/-development-blue) | string | A human-readable name or label of the target resource. [2] | `production-deploy`; `Q1-invoice-7734` | +| `audit.target.type` | ![Development](https://img.shields.io/badge/-development-blue) | string | The type or resource kind of the target. [3] | `User`; `apps/v1/Deployment`; `finance.invoice` | + +**[1] `audit.target.id`:** SHOULD be the primary key, ARN, URI, or equivalent durable identifier +of the resource. When acting on a collection rather than a single +resource, this MAY contain the collection identifier. + +**[2] `audit.target.name`:** Informational only. Use `audit.target.id` for stable identity correlation. + +**[3] `audit.target.type`:** SHOULD use a fully-qualified type where available (e.g. a Kubernetes +GroupVersionResource or an IAM resource type). For domain-specific types +a short qualified name MAY be used (e.g. `finance.invoice`). + +## Audit Source Attributes + +Attributes that describe the network origin or calling context of the action. + +**Attributes:** + +| Key | Stability | Value Type | Description | Example Values | +| --- | --- | --- | --- | --- | +| `audit.source.id` | ![Development](https://img.shields.io/badge/-development-blue) | string | A stable identifier for the source system or network endpoint that originated the action. [1] | `192.0.2.42`; `device-uuid-abcd1234` | +| `audit.source.type` | ![Development](https://img.shields.io/badge/-development-blue) | string | The category of origin that initiated the action. [2] | `ip_address`; `device`; `service_mesh_node` | + +**[1] `audit.source.id`:** MAY be an IP address, a device UUID, or a service mesh endpoint id. +Prefer stable identifiers (device UUID) over ephemeral ones (IP address) +when both are available. + +**[2] `audit.source.type`:** Well-known values: `ip_address`, `device`, `service_mesh_node`. +Custom values MAY be used. + +## Audit Integrity Attributes + +Attributes that provide cryptographic evidence that the audit record has not been tampered with since it was emitted. + +**Attributes:** + +| Key | Stability | Value Type | Description | Example Values | +| --- | --- | --- | --- | --- | +| `audit.integrity.algorithm` | ![Development](https://img.shields.io/badge/-development-blue) | string | The algorithm used to compute `audit.integrity.value`. [1] | `ES256`; `EdDSA`; `HMAC-SHA256` | +| `audit.integrity.certificate` | ![Development](https://img.shields.io/badge/-development-blue) | string | A reference to the key or certificate used for `audit.integrity.value`. [2] | `key-2024-01`; `SHA256:ab12cd34...` | +| `audit.integrity.value` | ![Development](https://img.shields.io/badge/-development-blue) | string | Base64url-encoded cryptographic signature or MAC covering this record. [3] | `SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c` | + +**[1] `audit.integrity.algorithm`:** MUST be set as a Resource attribute whenever `audit.integrity.value` is +present on any record emitted by this resource. Use a JWA identifier +(RFC 7518) for asymmetric signatures (e.g. `ES256`, `RS256`, `EdDSA`) or +an IANA MAC Algorithm identifier for symmetric MACs (e.g. `HMAC-SHA256`). + +**[2] `audit.integrity.certificate`:** Acceptable forms (in order of preference): a Key ID / `kid` (JOSE header +parameter), a DER-encoded X.509 certificate Base64url-encoded, an X.509 +certificate fingerprint (SHA-256 hex), or an Issuer + Serial Number pair. +Receivers MUST NOT use this field alone for trust decisions; key +validation MUST be performed out-of-band. + +**[3] `audit.integrity.value`:** The exact input to the signing / MAC operation MUST be the canonical +serialisation of the `AuditRecord` with `audit.integrity.value` absent. +`audit.integrity.algorithm` MUST be set on the emitting Resource whenever +this attribute is present. + +## Audit Sequence Attributes + +Attributes that link audit records into an ordered, tamper-evident chain within a single stream. + +**Attributes:** + +| Key | Stability | Value Type | Description | Example Values | +| --- | --- | --- | --- | --- | +| `audit.prev.hash` | ![Development](https://img.shields.io/badge/-development-blue) | string | SHA-256 hex digest of the `IntegrityHash` field of the immediately preceding record in the same audit stream. [1] | `a3f1c2e4b5d6a7f8e9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2`; `0000000000000000000000000000000000000000000000000000000000000000` | +| `audit.sequence.number` | ![Development](https://img.shields.io/badge/-development-blue) | int | A monotonically increasing counter assigned to each record within a single audit stream. [2] | `1`; `42`; `1000001` | + +**[1] `audit.prev.hash`:** Including the previous record's sink-acknowledged hash in the current +record creates an append-only hash chain. Any retroactive modification +of a record is detectable by re-verifying the chain. Set to the all-zeros +string `"0000000000000000000000000000000000000000000000000000000000000000"` +for the first record in a stream. + +**[2] `audit.sequence.number`:** Compliant sinks and Tier-2 Collectors MUST verify that consecutive +records within the same stream have strictly increasing sequence numbers. +Gaps MUST trigger a gap-detection warning and a security event log entry. +The counter SHOULD start at 1 and increment by 1 per emitted record, but +implementations MAY use a larger step if records can be emitted +concurrently from multiple threads. diff --git a/model/audit/logs.yaml b/model/audit/logs.yaml new file mode 100644 index 0000000000..5ee602d040 --- /dev/null +++ b/model/audit/logs.yaml @@ -0,0 +1,93 @@ +groups: + # --------------------------------------------------------------------------- + # Base audit record attribute group — shared mandatory + optional attributes + # referenced by all audit event definitions. + # --------------------------------------------------------------------------- + - id: audit.record + type: attribute_group + brief: > + Attributes for an audit record emitted through the OTel Audit Logging + signal. An AuditRecord IS a LogRecord; all audit-specific data is carried + as attributes in the `audit.*` namespace. + note: > + The five mandatory attributes (`audit.record.id`, `audit.actor.id`, + `audit.actor.type`, `audit.action`, `audit.outcome`) MUST be present on + every audit record. The SDK MUST auto-generate `audit.record.id` if the + caller omits it. Absence of any other mandatory attribute is a hard error; + the SDK MUST NOT silently drop the record. + + The LogRecord fields used by audit records are: + + * `Timestamp` (MUST) — time the auditable action occurred. + * `ObservedTimestamp` (MUST) — set by SDK if omitted. + * `EventName` (MUST) — e.g. `audit.user.login`, `audit.config.change`. + * `Body` (MAY) — free-form human-readable description; MUST NOT duplicate + mandatory attributes. + * `SeverityNumber` (SHOULD NOT) — not meaningful for audit records. + * `InstrumentationScope` (MUST be left empty). + attributes: + # --- mandatory --- + - ref: audit.record.id + requirement_level: required + - ref: audit.actor.id + requirement_level: required + - ref: audit.actor.type + requirement_level: required + - ref: audit.action + requirement_level: required + - ref: audit.outcome + requirement_level: required + + # --- actor (optional enrichment) --- + - ref: audit.actor.name + requirement_level: opt_in + + # --- target --- + - ref: audit.target.id + requirement_level: + recommended: > + When the action is performed on a specific, identifiable resource. + - ref: audit.target.type + requirement_level: + recommended: > + When `audit.target.id` is present and the resource kind adds + meaningful context for audit review. + - ref: audit.target.name + requirement_level: opt_in + + # --- source / origin --- + - ref: audit.source.id + requirement_level: + recommended: > + When the network origin or calling device of the action is known + and meaningful for compliance review (e.g. PCI-DSS access logging). + - ref: audit.source.type + requirement_level: + recommended: When `audit.source.id` is present. + + # --- integrity (tamper-evidence) --- + - ref: audit.integrity.value + requirement_level: opt_in + - ref: audit.integrity.algorithm + requirement_level: + conditionally_required: > + Required (as a Resource attribute) when `audit.integrity.value` is + present on any record emitted from this resource. + - ref: audit.integrity.certificate + requirement_level: opt_in + + # --- hash-chain ordering --- + - ref: audit.sequence.number + requirement_level: + recommended: > + When the emitting service maintains a monotonic per-stream counter. + Required when `audit.prev.hash` is present. + - ref: audit.prev.hash + requirement_level: + recommended: > + When the emitting service implements a hash chain for tamper + detection. Requires `audit.sequence.number` to be present. + + # --- schema versioning --- + - ref: audit.schema.version + requirement_level: opt_in diff --git a/model/audit/registry.yaml b/model/audit/registry.yaml new file mode 100644 index 0000000000..3f6242a42e --- /dev/null +++ b/model/audit/registry.yaml @@ -0,0 +1,317 @@ +groups: + # --------------------------------------------------------------------------- + # audit.record — identity and deduplication + # --------------------------------------------------------------------------- + - id: registry.audit.record + type: attribute_group + display_name: Audit Record Attributes + brief: > + Attributes that uniquely identify and version an audit record. + attributes: + - id: audit.record.id + type: string + stability: development + brief: > + A stable, globally unique identifier for this audit record. + note: > + The SDK MUST auto-generate a UUID v4 when the caller omits this field. + The value MUST remain identical across all retries of the same record. + Records with the same `audit.record.id` and identical payload hash are + treated as idempotent duplicates by compliant sinks. + examples: + - "3fa85f64-5717-4562-b3fc-2c963f66afa6" + + - id: audit.schema.version + type: string + stability: development + brief: > + The version of the audit semantic conventions schema used by this record. + note: > + Follows semantic versioning (MAJOR.MINOR.PATCH). Receivers MAY use this + value to select an appropriate validation schema. + examples: ["1.0.0", "1.2.0"] + + # --------------------------------------------------------------------------- + # audit.actor — who performed the action + # --------------------------------------------------------------------------- + - id: registry.audit.actor + type: attribute_group + display_name: Audit Actor Attributes + brief: > + Attributes that identify the principal (human user, service, or automated + system component) that initiated the auditable action. + attributes: + - id: audit.actor.id + type: string + stability: development + brief: > + The stable identifier of the actor that performed the action. + note: > + This SHOULD be an opaque, durable identifier (e.g. a user-UUID, service + account name, or IAM principal ARN) that remains stable across sessions. + Avoid using mutable display names or email addresses as the primary id. + examples: + - "u8472" + - "svc-deployer" + - "arn:aws:iam::123456789012:role/DeployRole" + + - id: audit.actor.type + type: + members: + - id: user + value: "user" + brief: A human user authenticated to the system. + stability: development + - id: service + value: "service" + brief: An automated service or daemon acting on its own behalf. + stability: development + - id: system + value: "system" + brief: > + An internal system component (scheduler, GC, background job) that + is not externally authenticated. + stability: development + stability: development + brief: > + The category of principal that performed the action. + examples: ["user", "service", "system"] + + - id: audit.actor.name + type: string + stability: development + brief: > + A human-readable display name or username of the actor. + note: > + MAY be a login name, email address, or display name. This value is + informational only; use `audit.actor.id` for stable identity correlation. + examples: ["alice", "alice@example.com", "Alice Smith"] + + # --------------------------------------------------------------------------- + # audit.action — what was done + # --------------------------------------------------------------------------- + - id: registry.audit.action + type: attribute_group + display_name: Audit Action Attributes + brief: > + Attributes that describe the operation performed by the actor. + attributes: + - id: audit.action + type: string + stability: development + brief: > + The auditable operation that was performed. + note: > + SHOULD be an uppercase verb from a controlled vocabulary where possible. + Well-known values include `LOGIN`, `LOGOUT`, `READ`, `CREATE`, `UPDATE`, + `DELETE`, `GRANT`, `REVOKE`, `EXPORT`, `IMPORT`, `EXECUTE`, `APPROVE`, + `REJECT`. Custom values MAY be used when none of the well-known values + applies, but SHOULD be documented in the producing service's changelog. + examples: + - "LOGIN" + - "DELETE" + - "GRANT" + - "CONFIG_CHANGE" + + - id: audit.outcome + type: + members: + - id: success + value: "success" + brief: > + The action completed successfully and produced its intended effect. + stability: development + - id: failure + value: "failure" + brief: > + The action was attempted but did not complete successfully (e.g. + authorization denied, validation error, resource not found). + stability: development + - id: unknown + value: "unknown" + brief: > + The outcome could not be determined at the time the event was + emitted, for example because the operation is async. + stability: development + stability: development + brief: > + The result of the auditable action. + examples: ["success", "failure", "unknown"] + + # --------------------------------------------------------------------------- + # audit.target — the resource acted upon + # --------------------------------------------------------------------------- + - id: registry.audit.target + type: attribute_group + display_name: Audit Target Attributes + brief: > + Attributes that describe the resource or object that was acted upon. + attributes: + - id: audit.target.id + type: string + stability: development + brief: > + The stable identifier of the resource that was the target of the action. + note: > + SHOULD be the primary key, ARN, URI, or equivalent durable identifier + of the resource. When acting on a collection rather than a single + resource, this MAY contain the collection identifier. + examples: + - "document-42" + - "arn:aws:s3:::my-bucket/key" + - "/api/v1/users/9f81" + + - id: audit.target.type + type: string + stability: development + brief: > + The type or resource kind of the target. + note: > + SHOULD use a fully-qualified type where available (e.g. a Kubernetes + GroupVersionResource or an IAM resource type). For domain-specific types + a short qualified name MAY be used (e.g. `finance.invoice`). + examples: + - "User" + - "apps/v1/Deployment" + - "finance.invoice" + + - id: audit.target.name + type: string + stability: development + brief: > + A human-readable name or label of the target resource. + note: > + Informational only. Use `audit.target.id` for stable identity correlation. + examples: + - "production-deploy" + - "Q1-invoice-7734" + + # --------------------------------------------------------------------------- + # audit.source — network / origin of the action + # --------------------------------------------------------------------------- + - id: registry.audit.source + type: attribute_group + display_name: Audit Source Attributes + brief: > + Attributes that describe the network origin or calling context of the action. + attributes: + - id: audit.source.id + type: string + stability: development + brief: > + A stable identifier for the source system or network endpoint that + originated the action. + note: > + MAY be an IP address, a device UUID, or a service mesh endpoint id. + Prefer stable identifiers (device UUID) over ephemeral ones (IP address) + when both are available. + examples: + - "192.0.2.42" + - "device-uuid-abcd1234" + + - id: audit.source.type + type: string + stability: development + brief: > + The category of origin that initiated the action. + note: > + Well-known values: `ip_address`, `device`, `service_mesh_node`. + Custom values MAY be used. + examples: + - "ip_address" + - "device" + - "service_mesh_node" + + # --------------------------------------------------------------------------- + # audit.integrity — cryptographic tamper-evidence + # --------------------------------------------------------------------------- + - id: registry.audit.integrity + type: attribute_group + display_name: Audit Integrity Attributes + brief: > + Attributes that provide cryptographic evidence that the audit record has + not been tampered with since it was emitted. + attributes: + - id: audit.integrity.value + type: string + stability: development + brief: > + Base64url-encoded cryptographic signature or MAC covering this record. + note: > + The exact input to the signing / MAC operation MUST be the canonical + serialisation of the `AuditRecord` with `audit.integrity.value` absent. + `audit.integrity.algorithm` MUST be set on the emitting Resource whenever + this attribute is present. + examples: + - "SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c" + + - id: audit.integrity.algorithm + type: string + stability: development + brief: > + The algorithm used to compute `audit.integrity.value`. + note: > + MUST be set as a Resource attribute whenever `audit.integrity.value` is + present on any record emitted by this resource. Use a JWA identifier + (RFC 7518) for asymmetric signatures (e.g. `ES256`, `RS256`, `EdDSA`) or + an IANA MAC Algorithm identifier for symmetric MACs (e.g. `HMAC-SHA256`). + examples: + - "ES256" + - "EdDSA" + - "HMAC-SHA256" + + - id: audit.integrity.certificate + type: string + stability: development + brief: > + A reference to the key or certificate used for `audit.integrity.value`. + note: > + Acceptable forms (in order of preference): a Key ID / `kid` (JOSE header + parameter), a DER-encoded X.509 certificate Base64url-encoded, an X.509 + certificate fingerprint (SHA-256 hex), or an Issuer + Serial Number pair. + Receivers MUST NOT use this field alone for trust decisions; key + validation MUST be performed out-of-band. + examples: + - "key-2024-01" + - "SHA256:ab12cd34..." + + # --------------------------------------------------------------------------- + # audit.sequence — hash-chain ordering + # --------------------------------------------------------------------------- + - id: registry.audit.sequence + type: attribute_group + display_name: Audit Sequence Attributes + brief: > + Attributes that link audit records into an ordered, tamper-evident chain + within a single stream. + attributes: + - id: audit.sequence.number + type: int + stability: development + brief: > + A monotonically increasing counter assigned to each record within a + single audit stream. + note: > + Compliant sinks and Tier-2 Collectors MUST verify that consecutive + records within the same stream have strictly increasing sequence numbers. + Gaps MUST trigger a gap-detection warning and a security event log entry. + The counter SHOULD start at 1 and increment by 1 per emitted record, but + implementations MAY use a larger step if records can be emitted + concurrently from multiple threads. + examples: [1, 42, 1000001] + + - id: audit.prev.hash + type: string + stability: development + brief: > + SHA-256 hex digest of the `IntegrityHash` field of the immediately + preceding record in the same audit stream. + note: > + Including the previous record's sink-acknowledged hash in the current + record creates an append-only hash chain. Any retroactive modification + of a record is detectable by re-verifying the chain. Set to the all-zeros + string `"0000000000000000000000000000000000000000000000000000000000000000"` + for the first record in a stream. + examples: + - "a3f1c2e4b5d6a7f8e9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2" + - "0000000000000000000000000000000000000000000000000000000000000000" From 5b2f3a51d449700e9bccc028fafc1eb171587f04 Mon Sep 17 00:00:00 2001 From: Hilmar Falkenberg Date: Wed, 3 Jun 2026 11:00:57 +0200 Subject: [PATCH 03/21] fix: audit.integrity.certificate is a Resource attribute like algorithm MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both audit.integrity.algorithm and audit.integrity.certificate are constants for the lifetime of a service instance — a resource uses one signing key throughout its life. Clarify in registry note, logs.yaml requirement level (conditionally_required as Resource attr), registry reference doc, and audit-logs.md integrity section + attribute table. Signed-off-by: Hilmar Falkenberg --- docs/audit/audit-logs.md | 14 +++++++++++--- docs/registry/attributes/audit.md | 13 ++++++++++--- model/audit/logs.yaml | 6 +++++- model/audit/registry.yaml | 7 +++++++ 4 files changed, 33 insertions(+), 7 deletions(-) diff --git a/docs/audit/audit-logs.md b/docs/audit/audit-logs.md index 9c6d64b5bf..7e0fa85235 100644 --- a/docs/audit/audit-logs.md +++ b/docs/audit/audit-logs.md @@ -129,7 +129,7 @@ namespace. | [`audit.actor.name`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Opt-In` | string | Human-readable display name of the actor. | `alice`; `alice@example.com` | | [`audit.target.name`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Opt-In` | string | Human-readable name of the target resource. | `production-deploy` | | [`audit.integrity.value`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Opt-In` | string | Base64url-encoded cryptographic signature or MAC. | `SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c` | -| [`audit.integrity.certificate`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Opt-In` | string | Reference to the key or certificate for `audit.integrity.value`. | `key-2024-01` | +| [`audit.integrity.certificate`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Conditionally Required` [11] | string | Reference to the key or certificate for `audit.integrity.value`. | `key-2024-01` | | [`audit.schema.version`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Opt-In` | string | Audit schema version string. | `1.0.0` | **[1] `audit.record.id`:** The SDK MUST auto-generate a UUID v4 when the caller omits this field. @@ -165,6 +165,12 @@ per-stream counter. Required when `audit.prev.hash` is present. Requires `audit.sequence.number` to be present. Use the all-zeros string for the very first record in a stream. +**[11] `audit.integrity.certificate`:** Required as a **Resource attribute**, together with +`audit.integrity.algorithm`, when `audit.integrity.value` is present on any +record emitted from this resource. Because a service instance uses a single +signing key for its entire lifetime, both attributes are constant for the +lifetime of the resource and MUST NOT be placed on individual records. + @@ -229,8 +235,10 @@ The integrity triplet (`audit.integrity.value`, `audit.integrity.algorithm`, `audit.integrity.certificate`) enables the audit sink to verify that a record was not altered in transit. -- `audit.integrity.algorithm` is a **Resource attribute** and MUST be the - same for all records emitted by a single service instance. +- `audit.integrity.algorithm` and `audit.integrity.certificate` are both + **Resource attributes**. A service instance uses a single signing key for + its entire lifetime, so both values are constant across all records emitted + by the same resource. They MUST NOT be placed on individual records. - `audit.integrity.value` is the per-record Base64url-encoded signature/MAC over the canonical serialisation of the record (with `audit.integrity.value` itself absent from the input). diff --git a/docs/registry/attributes/audit.md b/docs/registry/attributes/audit.md index b3c4fc3084..61679aa987 100644 --- a/docs/registry/attributes/audit.md +++ b/docs/registry/attributes/audit.md @@ -143,11 +143,18 @@ present on any record emitted by this resource. Use a JWA identifier (RFC 7518) for asymmetric signatures (e.g. `ES256`, `RS256`, `EdDSA`) or an IANA MAC Algorithm identifier for symmetric MACs (e.g. `HMAC-SHA256`). -**[2] `audit.integrity.certificate`:** Acceptable forms (in order of preference): a Key ID / `kid` (JOSE header +**[2] `audit.integrity.certificate`:** MUST be set as a Resource attribute together with `audit.integrity.algorithm` +whenever `audit.integrity.value` is present on any record emitted by this +resource. Because a service instance uses a single signing key for its entire +lifetime, both `audit.integrity.algorithm` and `audit.integrity.certificate` +are constant across all records from the same resource and therefore belong on +the Resource, not on individual records. + +Acceptable forms (in order of preference): a Key ID / `kid` (JOSE header parameter), a DER-encoded X.509 certificate Base64url-encoded, an X.509 certificate fingerprint (SHA-256 hex), or an Issuer + Serial Number pair. -Receivers MUST NOT use this field alone for trust decisions; key -validation MUST be performed out-of-band. +Receivers MUST NOT use this field alone for trust decisions; key validation +MUST be performed out-of-band. **[3] `audit.integrity.value`:** The exact input to the signing / MAC operation MUST be the canonical serialisation of the `AuditRecord` with `audit.integrity.value` absent. diff --git a/model/audit/logs.yaml b/model/audit/logs.yaml index 5ee602d040..289e6ace66 100644 --- a/model/audit/logs.yaml +++ b/model/audit/logs.yaml @@ -74,7 +74,11 @@ groups: Required (as a Resource attribute) when `audit.integrity.value` is present on any record emitted from this resource. - ref: audit.integrity.certificate - requirement_level: opt_in + requirement_level: + conditionally_required: > + Required (as a Resource attribute, together with + `audit.integrity.algorithm`) when `audit.integrity.value` is present + on any record emitted from this resource. # --- hash-chain ordering --- - ref: audit.sequence.number diff --git a/model/audit/registry.yaml b/model/audit/registry.yaml index 3f6242a42e..b3d66cb5d2 100644 --- a/model/audit/registry.yaml +++ b/model/audit/registry.yaml @@ -266,6 +266,13 @@ groups: brief: > A reference to the key or certificate used for `audit.integrity.value`. note: > + MUST be set as a Resource attribute (together with + `audit.integrity.algorithm`) whenever `audit.integrity.value` is present + on any record emitted by this resource. Because a service instance uses a + single signing key for its entire lifetime, both `audit.integrity.algorithm` + and `audit.integrity.certificate` are constant across all records from the + same resource and therefore belong on the Resource, not on individual records. + Acceptable forms (in order of preference): a Key ID / `kid` (JOSE header parameter), a DER-encoded X.509 certificate Base64url-encoded, an X.509 certificate fingerprint (SHA-256 hex), or an Issuer + Serial Number pair. From 5e8915a4548ef410716500c8d80a4e1c0047d5ef Mon Sep 17 00:00:00 2001 From: Hilmar Falkenberg Date: Wed, 3 Jun 2026 11:22:19 +0200 Subject: [PATCH 04/21] chore: add changelog entry for audit logging semconv Signed-off-by: Hilmar Falkenberg --- .chloggen/audit-logging-semconv.yaml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 .chloggen/audit-logging-semconv.yaml diff --git a/.chloggen/audit-logging-semconv.yaml b/.chloggen/audit-logging-semconv.yaml new file mode 100644 index 0000000000..a3f56e50b9 --- /dev/null +++ b/.chloggen/audit-logging-semconv.yaml @@ -0,0 +1,17 @@ +change_type: new_component + +component: audit + +note: Add `audit.*` semantic conventions for the OpenTelemetry Audit Logging signal (OTEP 0267). + +issues: [7] + +subtext: | + Introduces a dedicated `audit.*` attribute namespace for compliance-critical, + lossless audit logging (ISO 27001, SOC 2, PCI-DSS, HIPAA). Attribute groups + cover actor identity (`audit.actor.*`), action and outcome (`audit.action`, + `audit.outcome`), target resource (`audit.target.*`), network source + (`audit.source.*`), per-record cryptographic integrity (`audit.integrity.value`), + and resource-level signing metadata (`audit.integrity.algorithm`, + `audit.integrity.certificate`). An append-only hash-chain is supported via + `audit.sequence.number` and `audit.prev.hash`. From 16db228a3adb5114631d4f360e2916179f5dea07 Mon Sep 17 00:00:00 2001 From: Hilmar Falkenberg Date: Wed, 3 Jun 2026 11:27:06 +0200 Subject: [PATCH 05/21] chore: regenerate audit semconv table via weaver Signed-off-by: Hilmar Falkenberg --- docs/audit/audit-logs.md | 132 +++++++++++++++++++++++---------------- 1 file changed, 79 insertions(+), 53 deletions(-) diff --git a/docs/audit/audit-logs.md b/docs/audit/audit-logs.md index 7e0fa85235..d2ccf18e11 100644 --- a/docs/audit/audit-logs.md +++ b/docs/audit/audit-logs.md @@ -114,62 +114,88 @@ namespace. | Key | Stability | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Value Type | Description | Example Values | | --- | --- | --- | --- | --- | --- | -| [`audit.record.id`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Required` | string | A stable, globally unique identifier for this audit record. [1] | `3fa85f64-5717-4562-b3fc-2c963f66afa6` | +| [`audit.action`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Required` | string | The auditable operation that was performed. [1] | `LOGIN`; `DELETE`; `GRANT`; `CONFIG_CHANGE` | | [`audit.actor.id`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Required` | string | The stable identifier of the actor that performed the action. [2] | `u8472`; `svc-deployer`; `arn:aws:iam::123456789012:role/DeployRole` | | [`audit.actor.type`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Required` | string | The category of principal that performed the action. | `user`; `service`; `system` | -| [`audit.action`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Required` | string | The auditable operation that was performed. [3] | `LOGIN`; `DELETE`; `GRANT`; `CONFIG_CHANGE` | | [`audit.outcome`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Required` | string | The result of the auditable action. | `success`; `failure`; `unknown` | -| [`audit.integrity.algorithm`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Conditionally Required` [4] | string | The algorithm used to compute `audit.integrity.value`. | `ES256`; `EdDSA`; `HMAC-SHA256` | -| [`audit.source.id`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Recommended` [5] | string | A stable identifier for the source system or network endpoint. | `192.0.2.42`; `device-uuid-abcd1234` | -| [`audit.source.type`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Recommended` [6] | string | The category of origin that initiated the action. | `ip_address`; `device`; `service_mesh_node` | -| [`audit.target.id`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Recommended` [7] | string | The stable identifier of the resource that was the target of the action. | `document-42`; `arn:aws:s3:::my-bucket/key`; `/api/v1/users/9f81` | -| [`audit.target.type`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Recommended` [8] | string | The type or resource kind of the target. | `User`; `apps/v1/Deployment`; `finance.invoice` | -| [`audit.sequence.number`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Recommended` [9] | int | A monotonically increasing counter within a single audit stream. | `1`; `42`; `1000001` | -| [`audit.prev.hash`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Recommended` [10] | string | SHA-256 hex digest of the preceding record's `IntegrityHash`. | `a3f1c2e4...`; `000000...` | -| [`audit.actor.name`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Opt-In` | string | Human-readable display name of the actor. | `alice`; `alice@example.com` | -| [`audit.target.name`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Opt-In` | string | Human-readable name of the target resource. | `production-deploy` | -| [`audit.integrity.value`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Opt-In` | string | Base64url-encoded cryptographic signature or MAC. | `SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c` | -| [`audit.integrity.certificate`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Conditionally Required` [11] | string | Reference to the key or certificate for `audit.integrity.value`. | `key-2024-01` | -| [`audit.schema.version`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Opt-In` | string | Audit schema version string. | `1.0.0` | - -**[1] `audit.record.id`:** The SDK MUST auto-generate a UUID v4 when the caller omits this field. -The value MUST remain identical across all retries of the same record. - -**[2] `audit.actor.id`:** SHOULD be a durable, opaque identifier (user-UUID, service account name, -or IAM principal ARN) that remains stable across sessions. Avoid mutable -display names or email addresses as the primary id. - -**[3] `audit.action`:** SHOULD be an uppercase verb. Well-known values: `LOGIN`, `LOGOUT`, `READ`, -`CREATE`, `UPDATE`, `DELETE`, `GRANT`, `REVOKE`, `EXPORT`, `IMPORT`, -`EXECUTE`, `APPROVE`, `REJECT`. Custom values MAY be used but SHOULD be -documented in the producing service's changelog. - -**[4] `audit.integrity.algorithm`:** Required as a **Resource attribute** when `audit.integrity.value` -is present on any record emitted from this resource. - -**[5] `audit.source.id`:** Recommended when the network origin or calling device is known and -meaningful for compliance review (e.g. PCI-DSS access logging). - -**[6] `audit.source.type`:** Recommended when `audit.source.id` is present. - -**[7] `audit.target.id`:** Recommended when the action is performed on a specific, identifiable -resource. - -**[8] `audit.target.type`:** Recommended when `audit.target.id` is present and the resource kind -adds meaningful context for audit review. - -**[9] `audit.sequence.number`:** Recommended when the emitting service maintains a monotonic -per-stream counter. Required when `audit.prev.hash` is present. - -**[10] `audit.prev.hash`:** Recommended when the emitting service implements a hash chain. -Requires `audit.sequence.number` to be present. Use the all-zeros string -for the very first record in a stream. - -**[11] `audit.integrity.certificate`:** Required as a **Resource attribute**, together with -`audit.integrity.algorithm`, when `audit.integrity.value` is present on any -record emitted from this resource. Because a service instance uses a single -signing key for its entire lifetime, both attributes are constant for the -lifetime of the resource and MUST NOT be placed on individual records. +| [`audit.record.id`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Required` | string | A stable, globally unique identifier for this audit record. [3] | `3fa85f64-5717-4562-b3fc-2c963f66afa6` | +| [`audit.integrity.algorithm`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Conditionally Required` [4] | string | The algorithm used to compute `audit.integrity.value`. [5] | `ES256`; `EdDSA`; `HMAC-SHA256` | +| [`audit.integrity.certificate`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Conditionally Required` [6] | string | A reference to the key or certificate used for `audit.integrity.value`. [7] | `key-2024-01`; `SHA256:ab12cd34...` | +| [`audit.prev.hash`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Recommended` [8] | string | SHA-256 hex digest of the `IntegrityHash` field of the immediately preceding record in the same audit stream. [9] | `a3f1c2e4b5d6a7f8e9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2`; `0000000000000000000000000000000000000000000000000000000000000000` | +| [`audit.sequence.number`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Recommended` [10] | int | A monotonically increasing counter assigned to each record within a single audit stream. [11] | `1`; `42`; `1000001` | +| [`audit.source.id`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Recommended` [12] | string | A stable identifier for the source system or network endpoint that originated the action. [13] | `192.0.2.42`; `device-uuid-abcd1234` | +| [`audit.source.type`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Recommended` When `audit.source.id` is present. | string | The category of origin that initiated the action. [14] | `ip_address`; `device`; `service_mesh_node` | +| [`audit.target.id`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Recommended` [15] | string | The stable identifier of the resource that was the target of the action. [16] | `document-42`; `arn:aws:s3:::my-bucket/key`; `/api/v1/users/9f81` | +| [`audit.target.type`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Recommended` [17] | string | The type or resource kind of the target. [18] | `User`; `apps/v1/Deployment`; `finance.invoice` | +| [`audit.actor.name`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Opt-In` | string | A human-readable display name or username of the actor. [19] | `alice`; `alice@example.com`; `Alice Smith` | +| [`audit.integrity.value`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Opt-In` | string | Base64url-encoded cryptographic signature or MAC covering this record. [20] | `SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c` | +| [`audit.schema.version`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Opt-In` | string | The version of the audit semantic conventions schema used by this record. [21] | `1.0.0`; `1.2.0` | +| [`audit.target.name`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Opt-In` | string | A human-readable name or label of the target resource. [22] | `production-deploy`; `Q1-invoice-7734` | + +**[1] `audit.action`:** SHOULD be an uppercase verb from a controlled vocabulary where possible. Well-known values include `LOGIN`, `LOGOUT`, `READ`, `CREATE`, `UPDATE`, `DELETE`, `GRANT`, `REVOKE`, `EXPORT`, `IMPORT`, `EXECUTE`, `APPROVE`, `REJECT`. Custom values MAY be used when none of the well-known values applies, but SHOULD be documented in the producing service's changelog. + +**[2] `audit.actor.id`:** This SHOULD be an opaque, durable identifier (e.g. a user-UUID, service account name, or IAM principal ARN) that remains stable across sessions. Avoid using mutable display names or email addresses as the primary id. + +**[3] `audit.record.id`:** The SDK MUST auto-generate a UUID v4 when the caller omits this field. The value MUST remain identical across all retries of the same record. Records with the same `audit.record.id` and identical payload hash are treated as idempotent duplicates by compliant sinks. + +**[4] `audit.integrity.algorithm`:** Required (as a Resource attribute) when `audit.integrity.value` is present on any record emitted from this resource. + +**[5] `audit.integrity.algorithm`:** MUST be set as a Resource attribute whenever `audit.integrity.value` is present on any record emitted by this resource. Use a JWA identifier (RFC 7518) for asymmetric signatures (e.g. `ES256`, `RS256`, `EdDSA`) or an IANA MAC Algorithm identifier for symmetric MACs (e.g. `HMAC-SHA256`). + +**[6] `audit.integrity.certificate`:** Required (as a Resource attribute, together with `audit.integrity.algorithm`) when `audit.integrity.value` is present on any record emitted from this resource. + +**[7] `audit.integrity.certificate`:** MUST be set as a Resource attribute (together with `audit.integrity.algorithm`) whenever `audit.integrity.value` is present on any record emitted by this resource. Because a service instance uses a single signing key for its entire lifetime, both `audit.integrity.algorithm` and `audit.integrity.certificate` are constant across all records from the same resource and therefore belong on the Resource, not on individual records. +Acceptable forms (in order of preference): a Key ID / `kid` (JOSE header parameter), a DER-encoded X.509 certificate Base64url-encoded, an X.509 certificate fingerprint (SHA-256 hex), or an Issuer + Serial Number pair. Receivers MUST NOT use this field alone for trust decisions; key validation MUST be performed out-of-band. + +**[8] `audit.prev.hash`:** When the emitting service implements a hash chain for tamper detection. Requires `audit.sequence.number` to be present. + +**[9] `audit.prev.hash`:** Including the previous record's sink-acknowledged hash in the current record creates an append-only hash chain. Any retroactive modification of a record is detectable by re-verifying the chain. Set to the all-zeros string `"0000000000000000000000000000000000000000000000000000000000000000"` for the first record in a stream. + +**[10] `audit.sequence.number`:** When the emitting service maintains a monotonic per-stream counter. Required when `audit.prev.hash` is present. + +**[11] `audit.sequence.number`:** Compliant sinks and Tier-2 Collectors MUST verify that consecutive records within the same stream have strictly increasing sequence numbers. Gaps MUST trigger a gap-detection warning and a security event log entry. The counter SHOULD start at 1 and increment by 1 per emitted record, but implementations MAY use a larger step if records can be emitted concurrently from multiple threads. + +**[12] `audit.source.id`:** When the network origin or calling device of the action is known and meaningful for compliance review (e.g. PCI-DSS access logging). + +**[13] `audit.source.id`:** MAY be an IP address, a device UUID, or a service mesh endpoint id. Prefer stable identifiers (device UUID) over ephemeral ones (IP address) when both are available. + +**[14] `audit.source.type`:** Well-known values: `ip_address`, `device`, `service_mesh_node`. Custom values MAY be used. + +**[15] `audit.target.id`:** When the action is performed on a specific, identifiable resource. + +**[16] `audit.target.id`:** SHOULD be the primary key, ARN, URI, or equivalent durable identifier of the resource. When acting on a collection rather than a single resource, this MAY contain the collection identifier. + +**[17] `audit.target.type`:** When `audit.target.id` is present and the resource kind adds meaningful context for audit review. + +**[18] `audit.target.type`:** SHOULD use a fully-qualified type where available (e.g. a Kubernetes GroupVersionResource or an IAM resource type). For domain-specific types a short qualified name MAY be used (e.g. `finance.invoice`). + +**[19] `audit.actor.name`:** MAY be a login name, email address, or display name. This value is informational only; use `audit.actor.id` for stable identity correlation. + +**[20] `audit.integrity.value`:** The exact input to the signing / MAC operation MUST be the canonical serialisation of the `AuditRecord` with `audit.integrity.value` absent. `audit.integrity.algorithm` MUST be set on the emitting Resource whenever this attribute is present. + +**[21] `audit.schema.version`:** Follows semantic versioning (MAJOR.MINOR.PATCH). Receivers MAY use this value to select an appropriate validation schema. + +**[22] `audit.target.name`:** Informational only. Use `audit.target.id` for stable identity correlation. + +--- + +`audit.actor.type` has the following list of well-known values. If one of them applies, then the respective value MUST be used; otherwise, a custom value MAY be used. + +| Value | Description | Stability | +| --- | --- | --- | +| `service` | An automated service or daemon acting on its own behalf. | ![Development](https://img.shields.io/badge/-development-blue) | +| `system` | An internal system component (scheduler, GC, background job) that is not externally authenticated. | ![Development](https://img.shields.io/badge/-development-blue) | +| `user` | A human user authenticated to the system. | ![Development](https://img.shields.io/badge/-development-blue) | + +--- + +`audit.outcome` has the following list of well-known values. If one of them applies, then the respective value MUST be used; otherwise, a custom value MAY be used. + +| Value | Description | Stability | +| --- | --- | --- | +| `failure` | The action was attempted but did not complete successfully (e.g. authorization denied, validation error, resource not found). | ![Development](https://img.shields.io/badge/-development-blue) | +| `success` | The action completed successfully and produced its intended effect. | ![Development](https://img.shields.io/badge/-development-blue) | +| `unknown` | The outcome could not be determined at the time the event was emitted, for example because the operation is async. | ![Development](https://img.shields.io/badge/-development-blue) | From a540cd1c386eaedf9329f116bc2037e4bbfbc18f Mon Sep 17 00:00:00 2001 From: Hilmar Falkenberg Date: Wed, 3 Jun 2026 11:29:04 +0200 Subject: [PATCH 06/21] chore: add area:audit to GH issue templates Signed-off-by: Hilmar Falkenberg --- .github/ISSUE_TEMPLATE/bug_report.yaml | 1 + .github/ISSUE_TEMPLATE/change_proposal.yaml | 1 + .github/ISSUE_TEMPLATE/new-conventions.yaml | 1 + 3 files changed, 3 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index 05a426e838..f0356caf7b 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -26,6 +26,7 @@ body: - area:app - area:artifact - area:aspnetcore + - area:audit - area:aws - area:azure - area:browser diff --git a/.github/ISSUE_TEMPLATE/change_proposal.yaml b/.github/ISSUE_TEMPLATE/change_proposal.yaml index c5d1ab80da..6587d15731 100644 --- a/.github/ISSUE_TEMPLATE/change_proposal.yaml +++ b/.github/ISSUE_TEMPLATE/change_proposal.yaml @@ -18,6 +18,7 @@ body: - area:app - area:artifact - area:aspnetcore + - area:audit - area:aws - area:azure - area:browser diff --git a/.github/ISSUE_TEMPLATE/new-conventions.yaml b/.github/ISSUE_TEMPLATE/new-conventions.yaml index 1f84a59d5b..77669e30df 100644 --- a/.github/ISSUE_TEMPLATE/new-conventions.yaml +++ b/.github/ISSUE_TEMPLATE/new-conventions.yaml @@ -29,6 +29,7 @@ body: - area:app - area:artifact - area:aspnetcore + - area:audit - area:aws - area:azure - area:browser From 2fdc50176ba13f268112984d21141b354f1cd406 Mon Sep 17 00:00:00 2001 From: Hilmar Falkenberg Date: Wed, 3 Jun 2026 11:45:02 +0200 Subject: [PATCH 07/21] fix: rename audit.prev.hash to audit.sequence.prev_hash per naming conventions audit.prev.hash violated the dot-namespacing rule: 'prev' is not a standalone object namespace, it is a property qualifier for 'hash'. Moving it under audit.sequence.* groups it with audit.sequence.number where the rest of the hash-chain mechanics live, consistent with the {object}.{property} pattern (e.g. http.response.status_code). Signed-off-by: Hilmar Falkenberg --- docs/audit/audit-logs.md | 26 +++++++++++++------------- docs/registry/attributes/audit.md | 4 ++-- model/audit/logs.yaml | 4 ++-- model/audit/registry.yaml | 2 +- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/docs/audit/audit-logs.md b/docs/audit/audit-logs.md index d2ccf18e11..c5c5ffd69e 100644 --- a/docs/audit/audit-logs.md +++ b/docs/audit/audit-logs.md @@ -121,8 +121,8 @@ namespace. | [`audit.record.id`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Required` | string | A stable, globally unique identifier for this audit record. [3] | `3fa85f64-5717-4562-b3fc-2c963f66afa6` | | [`audit.integrity.algorithm`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Conditionally Required` [4] | string | The algorithm used to compute `audit.integrity.value`. [5] | `ES256`; `EdDSA`; `HMAC-SHA256` | | [`audit.integrity.certificate`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Conditionally Required` [6] | string | A reference to the key or certificate used for `audit.integrity.value`. [7] | `key-2024-01`; `SHA256:ab12cd34...` | -| [`audit.prev.hash`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Recommended` [8] | string | SHA-256 hex digest of the `IntegrityHash` field of the immediately preceding record in the same audit stream. [9] | `a3f1c2e4b5d6a7f8e9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2`; `0000000000000000000000000000000000000000000000000000000000000000` | -| [`audit.sequence.number`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Recommended` [10] | int | A monotonically increasing counter assigned to each record within a single audit stream. [11] | `1`; `42`; `1000001` | +| [`audit.sequence.number`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Recommended` [8] | int | A monotonically increasing counter assigned to each record within a single audit stream. [9] | `1`; `42`; `1000001` | +| [`audit.sequence.prev_hash`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Recommended` [10] | string | SHA-256 hex digest of the `IntegrityHash` field of the immediately preceding record in the same audit stream. [11] | `a3f1c2e4b5d6a7f8e9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2`; `0000000000000000000000000000000000000000000000000000000000000000` | | [`audit.source.id`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Recommended` [12] | string | A stable identifier for the source system or network endpoint that originated the action. [13] | `192.0.2.42`; `device-uuid-abcd1234` | | [`audit.source.type`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Recommended` When `audit.source.id` is present. | string | The category of origin that initiated the action. [14] | `ip_address`; `device`; `service_mesh_node` | | [`audit.target.id`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Recommended` [15] | string | The stable identifier of the resource that was the target of the action. [16] | `document-42`; `arn:aws:s3:::my-bucket/key`; `/api/v1/users/9f81` | @@ -147,13 +147,13 @@ namespace. **[7] `audit.integrity.certificate`:** MUST be set as a Resource attribute (together with `audit.integrity.algorithm`) whenever `audit.integrity.value` is present on any record emitted by this resource. Because a service instance uses a single signing key for its entire lifetime, both `audit.integrity.algorithm` and `audit.integrity.certificate` are constant across all records from the same resource and therefore belong on the Resource, not on individual records. Acceptable forms (in order of preference): a Key ID / `kid` (JOSE header parameter), a DER-encoded X.509 certificate Base64url-encoded, an X.509 certificate fingerprint (SHA-256 hex), or an Issuer + Serial Number pair. Receivers MUST NOT use this field alone for trust decisions; key validation MUST be performed out-of-band. -**[8] `audit.prev.hash`:** When the emitting service implements a hash chain for tamper detection. Requires `audit.sequence.number` to be present. +**[8] `audit.sequence.number`:** When the emitting service maintains a monotonic per-stream counter. Required when `audit.sequence.prev_hash` is present. -**[9] `audit.prev.hash`:** Including the previous record's sink-acknowledged hash in the current record creates an append-only hash chain. Any retroactive modification of a record is detectable by re-verifying the chain. Set to the all-zeros string `"0000000000000000000000000000000000000000000000000000000000000000"` for the first record in a stream. +**[9] `audit.sequence.number`:** Compliant sinks and Tier-2 Collectors MUST verify that consecutive records within the same stream have strictly increasing sequence numbers. Gaps MUST trigger a gap-detection warning and a security event log entry. The counter SHOULD start at 1 and increment by 1 per emitted record, but implementations MAY use a larger step if records can be emitted concurrently from multiple threads. -**[10] `audit.sequence.number`:** When the emitting service maintains a monotonic per-stream counter. Required when `audit.prev.hash` is present. +**[10] `audit.sequence.prev_hash`:** When the emitting service implements a hash chain for tamper detection. Requires `audit.sequence.number` to be present. -**[11] `audit.sequence.number`:** Compliant sinks and Tier-2 Collectors MUST verify that consecutive records within the same stream have strictly increasing sequence numbers. Gaps MUST trigger a gap-detection warning and a security event log entry. The counter SHOULD start at 1 and increment by 1 per emitted record, but implementations MAY use a larger step if records can be emitted concurrently from multiple threads. +**[11] `audit.sequence.prev_hash`:** Including the previous record's sink-acknowledged hash in the current record creates an append-only hash chain. Any retroactive modification of a record is detectable by re-verifying the chain. Set to the all-zeros string `"0000000000000000000000000000000000000000000000000000000000000000"` for the first record in a stream. **[12] `audit.source.id`:** When the network origin or calling device of the action is known and meaningful for compliance review (e.g. PCI-DSS access logging). @@ -278,17 +278,17 @@ to allow the sink to verify without possessing the signing key. ### Hash-chain ordering -`audit.sequence.number` and `audit.prev.hash` together form an append-only +`audit.sequence.number` and `audit.sequence.prev_hash` together form an append-only hash chain: ``` -Record N: sequence.number=N, prev.hash=IntegrityHash(Record N-1) -Record N+1: sequence.number=N+1, prev.hash=IntegrityHash(Record N) +Record N: sequence.number=N, sequence.prev_hash=IntegrityHash(Record N-1) +Record N+1: sequence.number=N+1, sequence.prev_hash=IntegrityHash(Record N) ``` -Any retroactive modification of Record N causes the `prev.hash` of Record N+1 +Any retroactive modification of Record N causes the `audit.sequence.prev_hash` of Record N+1 to become invalid, making the tampering detectable without re-signing. -Set `audit.prev.hash` to the all-zeros string for the very first record. +Set `audit.sequence.prev_hash` to the all-zeros string for the very first record. ## AuditReceipt @@ -333,7 +333,7 @@ The following invariants MUST be respected by every SDK implementation: | ISO 27001 A.8.17 — Clock sync | SDK warns when `\|Timestamp − ObservedTimestamp\|` > 5 s. | | SOC 2 CC7.2 — Anomaly detection | `audit.records.dropped` metric + operational alert. | | PCI-DSS Req. 10.2 — Audit trails | Mandatory attributes cover all required fields; `audit.source.id` for IP. | -| PCI-DSS Req. 10.5 — Log protection | `audit.integrity.value` + `audit.prev.hash` hash chain. | +| PCI-DSS Req. 10.5 — Log protection | `audit.integrity.value` + `audit.sequence.prev_hash` hash chain. | | HIPAA § 164.312(b) — Audit controls | `audit.actor.*` + `audit.target.*` cover ePHI access logging. | ## Examples @@ -382,7 +382,7 @@ The following invariants MUST be respected by every SDK implementation: "audit.source.id": "device-uuid-abcd1234", "audit.source.type": "device", "audit.sequence.number": 42, - "audit.prev.hash": "a3f1c2e4b5d6a7f8e9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2", + "audit.sequence.prev_hash": "a3f1c2e4b5d6a7f8e9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2", "audit.integrity.value": "SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c", "audit.schema.version": "1.0.0" } diff --git a/docs/registry/attributes/audit.md b/docs/registry/attributes/audit.md index 61679aa987..fd87965330 100644 --- a/docs/registry/attributes/audit.md +++ b/docs/registry/attributes/audit.md @@ -169,10 +169,10 @@ Attributes that link audit records into an ordered, tamper-evident chain within | Key | Stability | Value Type | Description | Example Values | | --- | --- | --- | --- | --- | -| `audit.prev.hash` | ![Development](https://img.shields.io/badge/-development-blue) | string | SHA-256 hex digest of the `IntegrityHash` field of the immediately preceding record in the same audit stream. [1] | `a3f1c2e4b5d6a7f8e9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2`; `0000000000000000000000000000000000000000000000000000000000000000` | +| `audit.sequence.prev_hash` | ![Development](https://img.shields.io/badge/-development-blue) | string | SHA-256 hex digest of the `IntegrityHash` field of the immediately preceding record in the same audit stream. [1] | `a3f1c2e4b5d6a7f8e9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2`; `0000000000000000000000000000000000000000000000000000000000000000` | | `audit.sequence.number` | ![Development](https://img.shields.io/badge/-development-blue) | int | A monotonically increasing counter assigned to each record within a single audit stream. [2] | `1`; `42`; `1000001` | -**[1] `audit.prev.hash`:** Including the previous record's sink-acknowledged hash in the current +**[1] `audit.sequence.prev_hash`:** Including the previous record's sink-acknowledged hash in the current record creates an append-only hash chain. Any retroactive modification of a record is detectable by re-verifying the chain. Set to the all-zeros string `"0000000000000000000000000000000000000000000000000000000000000000"` diff --git a/model/audit/logs.yaml b/model/audit/logs.yaml index 289e6ace66..24439c8e4a 100644 --- a/model/audit/logs.yaml +++ b/model/audit/logs.yaml @@ -85,8 +85,8 @@ groups: requirement_level: recommended: > When the emitting service maintains a monotonic per-stream counter. - Required when `audit.prev.hash` is present. - - ref: audit.prev.hash + Required when `audit.sequence.prev_hash` is present. + - ref: audit.sequence.prev_hash requirement_level: recommended: > When the emitting service implements a hash chain for tamper diff --git a/model/audit/registry.yaml b/model/audit/registry.yaml index b3d66cb5d2..d86cbac098 100644 --- a/model/audit/registry.yaml +++ b/model/audit/registry.yaml @@ -307,7 +307,7 @@ groups: concurrently from multiple threads. examples: [1, 42, 1000001] - - id: audit.prev.hash + - id: audit.sequence.prev_hash type: string stability: development brief: > From a19268f47bc0ea9ac97265087c47a2e9881b9429 Mon Sep 17 00:00:00 2001 From: Hilmar Falkenberg Date: Wed, 3 Jun 2026 12:00:39 +0200 Subject: [PATCH 08/21] chore: regenerate docs/registry/attributes/audit.md via weaver Signed-off-by: Hilmar Falkenberg --- docs/registry/attributes/audit.md | 167 +++++++++++------------------- 1 file changed, 62 insertions(+), 105 deletions(-) diff --git a/docs/registry/attributes/audit.md b/docs/registry/attributes/audit.md index fd87965330..a13641e97e 100644 --- a/docs/registry/attributes/audit.md +++ b/docs/registry/attributes/audit.md @@ -3,32 +3,36 @@ # Audit -- [Audit Record Attributes](#audit-record-attributes) -- [Audit Actor Attributes](#audit-actor-attributes) - [Audit Action Attributes](#audit-action-attributes) -- [Audit Target Attributes](#audit-target-attributes) -- [Audit Source Attributes](#audit-source-attributes) +- [Audit Actor Attributes](#audit-actor-attributes) - [Audit Integrity Attributes](#audit-integrity-attributes) +- [Audit Record Attributes](#audit-record-attributes) - [Audit Sequence Attributes](#audit-sequence-attributes) +- [Audit Source Attributes](#audit-source-attributes) +- [Audit Target Attributes](#audit-target-attributes) -## Audit Record Attributes +## Audit Action Attributes -Attributes that uniquely identify and version an audit record. +Attributes that describe the operation performed by the actor. **Attributes:** | Key | Stability | Value Type | Description | Example Values | | --- | --- | --- | --- | --- | -| `audit.record.id` | ![Development](https://img.shields.io/badge/-development-blue) | string | A stable, globally unique identifier for this audit record. [1] | `3fa85f64-5717-4562-b3fc-2c963f66afa6` | -| `audit.schema.version` | ![Development](https://img.shields.io/badge/-development-blue) | string | The version of the audit semantic conventions schema used by this record. [2] | `1.0.0`; `1.2.0` | +| `audit.action` | ![Development](https://img.shields.io/badge/-development-blue) | string | The auditable operation that was performed. [1] | `LOGIN`; `DELETE`; `GRANT`; `CONFIG_CHANGE` | +| `audit.outcome` | ![Development](https://img.shields.io/badge/-development-blue) | string | The result of the auditable action. | `success`; `failure`; `unknown` | + +**[1] `audit.action`:** SHOULD be an uppercase verb from a controlled vocabulary where possible. Well-known values include `LOGIN`, `LOGOUT`, `READ`, `CREATE`, `UPDATE`, `DELETE`, `GRANT`, `REVOKE`, `EXPORT`, `IMPORT`, `EXECUTE`, `APPROVE`, `REJECT`. Custom values MAY be used when none of the well-known values applies, but SHOULD be documented in the producing service's changelog. -**[1] `audit.record.id`:** The SDK MUST auto-generate a UUID v4 when the caller omits this field. -The value MUST remain identical across all retries of the same record. -Records with the same `audit.record.id` and identical payload hash are -treated as idempotent duplicates by compliant sinks. +--- + +`audit.outcome` has the following list of well-known values. If one of them applies, then the respective value MUST be used; otherwise, a custom value MAY be used. -**[2] `audit.schema.version`:** Follows semantic versioning (MAJOR.MINOR.PATCH). Receivers MAY use this -value to select an appropriate validation schema. +| Value | Description | Stability | +| --- | --- | --- | +| `failure` | The action was attempted but did not complete successfully (e.g. authorization denied, validation error, resource not found). | ![Development](https://img.shields.io/badge/-development-blue) | +| `success` | The action completed successfully and produced its intended effect. | ![Development](https://img.shields.io/badge/-development-blue) | +| `unknown` | The outcome could not be determined at the time the event was emitted, for example because the operation is async. | ![Development](https://img.shields.io/badge/-development-blue) | ## Audit Actor Attributes @@ -38,16 +42,13 @@ Attributes that identify the principal (human user, service, or automated system | Key | Stability | Value Type | Description | Example Values | | --- | --- | --- | --- | --- | -| `audit.actor.id` | ![Development](https://img.shields.io/badge/-development-blue) | string | The stable identifier of the actor that performed the action. [1] | `u8472`; `svc-deployer`; `arn:aws:iam::123456789012:role/DeployRole` | -| `audit.actor.name` | ![Development](https://img.shields.io/badge/-development-blue) | string | A human-readable display name or username of the actor. [2] | `alice`; `alice@example.com`; `Alice Smith` | +| `audit.actor.id` | ![Development](https://img.shields.io/badge/-development-blue) | string | The stable identifier of the actor that performed the action. [2] | `u8472`; `svc-deployer`; `arn:aws:iam::123456789012:role/DeployRole` | +| `audit.actor.name` | ![Development](https://img.shields.io/badge/-development-blue) | string | A human-readable display name or username of the actor. [3] | `alice`; `alice@example.com`; `Alice Smith` | | `audit.actor.type` | ![Development](https://img.shields.io/badge/-development-blue) | string | The category of principal that performed the action. | `user`; `service`; `system` | -**[1] `audit.actor.id`:** This SHOULD be an opaque, durable identifier (e.g. a user-UUID, service -account name, or IAM principal ARN) that remains stable across sessions. -Avoid using mutable display names or email addresses as the primary id. +**[2] `audit.actor.id`:** This SHOULD be an opaque, durable identifier (e.g. a user-UUID, service account name, or IAM principal ARN) that remains stable across sessions. Avoid using mutable display names or email addresses as the primary id. -**[2] `audit.actor.name`:** MAY be a login name, email address, or display name. This value is -informational only; use `audit.actor.id` for stable identity correlation. +**[3] `audit.actor.name`:** MAY be a login name, email address, or display name. This value is informational only; use `audit.actor.id` for stable identity correlation. --- @@ -59,128 +60,84 @@ informational only; use `audit.actor.id` for stable identity correlation. | `system` | An internal system component (scheduler, GC, background job) that is not externally authenticated. | ![Development](https://img.shields.io/badge/-development-blue) | | `user` | A human user authenticated to the system. | ![Development](https://img.shields.io/badge/-development-blue) | -## Audit Action Attributes +## Audit Integrity Attributes -Attributes that describe the operation performed by the actor. +Attributes that provide cryptographic evidence that the audit record has not been tampered with since it was emitted. **Attributes:** | Key | Stability | Value Type | Description | Example Values | | --- | --- | --- | --- | --- | -| `audit.action` | ![Development](https://img.shields.io/badge/-development-blue) | string | The auditable operation that was performed. [1] | `LOGIN`; `DELETE`; `GRANT`; `CONFIG_CHANGE` | -| `audit.outcome` | ![Development](https://img.shields.io/badge/-development-blue) | string | The result of the auditable action. | `success`; `failure`; `unknown` | +| `audit.integrity.algorithm` | ![Development](https://img.shields.io/badge/-development-blue) | string | The algorithm used to compute `audit.integrity.value`. [4] | `ES256`; `EdDSA`; `HMAC-SHA256` | +| `audit.integrity.certificate` | ![Development](https://img.shields.io/badge/-development-blue) | string | A reference to the key or certificate used for `audit.integrity.value`. [5] | `key-2024-01`; `SHA256:ab12cd34...` | +| `audit.integrity.value` | ![Development](https://img.shields.io/badge/-development-blue) | string | Base64url-encoded cryptographic signature or MAC covering this record. [6] | `SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c` | -**[1] `audit.action`:** SHOULD be an uppercase verb from a controlled vocabulary where possible. -Well-known values include `LOGIN`, `LOGOUT`, `READ`, `CREATE`, `UPDATE`, -`DELETE`, `GRANT`, `REVOKE`, `EXPORT`, `IMPORT`, `EXECUTE`, `APPROVE`, -`REJECT`. Custom values MAY be used when none of the well-known values -applies, but SHOULD be documented in the producing service's changelog. +**[4] `audit.integrity.algorithm`:** MUST be set as a Resource attribute whenever `audit.integrity.value` is present on any record emitted by this resource. Use a JWA identifier (RFC 7518) for asymmetric signatures (e.g. `ES256`, `RS256`, `EdDSA`) or an IANA MAC Algorithm identifier for symmetric MACs (e.g. `HMAC-SHA256`). ---- +**[5] `audit.integrity.certificate`:** MUST be set as a Resource attribute (together with `audit.integrity.algorithm`) whenever `audit.integrity.value` is present on any record emitted by this resource. Because a service instance uses a single signing key for its entire lifetime, both `audit.integrity.algorithm` and `audit.integrity.certificate` are constant across all records from the same resource and therefore belong on the Resource, not on individual records. +Acceptable forms (in order of preference): a Key ID / `kid` (JOSE header parameter), a DER-encoded X.509 certificate Base64url-encoded, an X.509 certificate fingerprint (SHA-256 hex), or an Issuer + Serial Number pair. Receivers MUST NOT use this field alone for trust decisions; key validation MUST be performed out-of-band. -`audit.outcome` has the following list of well-known values. If one of them applies, then the respective value MUST be used; otherwise, a custom value MAY be used. - -| Value | Description | Stability | -| --- | --- | --- | -| `failure` | The action was attempted but did not complete successfully (e.g. authorization denied, validation error, resource not found). | ![Development](https://img.shields.io/badge/-development-blue) | -| `success` | The action completed successfully and produced its intended effect. | ![Development](https://img.shields.io/badge/-development-blue) | -| `unknown` | The outcome could not be determined at the time the event was emitted, for example because the operation is async. | ![Development](https://img.shields.io/badge/-development-blue) | +**[6] `audit.integrity.value`:** The exact input to the signing / MAC operation MUST be the canonical serialisation of the `AuditRecord` with `audit.integrity.value` absent. `audit.integrity.algorithm` MUST be set on the emitting Resource whenever this attribute is present. -## Audit Target Attributes +## Audit Record Attributes -Attributes that describe the resource or object that was acted upon. +Attributes that uniquely identify and version an audit record. **Attributes:** | Key | Stability | Value Type | Description | Example Values | | --- | --- | --- | --- | --- | -| `audit.target.id` | ![Development](https://img.shields.io/badge/-development-blue) | string | The stable identifier of the resource that was the target of the action. [1] | `document-42`; `arn:aws:s3:::my-bucket/key`; `/api/v1/users/9f81` | -| `audit.target.name` | ![Development](https://img.shields.io/badge/-development-blue) | string | A human-readable name or label of the target resource. [2] | `production-deploy`; `Q1-invoice-7734` | -| `audit.target.type` | ![Development](https://img.shields.io/badge/-development-blue) | string | The type or resource kind of the target. [3] | `User`; `apps/v1/Deployment`; `finance.invoice` | - -**[1] `audit.target.id`:** SHOULD be the primary key, ARN, URI, or equivalent durable identifier -of the resource. When acting on a collection rather than a single -resource, this MAY contain the collection identifier. +| `audit.record.id` | ![Development](https://img.shields.io/badge/-development-blue) | string | A stable, globally unique identifier for this audit record. [7] | `3fa85f64-5717-4562-b3fc-2c963f66afa6` | +| `audit.schema.version` | ![Development](https://img.shields.io/badge/-development-blue) | string | The version of the audit semantic conventions schema used by this record. [8] | `1.0.0`; `1.2.0` | -**[2] `audit.target.name`:** Informational only. Use `audit.target.id` for stable identity correlation. +**[7] `audit.record.id`:** The SDK MUST auto-generate a UUID v4 when the caller omits this field. The value MUST remain identical across all retries of the same record. Records with the same `audit.record.id` and identical payload hash are treated as idempotent duplicates by compliant sinks. -**[3] `audit.target.type`:** SHOULD use a fully-qualified type where available (e.g. a Kubernetes -GroupVersionResource or an IAM resource type). For domain-specific types -a short qualified name MAY be used (e.g. `finance.invoice`). +**[8] `audit.schema.version`:** Follows semantic versioning (MAJOR.MINOR.PATCH). Receivers MAY use this value to select an appropriate validation schema. -## Audit Source Attributes +## Audit Sequence Attributes -Attributes that describe the network origin or calling context of the action. +Attributes that link audit records into an ordered, tamper-evident chain within a single stream. **Attributes:** | Key | Stability | Value Type | Description | Example Values | | --- | --- | --- | --- | --- | -| `audit.source.id` | ![Development](https://img.shields.io/badge/-development-blue) | string | A stable identifier for the source system or network endpoint that originated the action. [1] | `192.0.2.42`; `device-uuid-abcd1234` | -| `audit.source.type` | ![Development](https://img.shields.io/badge/-development-blue) | string | The category of origin that initiated the action. [2] | `ip_address`; `device`; `service_mesh_node` | +| `audit.sequence.number` | ![Development](https://img.shields.io/badge/-development-blue) | int | A monotonically increasing counter assigned to each record within a single audit stream. [9] | `1`; `42`; `1000001` | +| `audit.sequence.prev_hash` | ![Development](https://img.shields.io/badge/-development-blue) | string | SHA-256 hex digest of the `IntegrityHash` field of the immediately preceding record in the same audit stream. [10] | `a3f1c2e4b5d6a7f8e9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2`; `0000000000000000000000000000000000000000000000000000000000000000` | -**[1] `audit.source.id`:** MAY be an IP address, a device UUID, or a service mesh endpoint id. -Prefer stable identifiers (device UUID) over ephemeral ones (IP address) -when both are available. +**[9] `audit.sequence.number`:** Compliant sinks and Tier-2 Collectors MUST verify that consecutive records within the same stream have strictly increasing sequence numbers. Gaps MUST trigger a gap-detection warning and a security event log entry. The counter SHOULD start at 1 and increment by 1 per emitted record, but implementations MAY use a larger step if records can be emitted concurrently from multiple threads. -**[2] `audit.source.type`:** Well-known values: `ip_address`, `device`, `service_mesh_node`. -Custom values MAY be used. +**[10] `audit.sequence.prev_hash`:** Including the previous record's sink-acknowledged hash in the current record creates an append-only hash chain. Any retroactive modification of a record is detectable by re-verifying the chain. Set to the all-zeros string `"0000000000000000000000000000000000000000000000000000000000000000"` for the first record in a stream. -## Audit Integrity Attributes +## Audit Source Attributes -Attributes that provide cryptographic evidence that the audit record has not been tampered with since it was emitted. +Attributes that describe the network origin or calling context of the action. **Attributes:** | Key | Stability | Value Type | Description | Example Values | | --- | --- | --- | --- | --- | -| `audit.integrity.algorithm` | ![Development](https://img.shields.io/badge/-development-blue) | string | The algorithm used to compute `audit.integrity.value`. [1] | `ES256`; `EdDSA`; `HMAC-SHA256` | -| `audit.integrity.certificate` | ![Development](https://img.shields.io/badge/-development-blue) | string | A reference to the key or certificate used for `audit.integrity.value`. [2] | `key-2024-01`; `SHA256:ab12cd34...` | -| `audit.integrity.value` | ![Development](https://img.shields.io/badge/-development-blue) | string | Base64url-encoded cryptographic signature or MAC covering this record. [3] | `SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c` | - -**[1] `audit.integrity.algorithm`:** MUST be set as a Resource attribute whenever `audit.integrity.value` is -present on any record emitted by this resource. Use a JWA identifier -(RFC 7518) for asymmetric signatures (e.g. `ES256`, `RS256`, `EdDSA`) or -an IANA MAC Algorithm identifier for symmetric MACs (e.g. `HMAC-SHA256`). - -**[2] `audit.integrity.certificate`:** MUST be set as a Resource attribute together with `audit.integrity.algorithm` -whenever `audit.integrity.value` is present on any record emitted by this -resource. Because a service instance uses a single signing key for its entire -lifetime, both `audit.integrity.algorithm` and `audit.integrity.certificate` -are constant across all records from the same resource and therefore belong on -the Resource, not on individual records. - -Acceptable forms (in order of preference): a Key ID / `kid` (JOSE header -parameter), a DER-encoded X.509 certificate Base64url-encoded, an X.509 -certificate fingerprint (SHA-256 hex), or an Issuer + Serial Number pair. -Receivers MUST NOT use this field alone for trust decisions; key validation -MUST be performed out-of-band. - -**[3] `audit.integrity.value`:** The exact input to the signing / MAC operation MUST be the canonical -serialisation of the `AuditRecord` with `audit.integrity.value` absent. -`audit.integrity.algorithm` MUST be set on the emitting Resource whenever -this attribute is present. +| `audit.source.id` | ![Development](https://img.shields.io/badge/-development-blue) | string | A stable identifier for the source system or network endpoint that originated the action. [11] | `192.0.2.42`; `device-uuid-abcd1234` | +| `audit.source.type` | ![Development](https://img.shields.io/badge/-development-blue) | string | The category of origin that initiated the action. [12] | `ip_address`; `device`; `service_mesh_node` | -## Audit Sequence Attributes +**[11] `audit.source.id`:** MAY be an IP address, a device UUID, or a service mesh endpoint id. Prefer stable identifiers (device UUID) over ephemeral ones (IP address) when both are available. -Attributes that link audit records into an ordered, tamper-evident chain within a single stream. +**[12] `audit.source.type`:** Well-known values: `ip_address`, `device`, `service_mesh_node`. Custom values MAY be used. + +## Audit Target Attributes + +Attributes that describe the resource or object that was acted upon. **Attributes:** | Key | Stability | Value Type | Description | Example Values | | --- | --- | --- | --- | --- | -| `audit.sequence.prev_hash` | ![Development](https://img.shields.io/badge/-development-blue) | string | SHA-256 hex digest of the `IntegrityHash` field of the immediately preceding record in the same audit stream. [1] | `a3f1c2e4b5d6a7f8e9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2`; `0000000000000000000000000000000000000000000000000000000000000000` | -| `audit.sequence.number` | ![Development](https://img.shields.io/badge/-development-blue) | int | A monotonically increasing counter assigned to each record within a single audit stream. [2] | `1`; `42`; `1000001` | - -**[1] `audit.sequence.prev_hash`:** Including the previous record's sink-acknowledged hash in the current -record creates an append-only hash chain. Any retroactive modification -of a record is detectable by re-verifying the chain. Set to the all-zeros -string `"0000000000000000000000000000000000000000000000000000000000000000"` -for the first record in a stream. - -**[2] `audit.sequence.number`:** Compliant sinks and Tier-2 Collectors MUST verify that consecutive -records within the same stream have strictly increasing sequence numbers. -Gaps MUST trigger a gap-detection warning and a security event log entry. -The counter SHOULD start at 1 and increment by 1 per emitted record, but -implementations MAY use a larger step if records can be emitted -concurrently from multiple threads. +| `audit.target.id` | ![Development](https://img.shields.io/badge/-development-blue) | string | The stable identifier of the resource that was the target of the action. [13] | `document-42`; `arn:aws:s3:::my-bucket/key`; `/api/v1/users/9f81` | +| `audit.target.name` | ![Development](https://img.shields.io/badge/-development-blue) | string | A human-readable name or label of the target resource. [14] | `production-deploy`; `Q1-invoice-7734` | +| `audit.target.type` | ![Development](https://img.shields.io/badge/-development-blue) | string | The type or resource kind of the target. [15] | `User`; `apps/v1/Deployment`; `finance.invoice` | + +**[13] `audit.target.id`:** SHOULD be the primary key, ARN, URI, or equivalent durable identifier of the resource. When acting on a collection rather than a single resource, this MAY contain the collection identifier. + +**[14] `audit.target.name`:** Informational only. Use `audit.target.id` for stable identity correlation. + +**[15] `audit.target.type`:** SHOULD use a fully-qualified type where available (e.g. a Kubernetes GroupVersionResource or an IAM resource type). For domain-specific types a short qualified name MAY be used (e.g. `finance.invoice`). From 9dffcc872cd322e3bb30c13f9a3e5a776fc70733 Mon Sep 17 00:00:00 2001 From: Hilmar Falkenberg Date: Wed, 3 Jun 2026 12:05:11 +0200 Subject: [PATCH 09/21] chore: add audit namespace to registry attributes README Signed-off-by: Hilmar Falkenberg --- docs/registry/attributes/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/registry/attributes/README.md b/docs/registry/attributes/README.md index 64c71e2869..80c0928acd 100644 --- a/docs/registry/attributes/README.md +++ b/docs/registry/attributes/README.md @@ -35,6 +35,7 @@ Currently, the following namespaces exist: - [App](app.md) - [Artifact](artifact.md) - [Aspnetcore](aspnetcore.md) +- [Audit](audit.md) - [AWS](aws.md) - [Azure](azure.md) - [Browser](browser.md) From 01beb80624c861bd7da3d8cae8e53828aa55227d Mon Sep 17 00:00:00 2001 From: Hilmar Falkenberg Date: Thu, 30 Jul 2026 14:43:23 +0200 Subject: [PATCH 10/21] prepare pull app Signed-off-by: Hilmar Falkenberg --- .github/pull.yml | 12 ++++++++++++ .github/workflows/sync-fork.yaml | 16 ---------------- 2 files changed, 12 insertions(+), 16 deletions(-) create mode 100644 .github/pull.yml delete mode 100644 .github/workflows/sync-fork.yaml diff --git a/.github/pull.yml b/.github/pull.yml new file mode 100644 index 0000000000..bfb4fe9fd7 --- /dev/null +++ b/.github/pull.yml @@ -0,0 +1,12 @@ +# .github/pull.yml +version: "1" +rules: + - base: main + upstream: open-telemetry:main + mergeMethod: rebase + conflictReviewers: + - name: @apeirora/audit-logger + - base: upstream + upstream: open-telemetry:main + mergeMethod: hardreset + mergeUnstable: true diff --git a/.github/workflows/sync-fork.yaml b/.github/workflows/sync-fork.yaml deleted file mode 100644 index de520f2bc0..0000000000 --- a/.github/workflows/sync-fork.yaml +++ /dev/null @@ -1,16 +0,0 @@ -name: sync-fork -on: - schedule: - - cron: '4 2 * * 4,2' - workflow_dispatch: -jobs: - sync-fork: - runs-on: ubuntu-latest - permissions: - contents: write - steps: - - run: gh repo sync $REPOSITORY -b $BRANCH_NAME - env: - GITHUB_TOKEN: ${{ secrets.SYNC_FORK_TOKEN }} - REPOSITORY: ${{ github.repository }} - BRANCH_NAME: ${{ github.ref_name }} From fa44e11479bb7862c228261db83bfdf3dcdcda13 Mon Sep 17 00:00:00 2001 From: Hilmar Falkenberg Date: Thu, 30 Jul 2026 14:56:49 +0200 Subject: [PATCH 11/21] prepare pull app Signed-off-by: Hilmar Falkenberg --- .github/pull.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/pull.yml b/.github/pull.yml index bfb4fe9fd7..46b1e48586 100644 --- a/.github/pull.yml +++ b/.github/pull.yml @@ -5,7 +5,7 @@ rules: upstream: open-telemetry:main mergeMethod: rebase conflictReviewers: - - name: @apeirora/audit-logger + - apeirora/audit-logger - base: upstream upstream: open-telemetry:main mergeMethod: hardreset From fd5cb45fb73fc85cefcc88a9af78194b3a97bcdd Mon Sep 17 00:00:00 2001 From: Hilmar Falkenberg Date: Wed, 9 Sep 2026 11:56:08 +0200 Subject: [PATCH 12/21] revert pull app Signed-off-by: Hilmar Falkenberg --- .github/pull.yml | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 .github/pull.yml diff --git a/.github/pull.yml b/.github/pull.yml deleted file mode 100644 index 46b1e48586..0000000000 --- a/.github/pull.yml +++ /dev/null @@ -1,12 +0,0 @@ -# .github/pull.yml -version: "1" -rules: - - base: main - upstream: open-telemetry:main - mergeMethod: rebase - conflictReviewers: - - apeirora/audit-logger - - base: upstream - upstream: open-telemetry:main - mergeMethod: hardreset - mergeUnstable: true From 36decb7c4643ce4ebf7928598fa24022878de3d7 Mon Sep 17 00:00:00 2001 From: Hilmar Falkenberg Date: Wed, 9 Sep 2026 12:18:26 +0200 Subject: [PATCH 13/21] sync with latest spec Signed-off-by: Hilmar Falkenberg --- docs/audit/audit-logs.md | 79 ++++++++++++++++++---------- docs/registry/attributes/audit.md | 59 +++++++++++++-------- model/audit/logs.yaml | 25 +++++++++ model/audit/registry.yaml | 87 ++++++++++++++++++++++++++----- 4 files changed, 187 insertions(+), 63 deletions(-) diff --git a/docs/audit/audit-logs.md b/docs/audit/audit-logs.md index c5c5ffd69e..a99633a951 100644 --- a/docs/audit/audit-logs.md +++ b/docs/audit/audit-logs.md @@ -120,17 +120,22 @@ namespace. | [`audit.outcome`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Required` | string | The result of the auditable action. | `success`; `failure`; `unknown` | | [`audit.record.id`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Required` | string | A stable, globally unique identifier for this audit record. [3] | `3fa85f64-5717-4562-b3fc-2c963f66afa6` | | [`audit.integrity.algorithm`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Conditionally Required` [4] | string | The algorithm used to compute `audit.integrity.value`. [5] | `ES256`; `EdDSA`; `HMAC-SHA256` | -| [`audit.integrity.certificate`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Conditionally Required` [6] | string | A reference to the key or certificate used for `audit.integrity.value`. [7] | `key-2024-01`; `SHA256:ab12cd34...` | -| [`audit.sequence.number`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Recommended` [8] | int | A monotonically increasing counter assigned to each record within a single audit stream. [9] | `1`; `42`; `1000001` | -| [`audit.sequence.prev_hash`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Recommended` [10] | string | SHA-256 hex digest of the `IntegrityHash` field of the immediately preceding record in the same audit stream. [11] | `a3f1c2e4b5d6a7f8e9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2`; `0000000000000000000000000000000000000000000000000000000000000000` | -| [`audit.source.id`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Recommended` [12] | string | A stable identifier for the source system or network endpoint that originated the action. [13] | `192.0.2.42`; `device-uuid-abcd1234` | -| [`audit.source.type`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Recommended` When `audit.source.id` is present. | string | The category of origin that initiated the action. [14] | `ip_address`; `device`; `service_mesh_node` | -| [`audit.target.id`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Recommended` [15] | string | The stable identifier of the resource that was the target of the action. [16] | `document-42`; `arn:aws:s3:::my-bucket/key`; `/api/v1/users/9f81` | -| [`audit.target.type`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Recommended` [17] | string | The type or resource kind of the target. [18] | `User`; `apps/v1/Deployment`; `finance.invoice` | -| [`audit.actor.name`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Opt-In` | string | A human-readable display name or username of the actor. [19] | `alice`; `alice@example.com`; `Alice Smith` | -| [`audit.integrity.value`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Opt-In` | string | Base64url-encoded cryptographic signature or MAC covering this record. [20] | `SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c` | -| [`audit.schema.version`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Opt-In` | string | The version of the audit semantic conventions schema used by this record. [21] | `1.0.0`; `1.2.0` | -| [`audit.target.name`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Opt-In` | string | A human-readable name or label of the target resource. [22] | `production-deploy`; `Q1-invoice-7734` | +| [`audit.integrity.canonicalization`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Conditionally Required` [6] | string | The canonicalization scheme applied to the record before signing or MACing. [7] | `jcs` | +| [`audit.integrity.certificate`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Conditionally Required` [8] | string | A reference to the key or certificate used for `audit.integrity.value`. [9] | `key-2024-01`; `SHA256:ab12cd34...` | +| [`audit.sequence.end`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Conditionally Required` [10] | boolean | Set to `true` on the last record of a gracefully closed audit stream. [11] | `true` | +| [`audit.integrity.signer`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Recommended` When `audit.integrity.value` is present. | string | Identifies which tier produced the integrity proof in `audit.integrity.value`. [12] | `producer`; `collector` | +| [`audit.sequence.number`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Recommended` [13] | int | A monotonically increasing counter assigned to each record within a single audit stream. [14] | `1`; `42`; `1000001` | +| [`audit.sequence.prev_hash`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Recommended` [15] | string | SHA-256 hex digest of the `IntegrityHash` field of the immediately preceding record in the same audit stream. [16] | `a3f1c2e4b5d6a7f8e9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2` | +| [`audit.sequence.prev_record_id`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Recommended` [17] | string | The `audit.record.id` of the immediately preceding record in the same audit stream. [18] | `3fa85f64-5717-4562-b3fc-2c963f66afa6` | +| [`audit.sequence.stream_id`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Recommended` [19] | string | An opaque identifier that scopes the hash chain to a single audit stream. [20] | `7c9e6679-7425-40de-944b-e07fc1f90ae7` | +| [`audit.source.id`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Recommended` [21] | string | A stable identifier for the source system or network endpoint that originated the action. [22] | `192.0.2.42`; `device-uuid-abcd1234` | +| [`audit.source.type`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Recommended` When `audit.source.id` is present. | string | The category of origin that initiated the action. [23] | `ipv4`; `ipv6`; `hostname` | +| [`audit.target.id`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Recommended` [24] | string | The stable identifier of the resource that was the target of the action. [25] | `document-42`; `arn:aws:s3:::my-bucket/key`; `/api/v1/users/9f81` | +| [`audit.target.type`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Recommended` [26] | string | The type or resource kind of the target. [27] | `User`; `apps/v1/Deployment`; `finance.invoice` | +| [`audit.actor.name`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Opt-In` | string | A human-readable display name or username of the actor. [28] | `alice`; `alice@example.com`; `Alice Smith` | +| [`audit.integrity.value`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Opt-In` | string | Base64-encoded cryptographic signature or MAC covering this record. [29] | `SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c` | +| [`audit.schema.version`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Opt-In` | string | The version of the audit semantic conventions schema used by this record. [30] | `1.0.0`; `1.2.0` | +| [`audit.target.name`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Opt-In` | string | A human-readable name or label of the target resource. [31] | `production-deploy`; `Q1-invoice-7734` | **[1] `audit.action`:** SHOULD be an uppercase verb from a controlled vocabulary where possible. Well-known values include `LOGIN`, `LOGOUT`, `READ`, `CREATE`, `UPDATE`, `DELETE`, `GRANT`, `REVOKE`, `EXPORT`, `IMPORT`, `EXECUTE`, `APPROVE`, `REJECT`. Custom values MAY be used when none of the well-known values applies, but SHOULD be documented in the producing service's changelog. @@ -142,40 +147,58 @@ namespace. **[5] `audit.integrity.algorithm`:** MUST be set as a Resource attribute whenever `audit.integrity.value` is present on any record emitted by this resource. Use a JWA identifier (RFC 7518) for asymmetric signatures (e.g. `ES256`, `RS256`, `EdDSA`) or an IANA MAC Algorithm identifier for symmetric MACs (e.g. `HMAC-SHA256`). -**[6] `audit.integrity.certificate`:** Required (as a Resource attribute, together with `audit.integrity.algorithm`) when `audit.integrity.value` is present on any record emitted from this resource. +**[6] `audit.integrity.canonicalization`:** Required when a canonicalization scheme other than `jcs` (RFC 8785) is used. Omit when `jcs` is used. -**[7] `audit.integrity.certificate`:** MUST be set as a Resource attribute (together with `audit.integrity.algorithm`) whenever `audit.integrity.value` is present on any record emitted by this resource. Because a service instance uses a single signing key for its entire lifetime, both `audit.integrity.algorithm` and `audit.integrity.certificate` are constant across all records from the same resource and therefore belong on the Resource, not on individual records. +**[7] `audit.integrity.canonicalization`:** Defaults to `jcs` (RFC 8785 JSON Canonicalization Scheme). Set explicitly when any other canonicalization is used so that verifiers can reproduce the exact byte sequence that was signed. MUST be omitted when `jcs` is used and the default is sufficient. + +**[8] `audit.integrity.certificate`:** Required (as a Resource attribute, together with `audit.integrity.algorithm`) when `audit.integrity.value` is present on any record emitted from this resource. + +**[9] `audit.integrity.certificate`:** MUST be set as a Resource attribute (together with `audit.integrity.algorithm`) whenever `audit.integrity.value` is present on any record emitted by this resource. Because a service instance uses a single signing key for its entire lifetime, both `audit.integrity.algorithm` and `audit.integrity.certificate` are constant across all records from the same resource and therefore belong on the Resource, not on individual records. Acceptable forms (in order of preference): a Key ID / `kid` (JOSE header parameter), a DER-encoded X.509 certificate Base64url-encoded, an X.509 certificate fingerprint (SHA-256 hex), or an Issuer + Serial Number pair. Receivers MUST NOT use this field alone for trust decisions; key validation MUST be performed out-of-band. -**[8] `audit.sequence.number`:** When the emitting service maintains a monotonic per-stream counter. Required when `audit.sequence.prev_hash` is present. +**[10] `audit.sequence.end`:** Required on the final record of a gracefully closed stream (emitted during `ForceFlush` or `Shutdown`). Omit on all other records. + +**[11] `audit.sequence.end`:** Emitted by the SDK during `ForceFlush` or `Shutdown` to mark the terminal record of a stream. Absence is normal for all intermediate records — do not treat absence as an error. + +**[12] `audit.integrity.signer`:** `producer` means the SDK computed the value before export. `collector` means a Tier-2 Collector signed or re-signed the record after receiving it. When absent, `producer` SHOULD be assumed. + +**[13] `audit.sequence.number`:** When the emitting service maintains a monotonic per-stream counter. Required when `audit.sequence.prev_hash` is present. + +**[14] `audit.sequence.number`:** Compliant sinks and Tier-2 Collectors MUST verify that consecutive records within the same stream have strictly increasing sequence numbers. Gaps MUST trigger a gap-detection warning and a security event log entry. The counter SHOULD start at 1 and increment by 1 per emitted record, but implementations MAY use a larger step if records can be emitted concurrently from multiple threads. + +**[15] `audit.sequence.prev_hash`:** When the emitting service implements a hash chain for tamper detection. Requires `audit.sequence.number` to be present. MUST be omitted on the genesis record of a stream. + +**[16] `audit.sequence.prev_hash`:** Including the previous record's sink-acknowledged hash in the current record creates an append-only hash chain. Any retroactive modification of a record is detectable by re-verifying the chain. MUST be omitted on the genesis (first) record of a stream — absence is the normative signal; no magic sentinel constant is required. + +**[17] `audit.sequence.prev_record_id`:** When `audit.sequence.prev_hash` is present. Provides a resolvable locator for the predecessor record across storage boundaries. MUST be omitted on the genesis record of a stream. -**[9] `audit.sequence.number`:** Compliant sinks and Tier-2 Collectors MUST verify that consecutive records within the same stream have strictly increasing sequence numbers. Gaps MUST trigger a gap-detection warning and a security event log entry. The counter SHOULD start at 1 and increment by 1 per emitted record, but implementations MAY use a larger step if records can be emitted concurrently from multiple threads. +**[18] `audit.sequence.prev_record_id`:** Provides a resolvable locator for the predecessor across shards, storage systems, and retention boundaries, complementing `audit.sequence.prev_hash`. MUST be omitted on the genesis (first) record of a stream. -**[10] `audit.sequence.prev_hash`:** When the emitting service implements a hash chain for tamper detection. Requires `audit.sequence.number` to be present. +**[19] `audit.sequence.stream_id`:** When the emitting service uses hash-chain ordering. Scopes the chain to a single `AuditLogger` instance. -**[11] `audit.sequence.prev_hash`:** Including the previous record's sink-acknowledged hash in the current record creates an append-only hash chain. Any retroactive modification of a record is detectable by re-verifying the chain. Set to the all-zeros string `"0000000000000000000000000000000000000000000000000000000000000000"` for the first record in a stream. +**[20] `audit.sequence.stream_id`:** The SDK SHOULD generate a UUID v4 once per `AuditLogger` instance and include it on every record emitted by that logger. Allows multiple concurrent streams from the same resource to be distinguished by sinks and Collectors. -**[12] `audit.source.id`:** When the network origin or calling device of the action is known and meaningful for compliance review (e.g. PCI-DSS access logging). +**[21] `audit.source.id`:** When the network origin or calling device of the action is known and meaningful for compliance review (e.g. PCI-DSS access logging). -**[13] `audit.source.id`:** MAY be an IP address, a device UUID, or a service mesh endpoint id. Prefer stable identifiers (device UUID) over ephemeral ones (IP address) when both are available. +**[22] `audit.source.id`:** MAY be an IP address, a device UUID, or a service mesh endpoint id. Prefer stable identifiers (device UUID) over ephemeral ones (IP address) when both are available. -**[14] `audit.source.type`:** Well-known values: `ip_address`, `device`, `service_mesh_node`. Custom values MAY be used. +**[23] `audit.source.type`:** Well-known values: `ipv4`, `ipv6`, `hostname`. Custom values MAY be used. -**[15] `audit.target.id`:** When the action is performed on a specific, identifiable resource. +**[24] `audit.target.id`:** When the action is performed on a specific, identifiable resource. -**[16] `audit.target.id`:** SHOULD be the primary key, ARN, URI, or equivalent durable identifier of the resource. When acting on a collection rather than a single resource, this MAY contain the collection identifier. +**[25] `audit.target.id`:** SHOULD be the primary key, ARN, URI, or equivalent durable identifier of the resource. When acting on a collection rather than a single resource, this MAY contain the collection identifier. -**[17] `audit.target.type`:** When `audit.target.id` is present and the resource kind adds meaningful context for audit review. +**[26] `audit.target.type`:** When `audit.target.id` is present and the resource kind adds meaningful context for audit review. -**[18] `audit.target.type`:** SHOULD use a fully-qualified type where available (e.g. a Kubernetes GroupVersionResource or an IAM resource type). For domain-specific types a short qualified name MAY be used (e.g. `finance.invoice`). +**[27] `audit.target.type`:** SHOULD use a fully-qualified type where available (e.g. a Kubernetes GroupVersionResource or an IAM resource type). For domain-specific types a short qualified name MAY be used (e.g. `finance.invoice`). -**[19] `audit.actor.name`:** MAY be a login name, email address, or display name. This value is informational only; use `audit.actor.id` for stable identity correlation. +**[28] `audit.actor.name`:** MAY be a login name, email address, or display name. This value is informational only; use `audit.actor.id` for stable identity correlation. -**[20] `audit.integrity.value`:** The exact input to the signing / MAC operation MUST be the canonical serialisation of the `AuditRecord` with `audit.integrity.value` absent. `audit.integrity.algorithm` MUST be set on the emitting Resource whenever this attribute is present. +**[29] `audit.integrity.value`:** The exact input to the signing / MAC operation MUST be the JCS (RFC 8785) canonical JSON serialisation of the `AuditRecord` with all `audit.integrity.*` attributes excluded. `audit.integrity.algorithm` MUST be set on the emitting Resource whenever this attribute is present. -**[21] `audit.schema.version`:** Follows semantic versioning (MAJOR.MINOR.PATCH). Receivers MAY use this value to select an appropriate validation schema. +**[30] `audit.schema.version`:** Follows semantic versioning (MAJOR.MINOR.PATCH). Receivers MAY use this value to select an appropriate validation schema. -**[22] `audit.target.name`:** Informational only. Use `audit.target.id` for stable identity correlation. +**[31] `audit.target.name`:** Informational only. Use `audit.target.id` for stable identity correlation. --- diff --git a/docs/registry/attributes/audit.md b/docs/registry/attributes/audit.md index a13641e97e..7ced52f1af 100644 --- a/docs/registry/attributes/audit.md +++ b/docs/registry/attributes/audit.md @@ -69,15 +69,21 @@ Attributes that provide cryptographic evidence that the audit record has not bee | Key | Stability | Value Type | Description | Example Values | | --- | --- | --- | --- | --- | | `audit.integrity.algorithm` | ![Development](https://img.shields.io/badge/-development-blue) | string | The algorithm used to compute `audit.integrity.value`. [4] | `ES256`; `EdDSA`; `HMAC-SHA256` | -| `audit.integrity.certificate` | ![Development](https://img.shields.io/badge/-development-blue) | string | A reference to the key or certificate used for `audit.integrity.value`. [5] | `key-2024-01`; `SHA256:ab12cd34...` | -| `audit.integrity.value` | ![Development](https://img.shields.io/badge/-development-blue) | string | Base64url-encoded cryptographic signature or MAC covering this record. [6] | `SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c` | +| `audit.integrity.canonicalization` | ![Development](https://img.shields.io/badge/-development-blue) | string | The canonicalization scheme applied to the record before signing or MACing. [5] | `jcs` | +| `audit.integrity.certificate` | ![Development](https://img.shields.io/badge/-development-blue) | string | A reference to the key or certificate used for `audit.integrity.value`. [6] | `key-2024-01`; `SHA256:ab12cd34...` | +| `audit.integrity.signer` | ![Development](https://img.shields.io/badge/-development-blue) | string | Identifies which tier produced the integrity proof in `audit.integrity.value`. [7] | `producer`; `collector` | +| `audit.integrity.value` | ![Development](https://img.shields.io/badge/-development-blue) | string | Base64-encoded cryptographic signature or MAC covering this record. [8] | `SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c` | **[4] `audit.integrity.algorithm`:** MUST be set as a Resource attribute whenever `audit.integrity.value` is present on any record emitted by this resource. Use a JWA identifier (RFC 7518) for asymmetric signatures (e.g. `ES256`, `RS256`, `EdDSA`) or an IANA MAC Algorithm identifier for symmetric MACs (e.g. `HMAC-SHA256`). -**[5] `audit.integrity.certificate`:** MUST be set as a Resource attribute (together with `audit.integrity.algorithm`) whenever `audit.integrity.value` is present on any record emitted by this resource. Because a service instance uses a single signing key for its entire lifetime, both `audit.integrity.algorithm` and `audit.integrity.certificate` are constant across all records from the same resource and therefore belong on the Resource, not on individual records. +**[5] `audit.integrity.canonicalization`:** Defaults to `jcs` (RFC 8785 JSON Canonicalization Scheme). Set explicitly when any other canonicalization is used so that verifiers can reproduce the exact byte sequence that was signed. MUST be omitted when `jcs` is used and the default is sufficient. + +**[6] `audit.integrity.certificate`:** MUST be set as a Resource attribute (together with `audit.integrity.algorithm`) whenever `audit.integrity.value` is present on any record emitted by this resource. Because a service instance uses a single signing key for its entire lifetime, both `audit.integrity.algorithm` and `audit.integrity.certificate` are constant across all records from the same resource and therefore belong on the Resource, not on individual records. Acceptable forms (in order of preference): a Key ID / `kid` (JOSE header parameter), a DER-encoded X.509 certificate Base64url-encoded, an X.509 certificate fingerprint (SHA-256 hex), or an Issuer + Serial Number pair. Receivers MUST NOT use this field alone for trust decisions; key validation MUST be performed out-of-band. -**[6] `audit.integrity.value`:** The exact input to the signing / MAC operation MUST be the canonical serialisation of the `AuditRecord` with `audit.integrity.value` absent. `audit.integrity.algorithm` MUST be set on the emitting Resource whenever this attribute is present. +**[7] `audit.integrity.signer`:** `producer` means the SDK computed the value before export. `collector` means a Tier-2 Collector signed or re-signed the record after receiving it. When absent, `producer` SHOULD be assumed. + +**[8] `audit.integrity.value`:** The exact input to the signing / MAC operation MUST be the JCS (RFC 8785) canonical JSON serialisation of the `AuditRecord` with all `audit.integrity.*` attributes excluded. `audit.integrity.algorithm` MUST be set on the emitting Resource whenever this attribute is present. ## Audit Record Attributes @@ -87,12 +93,12 @@ Attributes that uniquely identify and version an audit record. | Key | Stability | Value Type | Description | Example Values | | --- | --- | --- | --- | --- | -| `audit.record.id` | ![Development](https://img.shields.io/badge/-development-blue) | string | A stable, globally unique identifier for this audit record. [7] | `3fa85f64-5717-4562-b3fc-2c963f66afa6` | -| `audit.schema.version` | ![Development](https://img.shields.io/badge/-development-blue) | string | The version of the audit semantic conventions schema used by this record. [8] | `1.0.0`; `1.2.0` | +| `audit.record.id` | ![Development](https://img.shields.io/badge/-development-blue) | string | A stable, globally unique identifier for this audit record. [9] | `3fa85f64-5717-4562-b3fc-2c963f66afa6` | +| `audit.schema.version` | ![Development](https://img.shields.io/badge/-development-blue) | string | The version of the audit semantic conventions schema used by this record. [10] | `1.0.0`; `1.2.0` | -**[7] `audit.record.id`:** The SDK MUST auto-generate a UUID v4 when the caller omits this field. The value MUST remain identical across all retries of the same record. Records with the same `audit.record.id` and identical payload hash are treated as idempotent duplicates by compliant sinks. +**[9] `audit.record.id`:** The SDK MUST auto-generate a UUID v4 when the caller omits this field. The value MUST remain identical across all retries of the same record. Records with the same `audit.record.id` and identical payload hash are treated as idempotent duplicates by compliant sinks. -**[8] `audit.schema.version`:** Follows semantic versioning (MAJOR.MINOR.PATCH). Receivers MAY use this value to select an appropriate validation schema. +**[10] `audit.schema.version`:** Follows semantic versioning (MAJOR.MINOR.PATCH). Receivers MAY use this value to select an appropriate validation schema. ## Audit Sequence Attributes @@ -102,12 +108,21 @@ Attributes that link audit records into an ordered, tamper-evident chain within | Key | Stability | Value Type | Description | Example Values | | --- | --- | --- | --- | --- | -| `audit.sequence.number` | ![Development](https://img.shields.io/badge/-development-blue) | int | A monotonically increasing counter assigned to each record within a single audit stream. [9] | `1`; `42`; `1000001` | -| `audit.sequence.prev_hash` | ![Development](https://img.shields.io/badge/-development-blue) | string | SHA-256 hex digest of the `IntegrityHash` field of the immediately preceding record in the same audit stream. [10] | `a3f1c2e4b5d6a7f8e9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2`; `0000000000000000000000000000000000000000000000000000000000000000` | +| `audit.sequence.end` | ![Development](https://img.shields.io/badge/-development-blue) | boolean | Set to `true` on the last record of a gracefully closed audit stream. [11] | `true` | +| `audit.sequence.number` | ![Development](https://img.shields.io/badge/-development-blue) | int | A monotonically increasing counter assigned to each record within a single audit stream. [12] | `1`; `42`; `1000001` | +| `audit.sequence.prev_hash` | ![Development](https://img.shields.io/badge/-development-blue) | string | SHA-256 hex digest of the `IntegrityHash` field of the immediately preceding record in the same audit stream. [13] | `a3f1c2e4b5d6a7f8e9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2` | +| `audit.sequence.prev_record_id` | ![Development](https://img.shields.io/badge/-development-blue) | string | The `audit.record.id` of the immediately preceding record in the same audit stream. [14] | `3fa85f64-5717-4562-b3fc-2c963f66afa6` | +| `audit.sequence.stream_id` | ![Development](https://img.shields.io/badge/-development-blue) | string | An opaque identifier that scopes the hash chain to a single audit stream. [15] | `7c9e6679-7425-40de-944b-e07fc1f90ae7` | + +**[11] `audit.sequence.end`:** Emitted by the SDK during `ForceFlush` or `Shutdown` to mark the terminal record of a stream. Absence is normal for all intermediate records — do not treat absence as an error. + +**[12] `audit.sequence.number`:** Compliant sinks and Tier-2 Collectors MUST verify that consecutive records within the same stream have strictly increasing sequence numbers. Gaps MUST trigger a gap-detection warning and a security event log entry. The counter SHOULD start at 1 and increment by 1 per emitted record, but implementations MAY use a larger step if records can be emitted concurrently from multiple threads. + +**[13] `audit.sequence.prev_hash`:** Including the previous record's sink-acknowledged hash in the current record creates an append-only hash chain. Any retroactive modification of a record is detectable by re-verifying the chain. MUST be omitted on the genesis (first) record of a stream — absence is the normative signal; no magic sentinel constant is required. -**[9] `audit.sequence.number`:** Compliant sinks and Tier-2 Collectors MUST verify that consecutive records within the same stream have strictly increasing sequence numbers. Gaps MUST trigger a gap-detection warning and a security event log entry. The counter SHOULD start at 1 and increment by 1 per emitted record, but implementations MAY use a larger step if records can be emitted concurrently from multiple threads. +**[14] `audit.sequence.prev_record_id`:** Provides a resolvable locator for the predecessor across shards, storage systems, and retention boundaries, complementing `audit.sequence.prev_hash`. MUST be omitted on the genesis (first) record of a stream. -**[10] `audit.sequence.prev_hash`:** Including the previous record's sink-acknowledged hash in the current record creates an append-only hash chain. Any retroactive modification of a record is detectable by re-verifying the chain. Set to the all-zeros string `"0000000000000000000000000000000000000000000000000000000000000000"` for the first record in a stream. +**[15] `audit.sequence.stream_id`:** The SDK SHOULD generate a UUID v4 once per `AuditLogger` instance and include it on every record emitted by that logger. Allows multiple concurrent streams from the same resource to be distinguished by sinks and Collectors. ## Audit Source Attributes @@ -117,12 +132,12 @@ Attributes that describe the network origin or calling context of the action. | Key | Stability | Value Type | Description | Example Values | | --- | --- | --- | --- | --- | -| `audit.source.id` | ![Development](https://img.shields.io/badge/-development-blue) | string | A stable identifier for the source system or network endpoint that originated the action. [11] | `192.0.2.42`; `device-uuid-abcd1234` | -| `audit.source.type` | ![Development](https://img.shields.io/badge/-development-blue) | string | The category of origin that initiated the action. [12] | `ip_address`; `device`; `service_mesh_node` | +| `audit.source.id` | ![Development](https://img.shields.io/badge/-development-blue) | string | A stable identifier for the source system or network endpoint that originated the action. [16] | `192.0.2.42`; `device-uuid-abcd1234` | +| `audit.source.type` | ![Development](https://img.shields.io/badge/-development-blue) | string | The category of origin that initiated the action. [17] | `ipv4`; `ipv6`; `hostname` | -**[11] `audit.source.id`:** MAY be an IP address, a device UUID, or a service mesh endpoint id. Prefer stable identifiers (device UUID) over ephemeral ones (IP address) when both are available. +**[16] `audit.source.id`:** MAY be an IP address, a device UUID, or a service mesh endpoint id. Prefer stable identifiers (device UUID) over ephemeral ones (IP address) when both are available. -**[12] `audit.source.type`:** Well-known values: `ip_address`, `device`, `service_mesh_node`. Custom values MAY be used. +**[17] `audit.source.type`:** Well-known values: `ipv4`, `ipv6`, `hostname`. Custom values MAY be used. ## Audit Target Attributes @@ -132,12 +147,12 @@ Attributes that describe the resource or object that was acted upon. | Key | Stability | Value Type | Description | Example Values | | --- | --- | --- | --- | --- | -| `audit.target.id` | ![Development](https://img.shields.io/badge/-development-blue) | string | The stable identifier of the resource that was the target of the action. [13] | `document-42`; `arn:aws:s3:::my-bucket/key`; `/api/v1/users/9f81` | -| `audit.target.name` | ![Development](https://img.shields.io/badge/-development-blue) | string | A human-readable name or label of the target resource. [14] | `production-deploy`; `Q1-invoice-7734` | -| `audit.target.type` | ![Development](https://img.shields.io/badge/-development-blue) | string | The type or resource kind of the target. [15] | `User`; `apps/v1/Deployment`; `finance.invoice` | +| `audit.target.id` | ![Development](https://img.shields.io/badge/-development-blue) | string | The stable identifier of the resource that was the target of the action. [18] | `document-42`; `arn:aws:s3:::my-bucket/key`; `/api/v1/users/9f81` | +| `audit.target.name` | ![Development](https://img.shields.io/badge/-development-blue) | string | A human-readable name or label of the target resource. [19] | `production-deploy`; `Q1-invoice-7734` | +| `audit.target.type` | ![Development](https://img.shields.io/badge/-development-blue) | string | The type or resource kind of the target. [20] | `User`; `apps/v1/Deployment`; `finance.invoice` | -**[13] `audit.target.id`:** SHOULD be the primary key, ARN, URI, or equivalent durable identifier of the resource. When acting on a collection rather than a single resource, this MAY contain the collection identifier. +**[18] `audit.target.id`:** SHOULD be the primary key, ARN, URI, or equivalent durable identifier of the resource. When acting on a collection rather than a single resource, this MAY contain the collection identifier. -**[14] `audit.target.name`:** Informational only. Use `audit.target.id` for stable identity correlation. +**[19] `audit.target.name`:** Informational only. Use `audit.target.id` for stable identity correlation. -**[15] `audit.target.type`:** SHOULD use a fully-qualified type where available (e.g. a Kubernetes GroupVersionResource or an IAM resource type). For domain-specific types a short qualified name MAY be used (e.g. `finance.invoice`). +**[20] `audit.target.type`:** SHOULD use a fully-qualified type where available (e.g. a Kubernetes GroupVersionResource or an IAM resource type). For domain-specific types a short qualified name MAY be used (e.g. `finance.invoice`). diff --git a/model/audit/logs.yaml b/model/audit/logs.yaml index 24439c8e4a..6b50a1e133 100644 --- a/model/audit/logs.yaml +++ b/model/audit/logs.yaml @@ -68,6 +68,14 @@ groups: # --- integrity (tamper-evidence) --- - ref: audit.integrity.value requirement_level: opt_in + - ref: audit.integrity.signer + requirement_level: + recommended: When `audit.integrity.value` is present. + - ref: audit.integrity.canonicalization + requirement_level: + conditionally_required: > + Required when a canonicalization scheme other than `jcs` (RFC 8785) + is used. Omit when `jcs` is used. - ref: audit.integrity.algorithm requirement_level: conditionally_required: > @@ -81,6 +89,11 @@ groups: on any record emitted from this resource. # --- hash-chain ordering --- + - ref: audit.sequence.stream_id + requirement_level: + recommended: > + When the emitting service uses hash-chain ordering. Scopes the chain + to a single `AuditLogger` instance. - ref: audit.sequence.number requirement_level: recommended: > @@ -91,6 +104,18 @@ groups: recommended: > When the emitting service implements a hash chain for tamper detection. Requires `audit.sequence.number` to be present. + MUST be omitted on the genesis record of a stream. + - ref: audit.sequence.prev_record_id + requirement_level: + recommended: > + When `audit.sequence.prev_hash` is present. Provides a resolvable + locator for the predecessor record across storage boundaries. + MUST be omitted on the genesis record of a stream. + - ref: audit.sequence.end + requirement_level: + conditionally_required: > + Required on the final record of a gracefully closed stream + (emitted during `ForceFlush` or `Shutdown`). Omit on all other records. # --- schema versioning --- - ref: audit.schema.version diff --git a/model/audit/registry.yaml b/model/audit/registry.yaml index d86cbac098..b9af5f9b35 100644 --- a/model/audit/registry.yaml +++ b/model/audit/registry.yaml @@ -215,12 +215,12 @@ groups: brief: > The category of origin that initiated the action. note: > - Well-known values: `ip_address`, `device`, `service_mesh_node`. + Well-known values: `ipv4`, `ipv6`, `hostname`. Custom values MAY be used. examples: - - "ip_address" - - "device" - - "service_mesh_node" + - "ipv4" + - "ipv6" + - "hostname" # --------------------------------------------------------------------------- # audit.integrity — cryptographic tamper-evidence @@ -236,15 +236,40 @@ groups: type: string stability: development brief: > - Base64url-encoded cryptographic signature or MAC covering this record. + Base64-encoded cryptographic signature or MAC covering this record. note: > - The exact input to the signing / MAC operation MUST be the canonical - serialisation of the `AuditRecord` with `audit.integrity.value` absent. - `audit.integrity.algorithm` MUST be set on the emitting Resource whenever - this attribute is present. + The input to the signing / MAC operation MUST be the canonical + serialisation of the `AuditRecord` with all `audit.integrity.*` + attributes excluded. The default canonicalization is JCS (RFC 8785); + set `audit.integrity.canonicalization` when a different scheme is used. + `audit.integrity.algorithm` MUST be set on the emitting Resource + whenever this attribute is present. examples: - "SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c" + - id: audit.integrity.signer + type: string + stability: development + brief: > + Identifies which tier produced the integrity proof in `audit.integrity.value`. + note: > + `producer` means the SDK computed the value before export. `collector` + means a Tier-2 Collector signed or re-signed the record after receiving it. + When absent, `producer` SHOULD be assumed. + examples: ["producer", "collector"] + + - id: audit.integrity.canonicalization + type: string + stability: development + brief: > + The canonicalization scheme applied to the record before signing or MACing. + note: > + Defaults to `jcs` (RFC 8785 JSON Canonicalization Scheme). Set explicitly + when any other canonicalization is used so that verifiers can reproduce the + exact byte sequence that was signed. MUST be omitted when `jcs` is used and + the default is sufficient. + examples: ["jcs"] + - id: audit.integrity.algorithm type: string stability: development @@ -316,9 +341,45 @@ groups: note: > Including the previous record's sink-acknowledged hash in the current record creates an append-only hash chain. Any retroactive modification - of a record is detectable by re-verifying the chain. Set to the all-zeros - string `"0000000000000000000000000000000000000000000000000000000000000000"` - for the first record in a stream. + of a record is detectable by re-verifying the chain. MUST be omitted on + the genesis (first) record of a stream — absence is the normative signal; + no magic sentinel constant is required. examples: - "a3f1c2e4b5d6a7f8e9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2" - - "0000000000000000000000000000000000000000000000000000000000000000" + + - id: audit.sequence.prev_record_id + type: string + stability: development + brief: > + The `audit.record.id` of the immediately preceding record in the same + audit stream. + note: > + Provides a resolvable locator for the predecessor across shards, storage + systems, and retention boundaries, complementing `audit.sequence.prev_hash`. + MUST be omitted on the genesis (first) record of a stream. + examples: + - "3fa85f64-5717-4562-b3fc-2c963f66afa6" + + - id: audit.sequence.end + type: boolean + stability: development + brief: > + Set to `true` on the last record of a gracefully closed audit stream. + note: > + Emitted by the SDK during `ForceFlush` or `Shutdown` to mark the terminal + record of a stream. Absence is normal for all intermediate records — do not + treat absence as an error. + examples: [true] + + - id: audit.sequence.stream_id + type: string + stability: development + brief: > + An opaque identifier that scopes the hash chain to a single audit stream. + note: > + The SDK SHOULD generate a UUID v4 once per `AuditLogger` instance and + include it on every record emitted by that logger. Allows multiple + concurrent streams from the same resource to be distinguished by sinks + and Collectors. + examples: + - "7c9e6679-7425-40de-944b-e07fc1f90ae7" From 8bfd208dfb2172b02c1a18573ce1e498df527d91 Mon Sep 17 00:00:00 2001 From: Hilmar Falkenberg Date: Wed, 9 Sep 2026 12:23:30 +0200 Subject: [PATCH 14/21] be more clearer Signed-off-by: Hilmar Falkenberg --- docs/audit/audit-logs.md | 8 ++++---- docs/registry/attributes/audit.md | 8 ++++---- model/audit/registry.yaml | 10 ++++------ 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/docs/audit/audit-logs.md b/docs/audit/audit-logs.md index a99633a951..3872759c59 100644 --- a/docs/audit/audit-logs.md +++ b/docs/audit/audit-logs.md @@ -149,7 +149,7 @@ namespace. **[6] `audit.integrity.canonicalization`:** Required when a canonicalization scheme other than `jcs` (RFC 8785) is used. Omit when `jcs` is used. -**[7] `audit.integrity.canonicalization`:** Defaults to `jcs` (RFC 8785 JSON Canonicalization Scheme). Set explicitly when any other canonicalization is used so that verifiers can reproduce the exact byte sequence that was signed. MUST be omitted when `jcs` is used and the default is sufficient. +**[7] `audit.integrity.canonicalization`:** Defaults to `jcs` (RFC 8785 JSON Canonicalization Scheme). Set explicitly when any other canonicalization is used so that verifiers can reproduce the exact byte sequence that was signed. MUST be omitted when `jcs` is used. **[8] `audit.integrity.certificate`:** Required (as a Resource attribute, together with `audit.integrity.algorithm`) when `audit.integrity.value` is present on any record emitted from this resource. @@ -176,7 +176,7 @@ Acceptable forms (in order of preference): a Key ID / `kid` (JOSE header paramet **[19] `audit.sequence.stream_id`:** When the emitting service uses hash-chain ordering. Scopes the chain to a single `AuditLogger` instance. -**[20] `audit.sequence.stream_id`:** The SDK SHOULD generate a UUID v4 once per `AuditLogger` instance and include it on every record emitted by that logger. Allows multiple concurrent streams from the same resource to be distinguished by sinks and Collectors. +**[20] `audit.sequence.stream_id`:** The SDK SHOULD generate a UUID v4 once per `AuditLogger` instance and include it on every record emitted by that logger. **[21] `audit.source.id`:** When the network origin or calling device of the action is known and meaningful for compliance review (e.g. PCI-DSS access logging). @@ -194,9 +194,9 @@ Acceptable forms (in order of preference): a Key ID / `kid` (JOSE header paramet **[28] `audit.actor.name`:** MAY be a login name, email address, or display name. This value is informational only; use `audit.actor.id` for stable identity correlation. -**[29] `audit.integrity.value`:** The exact input to the signing / MAC operation MUST be the JCS (RFC 8785) canonical JSON serialisation of the `AuditRecord` with all `audit.integrity.*` attributes excluded. `audit.integrity.algorithm` MUST be set on the emitting Resource whenever this attribute is present. +**[29] `audit.integrity.value`:** The input to the signing / MAC operation MUST be the canonical serialisation of the `AuditRecord` with all `audit.integrity.*` attributes excluded. The default canonicalization is JCS (RFC 8785); set `audit.integrity.canonicalization` when a different scheme is used. `audit.integrity.algorithm` MUST be set on the emitting Resource whenever this attribute is present. -**[30] `audit.schema.version`:** Follows semantic versioning (MAJOR.MINOR.PATCH). Receivers MAY use this value to select an appropriate validation schema. +**[30] `audit.schema.version`:** Follows semantic versioning (MAJOR.MINOR.PATCH). Receivers MAY use this value to select the matching validation schema for the record's attribute vocabulary. **[31] `audit.target.name`:** Informational only. Use `audit.target.id` for stable identity correlation. diff --git a/docs/registry/attributes/audit.md b/docs/registry/attributes/audit.md index 7ced52f1af..d01c0c504a 100644 --- a/docs/registry/attributes/audit.md +++ b/docs/registry/attributes/audit.md @@ -76,14 +76,14 @@ Attributes that provide cryptographic evidence that the audit record has not bee **[4] `audit.integrity.algorithm`:** MUST be set as a Resource attribute whenever `audit.integrity.value` is present on any record emitted by this resource. Use a JWA identifier (RFC 7518) for asymmetric signatures (e.g. `ES256`, `RS256`, `EdDSA`) or an IANA MAC Algorithm identifier for symmetric MACs (e.g. `HMAC-SHA256`). -**[5] `audit.integrity.canonicalization`:** Defaults to `jcs` (RFC 8785 JSON Canonicalization Scheme). Set explicitly when any other canonicalization is used so that verifiers can reproduce the exact byte sequence that was signed. MUST be omitted when `jcs` is used and the default is sufficient. +**[5] `audit.integrity.canonicalization`:** Defaults to `jcs` (RFC 8785 JSON Canonicalization Scheme). Set explicitly when any other canonicalization is used so that verifiers can reproduce the exact byte sequence that was signed. MUST be omitted when `jcs` is used. **[6] `audit.integrity.certificate`:** MUST be set as a Resource attribute (together with `audit.integrity.algorithm`) whenever `audit.integrity.value` is present on any record emitted by this resource. Because a service instance uses a single signing key for its entire lifetime, both `audit.integrity.algorithm` and `audit.integrity.certificate` are constant across all records from the same resource and therefore belong on the Resource, not on individual records. Acceptable forms (in order of preference): a Key ID / `kid` (JOSE header parameter), a DER-encoded X.509 certificate Base64url-encoded, an X.509 certificate fingerprint (SHA-256 hex), or an Issuer + Serial Number pair. Receivers MUST NOT use this field alone for trust decisions; key validation MUST be performed out-of-band. **[7] `audit.integrity.signer`:** `producer` means the SDK computed the value before export. `collector` means a Tier-2 Collector signed or re-signed the record after receiving it. When absent, `producer` SHOULD be assumed. -**[8] `audit.integrity.value`:** The exact input to the signing / MAC operation MUST be the JCS (RFC 8785) canonical JSON serialisation of the `AuditRecord` with all `audit.integrity.*` attributes excluded. `audit.integrity.algorithm` MUST be set on the emitting Resource whenever this attribute is present. +**[8] `audit.integrity.value`:** The input to the signing / MAC operation MUST be the canonical serialisation of the `AuditRecord` with all `audit.integrity.*` attributes excluded. The default canonicalization is JCS (RFC 8785); set `audit.integrity.canonicalization` when a different scheme is used. `audit.integrity.algorithm` MUST be set on the emitting Resource whenever this attribute is present. ## Audit Record Attributes @@ -98,7 +98,7 @@ Attributes that uniquely identify and version an audit record. **[9] `audit.record.id`:** The SDK MUST auto-generate a UUID v4 when the caller omits this field. The value MUST remain identical across all retries of the same record. Records with the same `audit.record.id` and identical payload hash are treated as idempotent duplicates by compliant sinks. -**[10] `audit.schema.version`:** Follows semantic versioning (MAJOR.MINOR.PATCH). Receivers MAY use this value to select an appropriate validation schema. +**[10] `audit.schema.version`:** Follows semantic versioning (MAJOR.MINOR.PATCH). Receivers MAY use this value to select the matching validation schema for the record's attribute vocabulary. ## Audit Sequence Attributes @@ -122,7 +122,7 @@ Attributes that link audit records into an ordered, tamper-evident chain within **[14] `audit.sequence.prev_record_id`:** Provides a resolvable locator for the predecessor across shards, storage systems, and retention boundaries, complementing `audit.sequence.prev_hash`. MUST be omitted on the genesis (first) record of a stream. -**[15] `audit.sequence.stream_id`:** The SDK SHOULD generate a UUID v4 once per `AuditLogger` instance and include it on every record emitted by that logger. Allows multiple concurrent streams from the same resource to be distinguished by sinks and Collectors. +**[15] `audit.sequence.stream_id`:** The SDK SHOULD generate a UUID v4 once per `AuditLogger` instance and include it on every record emitted by that logger. ## Audit Source Attributes diff --git a/model/audit/registry.yaml b/model/audit/registry.yaml index b9af5f9b35..8595f55e88 100644 --- a/model/audit/registry.yaml +++ b/model/audit/registry.yaml @@ -28,7 +28,8 @@ groups: The version of the audit semantic conventions schema used by this record. note: > Follows semantic versioning (MAJOR.MINOR.PATCH). Receivers MAY use this - value to select an appropriate validation schema. + value to select the matching validation schema for the record's attribute + vocabulary. examples: ["1.0.0", "1.2.0"] # --------------------------------------------------------------------------- @@ -266,8 +267,7 @@ groups: note: > Defaults to `jcs` (RFC 8785 JSON Canonicalization Scheme). Set explicitly when any other canonicalization is used so that verifiers can reproduce the - exact byte sequence that was signed. MUST be omitted when `jcs` is used and - the default is sufficient. + exact byte sequence that was signed. MUST be omitted when `jcs` is used. examples: ["jcs"] - id: audit.integrity.algorithm @@ -378,8 +378,6 @@ groups: An opaque identifier that scopes the hash chain to a single audit stream. note: > The SDK SHOULD generate a UUID v4 once per `AuditLogger` instance and - include it on every record emitted by that logger. Allows multiple - concurrent streams from the same resource to be distinguished by sinks - and Collectors. + include it on every record emitted by that logger. examples: - "7c9e6679-7425-40de-944b-e07fc1f90ae7" From c0d79a293c314f597b3411c644c09746ddf45b70 Mon Sep 17 00:00:00 2001 From: Hilmar Falkenberg Date: Wed, 9 Sep 2026 12:34:05 +0200 Subject: [PATCH 15/21] fix typos and textlint issues Signed-off-by: Hilmar Falkenberg --- docs/audit/audit-logs.md | 6 +++--- docs/registry/attributes/audit.md | 2 +- model/audit/registry.yaml | 12 ++++++------ 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/audit/audit-logs.md b/docs/audit/audit-logs.md index 3872759c59..1af94659bf 100644 --- a/docs/audit/audit-logs.md +++ b/docs/audit/audit-logs.md @@ -139,7 +139,7 @@ namespace. **[1] `audit.action`:** SHOULD be an uppercase verb from a controlled vocabulary where possible. Well-known values include `LOGIN`, `LOGOUT`, `READ`, `CREATE`, `UPDATE`, `DELETE`, `GRANT`, `REVOKE`, `EXPORT`, `IMPORT`, `EXECUTE`, `APPROVE`, `REJECT`. Custom values MAY be used when none of the well-known values applies, but SHOULD be documented in the producing service's changelog. -**[2] `audit.actor.id`:** This SHOULD be an opaque, durable identifier (e.g. a user-UUID, service account name, or IAM principal ARN) that remains stable across sessions. Avoid using mutable display names or email addresses as the primary id. +**[2] `audit.actor.id`:** This SHOULD be an opaque, durable identifier (e.g. a user-UUID, service account name, or IAM principal ARN) that remains stable across sessions. Avoid using mutable display names or email addresses as the primary ID. **[3] `audit.record.id`:** The SDK MUST auto-generate a UUID v4 when the caller omits this field. The value MUST remain identical across all retries of the same record. Records with the same `audit.record.id` and identical payload hash are treated as idempotent duplicates by compliant sinks. @@ -180,7 +180,7 @@ Acceptable forms (in order of preference): a Key ID / `kid` (JOSE header paramet **[21] `audit.source.id`:** When the network origin or calling device of the action is known and meaningful for compliance review (e.g. PCI-DSS access logging). -**[22] `audit.source.id`:** MAY be an IP address, a device UUID, or a service mesh endpoint id. Prefer stable identifiers (device UUID) over ephemeral ones (IP address) when both are available. +**[22] `audit.source.id`:** MAY be an IP address, a device UUID, or a service mesh endpoint ID. Prefer stable identifiers (device UUID) over ephemeral ones (IP address) when both are available. **[23] `audit.source.type`:** Well-known values: `ipv4`, `ipv6`, `hostname`. Custom values MAY be used. @@ -194,7 +194,7 @@ Acceptable forms (in order of preference): a Key ID / `kid` (JOSE header paramet **[28] `audit.actor.name`:** MAY be a login name, email address, or display name. This value is informational only; use `audit.actor.id` for stable identity correlation. -**[29] `audit.integrity.value`:** The input to the signing / MAC operation MUST be the canonical serialisation of the `AuditRecord` with all `audit.integrity.*` attributes excluded. The default canonicalization is JCS (RFC 8785); set `audit.integrity.canonicalization` when a different scheme is used. `audit.integrity.algorithm` MUST be set on the emitting Resource whenever this attribute is present. +**[29] `audit.integrity.value`:** The input to the signing / MAC operation MUST be the canonical serialization of the `AuditRecord` with all `audit.integrity.*` attributes excluded. The default canonicalization is JCS (RFC 8785); set `audit.integrity.canonicalization` when a different scheme is used. `audit.integrity.algorithm` MUST be set on the emitting Resource whenever this attribute is present. **[30] `audit.schema.version`:** Follows semantic versioning (MAJOR.MINOR.PATCH). Receivers MAY use this value to select the matching validation schema for the record's attribute vocabulary. diff --git a/docs/registry/attributes/audit.md b/docs/registry/attributes/audit.md index d01c0c504a..bdcce014be 100644 --- a/docs/registry/attributes/audit.md +++ b/docs/registry/attributes/audit.md @@ -83,7 +83,7 @@ Acceptable forms (in order of preference): a Key ID / `kid` (JOSE header paramet **[7] `audit.integrity.signer`:** `producer` means the SDK computed the value before export. `collector` means a Tier-2 Collector signed or re-signed the record after receiving it. When absent, `producer` SHOULD be assumed. -**[8] `audit.integrity.value`:** The input to the signing / MAC operation MUST be the canonical serialisation of the `AuditRecord` with all `audit.integrity.*` attributes excluded. The default canonicalization is JCS (RFC 8785); set `audit.integrity.canonicalization` when a different scheme is used. `audit.integrity.algorithm` MUST be set on the emitting Resource whenever this attribute is present. +**[8] `audit.integrity.value`:** The input to the signing / MAC operation MUST be the canonical serialization of the `AuditRecord` with all `audit.integrity.*` attributes excluded. The default canonicalization is JCS (RFC 8785); set `audit.integrity.canonicalization` when a different scheme is used. `audit.integrity.algorithm` MUST be set on the emitting Resource whenever this attribute is present. ## Audit Record Attributes diff --git a/model/audit/registry.yaml b/model/audit/registry.yaml index 8595f55e88..50168e5ebf 100644 --- a/model/audit/registry.yaml +++ b/model/audit/registry.yaml @@ -50,7 +50,7 @@ groups: note: > This SHOULD be an opaque, durable identifier (e.g. a user-UUID, service account name, or IAM principal ARN) that remains stable across sessions. - Avoid using mutable display names or email addresses as the primary id. + Avoid using mutable display names or email addresses as the primary ID. examples: - "u8472" - "svc-deployer" @@ -203,7 +203,7 @@ groups: A stable identifier for the source system or network endpoint that originated the action. note: > - MAY be an IP address, a device UUID, or a service mesh endpoint id. + MAY be an IP address, a device UUID, or a service mesh endpoint ID. Prefer stable identifiers (device UUID) over ephemeral ones (IP address) when both are available. examples: @@ -219,8 +219,8 @@ groups: Well-known values: `ipv4`, `ipv6`, `hostname`. Custom values MAY be used. examples: - - "ipv4" - - "ipv6" + - "IPv4" + - "IPv6" - "hostname" # --------------------------------------------------------------------------- @@ -237,10 +237,10 @@ groups: type: string stability: development brief: > - Base64-encoded cryptographic signature or MAC covering this record. + base64-encoded cryptographic signature or MAC covering this record. note: > The input to the signing / MAC operation MUST be the canonical - serialisation of the `AuditRecord` with all `audit.integrity.*` + serialization of the `AuditRecord` with all `audit.integrity.*` attributes excluded. The default canonicalization is JCS (RFC 8785); set `audit.integrity.canonicalization` when a different scheme is used. `audit.integrity.algorithm` MUST be set on the emitting Resource From 722e3450ff196391fe8ee9211a52c26c52221e7e Mon Sep 17 00:00:00 2001 From: Hilmar Falkenberg Date: Wed, 9 Sep 2026 12:48:33 +0200 Subject: [PATCH 16/21] SeverityNumbere severity implies triage priority, which has no meaning for audit records Signed-off-by: Hilmar Falkenberg --- docs/audit/audit-logs.md | 4 ++-- docs/registry/attributes/audit.md | 8 ++++---- model/audit/logs.yaml | 6 +++++- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/docs/audit/audit-logs.md b/docs/audit/audit-logs.md index 1af94659bf..051b3ca71e 100644 --- a/docs/audit/audit-logs.md +++ b/docs/audit/audit-logs.md @@ -129,11 +129,11 @@ namespace. | [`audit.sequence.prev_record_id`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Recommended` [17] | string | The `audit.record.id` of the immediately preceding record in the same audit stream. [18] | `3fa85f64-5717-4562-b3fc-2c963f66afa6` | | [`audit.sequence.stream_id`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Recommended` [19] | string | An opaque identifier that scopes the hash chain to a single audit stream. [20] | `7c9e6679-7425-40de-944b-e07fc1f90ae7` | | [`audit.source.id`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Recommended` [21] | string | A stable identifier for the source system or network endpoint that originated the action. [22] | `192.0.2.42`; `device-uuid-abcd1234` | -| [`audit.source.type`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Recommended` When `audit.source.id` is present. | string | The category of origin that initiated the action. [23] | `ipv4`; `ipv6`; `hostname` | +| [`audit.source.type`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Recommended` When `audit.source.id` is present. | string | The category of origin that initiated the action. [23] | `IPv4`; `IPv6`; `hostname` | | [`audit.target.id`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Recommended` [24] | string | The stable identifier of the resource that was the target of the action. [25] | `document-42`; `arn:aws:s3:::my-bucket/key`; `/api/v1/users/9f81` | | [`audit.target.type`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Recommended` [26] | string | The type or resource kind of the target. [27] | `User`; `apps/v1/Deployment`; `finance.invoice` | | [`audit.actor.name`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Opt-In` | string | A human-readable display name or username of the actor. [28] | `alice`; `alice@example.com`; `Alice Smith` | -| [`audit.integrity.value`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Opt-In` | string | Base64-encoded cryptographic signature or MAC covering this record. [29] | `SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c` | +| [`audit.integrity.value`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Opt-In` | string | base64-encoded cryptographic signature or MAC covering this record. [29] | `SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c` | | [`audit.schema.version`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Opt-In` | string | The version of the audit semantic conventions schema used by this record. [30] | `1.0.0`; `1.2.0` | | [`audit.target.name`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Opt-In` | string | A human-readable name or label of the target resource. [31] | `production-deploy`; `Q1-invoice-7734` | diff --git a/docs/registry/attributes/audit.md b/docs/registry/attributes/audit.md index bdcce014be..be2490bb0c 100644 --- a/docs/registry/attributes/audit.md +++ b/docs/registry/attributes/audit.md @@ -46,7 +46,7 @@ Attributes that identify the principal (human user, service, or automated system | `audit.actor.name` | ![Development](https://img.shields.io/badge/-development-blue) | string | A human-readable display name or username of the actor. [3] | `alice`; `alice@example.com`; `Alice Smith` | | `audit.actor.type` | ![Development](https://img.shields.io/badge/-development-blue) | string | The category of principal that performed the action. | `user`; `service`; `system` | -**[2] `audit.actor.id`:** This SHOULD be an opaque, durable identifier (e.g. a user-UUID, service account name, or IAM principal ARN) that remains stable across sessions. Avoid using mutable display names or email addresses as the primary id. +**[2] `audit.actor.id`:** This SHOULD be an opaque, durable identifier (e.g. a user-UUID, service account name, or IAM principal ARN) that remains stable across sessions. Avoid using mutable display names or email addresses as the primary ID. **[3] `audit.actor.name`:** MAY be a login name, email address, or display name. This value is informational only; use `audit.actor.id` for stable identity correlation. @@ -72,7 +72,7 @@ Attributes that provide cryptographic evidence that the audit record has not bee | `audit.integrity.canonicalization` | ![Development](https://img.shields.io/badge/-development-blue) | string | The canonicalization scheme applied to the record before signing or MACing. [5] | `jcs` | | `audit.integrity.certificate` | ![Development](https://img.shields.io/badge/-development-blue) | string | A reference to the key or certificate used for `audit.integrity.value`. [6] | `key-2024-01`; `SHA256:ab12cd34...` | | `audit.integrity.signer` | ![Development](https://img.shields.io/badge/-development-blue) | string | Identifies which tier produced the integrity proof in `audit.integrity.value`. [7] | `producer`; `collector` | -| `audit.integrity.value` | ![Development](https://img.shields.io/badge/-development-blue) | string | Base64-encoded cryptographic signature or MAC covering this record. [8] | `SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c` | +| `audit.integrity.value` | ![Development](https://img.shields.io/badge/-development-blue) | string | base64-encoded cryptographic signature or MAC covering this record. [8] | `SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c` | **[4] `audit.integrity.algorithm`:** MUST be set as a Resource attribute whenever `audit.integrity.value` is present on any record emitted by this resource. Use a JWA identifier (RFC 7518) for asymmetric signatures (e.g. `ES256`, `RS256`, `EdDSA`) or an IANA MAC Algorithm identifier for symmetric MACs (e.g. `HMAC-SHA256`). @@ -133,9 +133,9 @@ Attributes that describe the network origin or calling context of the action. | Key | Stability | Value Type | Description | Example Values | | --- | --- | --- | --- | --- | | `audit.source.id` | ![Development](https://img.shields.io/badge/-development-blue) | string | A stable identifier for the source system or network endpoint that originated the action. [16] | `192.0.2.42`; `device-uuid-abcd1234` | -| `audit.source.type` | ![Development](https://img.shields.io/badge/-development-blue) | string | The category of origin that initiated the action. [17] | `ipv4`; `ipv6`; `hostname` | +| `audit.source.type` | ![Development](https://img.shields.io/badge/-development-blue) | string | The category of origin that initiated the action. [17] | `IPv4`; `IPv6`; `hostname` | -**[16] `audit.source.id`:** MAY be an IP address, a device UUID, or a service mesh endpoint id. Prefer stable identifiers (device UUID) over ephemeral ones (IP address) when both are available. +**[16] `audit.source.id`:** MAY be an IP address, a device UUID, or a service mesh endpoint ID. Prefer stable identifiers (device UUID) over ephemeral ones (IP address) when both are available. **[17] `audit.source.type`:** Well-known values: `ipv4`, `ipv6`, `hostname`. Custom values MAY be used. diff --git a/model/audit/logs.yaml b/model/audit/logs.yaml index 6b50a1e133..8cf49a6dbb 100644 --- a/model/audit/logs.yaml +++ b/model/audit/logs.yaml @@ -23,7 +23,11 @@ groups: * `EventName` (MUST) — e.g. `audit.user.login`, `audit.config.change`. * `Body` (MAY) — free-form human-readable description; MUST NOT duplicate mandatory attributes. - * `SeverityNumber` (SHOULD NOT) — not meaningful for audit records. + * `SeverityNumber` (SHOULD NOT) — audit records are compliance evidence, not + operational diagnostics. Severity implies triage priority, which has no + meaning for records that MUST all be delivered regardless of their outcome. + Receivers MUST NOT use `SeverityNumber` to filter or prioritize audit records. + Use `audit.outcome` to distinguish success from failure. * `InstrumentationScope` (MUST be left empty). attributes: # --- mandatory --- From 9c2ab7c7517605f68169c3a44c17da88a7dfab8f Mon Sep 17 00:00:00 2001 From: Hilmar Falkenberg Date: Wed, 9 Sep 2026 12:59:57 +0200 Subject: [PATCH 17/21] serialization Signed-off-by: Hilmar Falkenberg --- docs/audit/audit-logs.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/audit/audit-logs.md b/docs/audit/audit-logs.md index 051b3ca71e..b086ac67d8 100644 --- a/docs/audit/audit-logs.md +++ b/docs/audit/audit-logs.md @@ -289,7 +289,7 @@ was not altered in transit. its entire lifetime, so both values are constant across all records emitted by the same resource. They MUST NOT be placed on individual records. - `audit.integrity.value` is the per-record Base64url-encoded signature/MAC - over the canonical serialisation of the record (with `audit.integrity.value` + over the canonical serialization of the record (with `audit.integrity.value` itself absent from the input). - On acknowledgement, the sink returns an `AuditReceipt` containing an `IntegrityHash` (SHA-256 of the persisted record). The emitter SHOULD @@ -412,4 +412,4 @@ The following invariants MUST be respected by every SDK implementation: } ``` -[DocumentStatus]: https://opentelemetry.io/docs/specs/otel/document-status +[DocumentStatus]: https://opentelemetry.io/docs/specs/otel/document-status/ From 519f2776fa485de91900cdff2df47aea5b410116 Mon Sep 17 00:00:00 2001 From: Hilmar Falkenberg Date: Wed, 9 Sep 2026 15:32:28 +0200 Subject: [PATCH 18/21] previous Signed-off-by: Hilmar Falkenberg --- docs/audit/audit-logs.md | 28 ++++++++++++++-------------- docs/registry/attributes/audit.md | 8 ++++---- model/audit/logs.yaml | 8 ++++---- model/audit/registry.yaml | 6 +++--- 4 files changed, 25 insertions(+), 25 deletions(-) diff --git a/docs/audit/audit-logs.md b/docs/audit/audit-logs.md index b086ac67d8..c76ba088a7 100644 --- a/docs/audit/audit-logs.md +++ b/docs/audit/audit-logs.md @@ -125,8 +125,8 @@ namespace. | [`audit.sequence.end`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Conditionally Required` [10] | boolean | Set to `true` on the last record of a gracefully closed audit stream. [11] | `true` | | [`audit.integrity.signer`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Recommended` When `audit.integrity.value` is present. | string | Identifies which tier produced the integrity proof in `audit.integrity.value`. [12] | `producer`; `collector` | | [`audit.sequence.number`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Recommended` [13] | int | A monotonically increasing counter assigned to each record within a single audit stream. [14] | `1`; `42`; `1000001` | -| [`audit.sequence.prev_hash`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Recommended` [15] | string | SHA-256 hex digest of the `IntegrityHash` field of the immediately preceding record in the same audit stream. [16] | `a3f1c2e4b5d6a7f8e9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2` | -| [`audit.sequence.prev_record_id`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Recommended` [17] | string | The `audit.record.id` of the immediately preceding record in the same audit stream. [18] | `3fa85f64-5717-4562-b3fc-2c963f66afa6` | +| [`audit.sequence.previous_hash`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Recommended` [15] | string | SHA-256 hex digest of the `IntegrityHash` field of the immediately preceding record in the same audit stream. [16] | `a3f1c2e4b5d6a7f8e9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2` | +| [`audit.sequence.previous_record_id`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Recommended` [17] | string | The `audit.record.id` of the immediately preceding record in the same audit stream. [18] | `3fa85f64-5717-4562-b3fc-2c963f66afa6` | | [`audit.sequence.stream_id`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Recommended` [19] | string | An opaque identifier that scopes the hash chain to a single audit stream. [20] | `7c9e6679-7425-40de-944b-e07fc1f90ae7` | | [`audit.source.id`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Recommended` [21] | string | A stable identifier for the source system or network endpoint that originated the action. [22] | `192.0.2.42`; `device-uuid-abcd1234` | | [`audit.source.type`](/docs/registry/attributes/audit.md) | ![Development](https://img.shields.io/badge/-development-blue) | `Recommended` When `audit.source.id` is present. | string | The category of origin that initiated the action. [23] | `IPv4`; `IPv6`; `hostname` | @@ -162,17 +162,17 @@ Acceptable forms (in order of preference): a Key ID / `kid` (JOSE header paramet **[12] `audit.integrity.signer`:** `producer` means the SDK computed the value before export. `collector` means a Tier-2 Collector signed or re-signed the record after receiving it. When absent, `producer` SHOULD be assumed. -**[13] `audit.sequence.number`:** When the emitting service maintains a monotonic per-stream counter. Required when `audit.sequence.prev_hash` is present. +**[13] `audit.sequence.number`:** When the emitting service maintains a monotonic per-stream counter. Required when `audit.sequence.previous_hash` is present. **[14] `audit.sequence.number`:** Compliant sinks and Tier-2 Collectors MUST verify that consecutive records within the same stream have strictly increasing sequence numbers. Gaps MUST trigger a gap-detection warning and a security event log entry. The counter SHOULD start at 1 and increment by 1 per emitted record, but implementations MAY use a larger step if records can be emitted concurrently from multiple threads. -**[15] `audit.sequence.prev_hash`:** When the emitting service implements a hash chain for tamper detection. Requires `audit.sequence.number` to be present. MUST be omitted on the genesis record of a stream. +**[15] `audit.sequence.previous_hash`:** When the emitting service implements a hash chain for tamper detection. Requires `audit.sequence.number` to be present. MUST be omitted on the genesis record of a stream. -**[16] `audit.sequence.prev_hash`:** Including the previous record's sink-acknowledged hash in the current record creates an append-only hash chain. Any retroactive modification of a record is detectable by re-verifying the chain. MUST be omitted on the genesis (first) record of a stream — absence is the normative signal; no magic sentinel constant is required. +**[16] `audit.sequence.previous_hash`:** Including the previous record's sink-acknowledged hash in the current record creates an append-only hash chain. Any retroactive modification of a record is detectable by re-verifying the chain. MUST be omitted on the genesis (first) record of a stream — absence is the normative signal; no magic sentinel constant is required. -**[17] `audit.sequence.prev_record_id`:** When `audit.sequence.prev_hash` is present. Provides a resolvable locator for the predecessor record across storage boundaries. MUST be omitted on the genesis record of a stream. +**[17] `audit.sequence.previous_record_id`:** When `audit.sequence.previous_hash` is present. Provides a resolvable locator for the predecessor record across storage boundaries. MUST be omitted on the genesis record of a stream. -**[18] `audit.sequence.prev_record_id`:** Provides a resolvable locator for the predecessor across shards, storage systems, and retention boundaries, complementing `audit.sequence.prev_hash`. MUST be omitted on the genesis (first) record of a stream. +**[18] `audit.sequence.previous_record_id`:** Provides a resolvable locator for the predecessor across shards, storage systems, and retention boundaries, complementing `audit.sequence.previous_hash`. MUST be omitted on the genesis (first) record of a stream. **[19] `audit.sequence.stream_id`:** When the emitting service uses hash-chain ordering. Scopes the chain to a single `AuditLogger` instance. @@ -301,17 +301,17 @@ to allow the sink to verify without possessing the signing key. ### Hash-chain ordering -`audit.sequence.number` and `audit.sequence.prev_hash` together form an append-only +`audit.sequence.number` and `audit.sequence.previous_hash` together form an append-only hash chain: ``` -Record N: sequence.number=N, sequence.prev_hash=IntegrityHash(Record N-1) -Record N+1: sequence.number=N+1, sequence.prev_hash=IntegrityHash(Record N) +Record N: sequence.number=N, sequence.previous_hash=IntegrityHash(Record N-1) +Record N+1: sequence.number=N+1, sequence.previous_hash=IntegrityHash(Record N) ``` -Any retroactive modification of Record N causes the `audit.sequence.prev_hash` of Record N+1 +Any retroactive modification of Record N causes the `audit.sequence.previous_hash` of Record N+1 to become invalid, making the tampering detectable without re-signing. -Set `audit.sequence.prev_hash` to the all-zeros string for the very first record. +The genesis (first) record of a stream MUST omit `audit.sequence.previous_hash` — absence is the normative signal. ## AuditReceipt @@ -356,7 +356,7 @@ The following invariants MUST be respected by every SDK implementation: | ISO 27001 A.8.17 — Clock sync | SDK warns when `\|Timestamp − ObservedTimestamp\|` > 5 s. | | SOC 2 CC7.2 — Anomaly detection | `audit.records.dropped` metric + operational alert. | | PCI-DSS Req. 10.2 — Audit trails | Mandatory attributes cover all required fields; `audit.source.id` for IP. | -| PCI-DSS Req. 10.5 — Log protection | `audit.integrity.value` + `audit.sequence.prev_hash` hash chain. | +| PCI-DSS Req. 10.5 — Log protection | `audit.integrity.value` + `audit.sequence.previous_hash` hash chain. | | HIPAA § 164.312(b) — Audit controls | `audit.actor.*` + `audit.target.*` cover ePHI access logging. | ## Examples @@ -405,7 +405,7 @@ The following invariants MUST be respected by every SDK implementation: "audit.source.id": "device-uuid-abcd1234", "audit.source.type": "device", "audit.sequence.number": 42, - "audit.sequence.prev_hash": "a3f1c2e4b5d6a7f8e9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2", + "audit.sequence.previous_hash": "a3f1c2e4b5d6a7f8e9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2", "audit.integrity.value": "SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c", "audit.schema.version": "1.0.0" } diff --git a/docs/registry/attributes/audit.md b/docs/registry/attributes/audit.md index be2490bb0c..7be18d247f 100644 --- a/docs/registry/attributes/audit.md +++ b/docs/registry/attributes/audit.md @@ -110,17 +110,17 @@ Attributes that link audit records into an ordered, tamper-evident chain within | --- | --- | --- | --- | --- | | `audit.sequence.end` | ![Development](https://img.shields.io/badge/-development-blue) | boolean | Set to `true` on the last record of a gracefully closed audit stream. [11] | `true` | | `audit.sequence.number` | ![Development](https://img.shields.io/badge/-development-blue) | int | A monotonically increasing counter assigned to each record within a single audit stream. [12] | `1`; `42`; `1000001` | -| `audit.sequence.prev_hash` | ![Development](https://img.shields.io/badge/-development-blue) | string | SHA-256 hex digest of the `IntegrityHash` field of the immediately preceding record in the same audit stream. [13] | `a3f1c2e4b5d6a7f8e9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2` | -| `audit.sequence.prev_record_id` | ![Development](https://img.shields.io/badge/-development-blue) | string | The `audit.record.id` of the immediately preceding record in the same audit stream. [14] | `3fa85f64-5717-4562-b3fc-2c963f66afa6` | +| `audit.sequence.previous_hash` | ![Development](https://img.shields.io/badge/-development-blue) | string | SHA-256 hex digest of the `IntegrityHash` field of the immediately preceding record in the same audit stream. [13] | `a3f1c2e4b5d6a7f8e9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2` | +| `audit.sequence.previous_record_id` | ![Development](https://img.shields.io/badge/-development-blue) | string | The `audit.record.id` of the immediately preceding record in the same audit stream. [14] | `3fa85f64-5717-4562-b3fc-2c963f66afa6` | | `audit.sequence.stream_id` | ![Development](https://img.shields.io/badge/-development-blue) | string | An opaque identifier that scopes the hash chain to a single audit stream. [15] | `7c9e6679-7425-40de-944b-e07fc1f90ae7` | **[11] `audit.sequence.end`:** Emitted by the SDK during `ForceFlush` or `Shutdown` to mark the terminal record of a stream. Absence is normal for all intermediate records — do not treat absence as an error. **[12] `audit.sequence.number`:** Compliant sinks and Tier-2 Collectors MUST verify that consecutive records within the same stream have strictly increasing sequence numbers. Gaps MUST trigger a gap-detection warning and a security event log entry. The counter SHOULD start at 1 and increment by 1 per emitted record, but implementations MAY use a larger step if records can be emitted concurrently from multiple threads. -**[13] `audit.sequence.prev_hash`:** Including the previous record's sink-acknowledged hash in the current record creates an append-only hash chain. Any retroactive modification of a record is detectable by re-verifying the chain. MUST be omitted on the genesis (first) record of a stream — absence is the normative signal; no magic sentinel constant is required. +**[13] `audit.sequence.previous_hash`:** Including the previous record's sink-acknowledged hash in the current record creates an append-only hash chain. Any retroactive modification of a record is detectable by re-verifying the chain. MUST be omitted on the genesis (first) record of a stream — absence is the normative signal; no magic sentinel constant is required. -**[14] `audit.sequence.prev_record_id`:** Provides a resolvable locator for the predecessor across shards, storage systems, and retention boundaries, complementing `audit.sequence.prev_hash`. MUST be omitted on the genesis (first) record of a stream. +**[14] `audit.sequence.previous_record_id`:** Provides a resolvable locator for the predecessor across shards, storage systems, and retention boundaries, complementing `audit.sequence.previous_hash`. MUST be omitted on the genesis (first) record of a stream. **[15] `audit.sequence.stream_id`:** The SDK SHOULD generate a UUID v4 once per `AuditLogger` instance and include it on every record emitted by that logger. diff --git a/model/audit/logs.yaml b/model/audit/logs.yaml index 8cf49a6dbb..625505c4dd 100644 --- a/model/audit/logs.yaml +++ b/model/audit/logs.yaml @@ -102,17 +102,17 @@ groups: requirement_level: recommended: > When the emitting service maintains a monotonic per-stream counter. - Required when `audit.sequence.prev_hash` is present. - - ref: audit.sequence.prev_hash + Required when `audit.sequence.previous_hash` is present. + - ref: audit.sequence.previous_hash requirement_level: recommended: > When the emitting service implements a hash chain for tamper detection. Requires `audit.sequence.number` to be present. MUST be omitted on the genesis record of a stream. - - ref: audit.sequence.prev_record_id + - ref: audit.sequence.previous_record_id requirement_level: recommended: > - When `audit.sequence.prev_hash` is present. Provides a resolvable + When `audit.sequence.previous_hash` is present. Provides a resolvable locator for the predecessor record across storage boundaries. MUST be omitted on the genesis record of a stream. - ref: audit.sequence.end diff --git a/model/audit/registry.yaml b/model/audit/registry.yaml index 50168e5ebf..3e26ed3ca4 100644 --- a/model/audit/registry.yaml +++ b/model/audit/registry.yaml @@ -332,7 +332,7 @@ groups: concurrently from multiple threads. examples: [1, 42, 1000001] - - id: audit.sequence.prev_hash + - id: audit.sequence.previous_hash type: string stability: development brief: > @@ -347,7 +347,7 @@ groups: examples: - "a3f1c2e4b5d6a7f8e9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2" - - id: audit.sequence.prev_record_id + - id: audit.sequence.previous_record_id type: string stability: development brief: > @@ -355,7 +355,7 @@ groups: audit stream. note: > Provides a resolvable locator for the predecessor across shards, storage - systems, and retention boundaries, complementing `audit.sequence.prev_hash`. + systems, and retention boundaries, complementing `audit.sequence.previous_hash`. MUST be omitted on the genesis (first) record of a stream. examples: - "3fa85f64-5717-4562-b3fc-2c963f66afa6" From e46b4f6bc139fc42c071c58ae0824cacf44c9703 Mon Sep 17 00:00:00 2001 From: Hilmar Falkenberg Date: Wed, 9 Sep 2026 15:44:01 +0200 Subject: [PATCH 19/21] format table, fix Examples Signed-off-by: Hilmar Falkenberg --- docs/audit/audit-logs.md | 72 +++++++++++++++++++++------------------- 1 file changed, 38 insertions(+), 34 deletions(-) diff --git a/docs/audit/audit-logs.md b/docs/audit/audit-logs.md index c76ba088a7..95af945476 100644 --- a/docs/audit/audit-logs.md +++ b/docs/audit/audit-logs.md @@ -335,29 +335,31 @@ configured timeout. It MUST NOT return successfully without a valid receipt. The following invariants MUST be respected by every SDK implementation: -| # | Invariant | -| --- | --- | -| 1 | `AuditProvider` MUST NOT accept sampler or sampling-rate configuration. | -| 2 | `emit()` MUST block until the sink acknowledges, or raise a hard error. | -| 3 | `emit()` MUST return a valid `AuditReceipt`. | -| 4 | The queue MUST be disk-backed or unbounded in-memory — **never** silently drops. | -| 5 | Processors are additive-only: MAY enrich; MUST NOT delete, filter, or transform. | -| 6 | Transport: `POST /v1/audit` with `audit: true` on `ResourceLogs`. | -| 7 | `partial_success` in a sink response MUST be treated as a hard `Failure`. | -| 8 | `InstrumentationScope` MUST be left empty. | -| 9 | SDK exposes metrics: `audit.records.emitted`, `audit.records.exported`, `audit.records.dropped`, `audit.queue.depth`, `audit.export.duration`. | -| 10 | Non-zero `audit.records.dropped` MUST trigger an operational alert. | +| # | Invariant | +|----|------------------------------------------------------------------------------------------------------------------------------------------------| +| 1 | `AuditProvider` MUST NOT accept sampler or sampling-rate configuration. | +| 2 | `emit()` MUST block until the sink acknowledges, or raise a hard error. | +| 3 | `emit()` MUST return a valid `AuditReceipt`. | +| 4 | The queue MUST be disk-backed or unbounded in-memory — **never** silently drops. | +| 5 | Processors are additive-only: MAY enrich; MUST NOT delete, filter, or transform. | +| 6 | Transport: `POST /v1/audit` with `audit: true` on `ResourceLogs`. | +| 7 | `partial_success` in a sink response MUST be treated as a hard `Failure`. | +| 8 | `InstrumentationScope` MUST be left empty. | +| 9 | SDK exposes metrics: `audit.records.emitted`, `audit.records.exported`, `audit.records.dropped`, `audit.queue.depth`, `audit.export.duration`. | +| 10 | Non-zero `audit.records.dropped` MUST trigger an operational alert. | +| 11 | `emit()` called on a mandatory attribute missing or empty MUST raise a hard error — MUST NOT silently drop the record. | +| 12 | `emit()` called after `Shutdown` MUST raise a hard error — MUST NOT silently drop the record. | ## Compliance mapping -| Requirement | Audit signal feature | -| --- | --- | -| ISO 27001 A.8.15 — Logging | All actions recorded; logs protected via integrity attributes. | -| ISO 27001 A.8.17 — Clock sync | SDK warns when `\|Timestamp − ObservedTimestamp\|` > 5 s. | -| SOC 2 CC7.2 — Anomaly detection | `audit.records.dropped` metric + operational alert. | -| PCI-DSS Req. 10.2 — Audit trails | Mandatory attributes cover all required fields; `audit.source.id` for IP. | -| PCI-DSS Req. 10.5 — Log protection | `audit.integrity.value` + `audit.sequence.previous_hash` hash chain. | -| HIPAA § 164.312(b) — Audit controls | `audit.actor.*` + `audit.target.*` cover ePHI access logging. | +| Requirement | Audit signal feature | +|-------------------------------------|---------------------------------------------------------------------------| +| ISO 27001 A.8.15 — Logging | All actions recorded; logs protected via integrity attributes. | +| ISO 27001 A.8.17 — Clock sync | SDK warns when `\|Timestamp − ObservedTimestamp\|` > 5 s. | +| SOC 2 CC7.2 — Anomaly detection | `audit.records.dropped` metric + operational alert. | +| PCI-DSS Req. 10.2 — Audit trails | Mandatory attributes cover all required fields; `audit.source.id` for IP. | +| PCI-DSS Req. 10.5 — Log protection | `audit.integrity.value` + `audit.sequence.previous_hash` hash chain. | +| HIPAA § 164.312(b) — Audit controls | `audit.actor.*` + `audit.target.*` cover ePHI access logging. | ## Examples @@ -376,7 +378,7 @@ The following invariants MUST be respected by every SDK implementation: "audit.action": "LOGIN", "audit.outcome": "success", "audit.source.id": "192.0.2.42", - "audit.source.type": "ip_address" + "audit.source.type": "ipv4" } } ``` @@ -395,19 +397,21 @@ The following invariants MUST be respected by every SDK implementation: "audit.integrity.certificate": "key-2024-01" }, "Attributes": { - "audit.record.id": "7c9e6679-7425-40de-944b-e07fc1f90ae7", - "audit.actor.id": "svc-deployer", - "audit.actor.type": "service", - "audit.action": "DELETE", - "audit.outcome": "success", - "audit.target.id": "invoice-8819", - "audit.target.type": "finance.invoice", - "audit.source.id": "device-uuid-abcd1234", - "audit.source.type": "device", - "audit.sequence.number": 42, - "audit.sequence.previous_hash": "a3f1c2e4b5d6a7f8e9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2", - "audit.integrity.value": "SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c", - "audit.schema.version": "1.0.0" + "audit.record.id": "7c9e6679-7425-40de-944b-e07fc1f90ae7", + "audit.actor.id": "svc-deployer", + "audit.actor.type": "service", + "audit.action": "DELETE", + "audit.outcome": "success", + "audit.target.id": "invoice-8819", + "audit.target.type": "finance.invoice", + "audit.source.id": "192.0.2.99", + "audit.source.type": "ipv4", + "audit.sequence.stream_id": "b1d2e3f4-a5b6-7c8d-9e0f-a1b2c3d4e5f6", + "audit.sequence.number": 42, + "audit.sequence.previous_hash": "a3f1c2e4b5d6a7f8e9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2", + "audit.integrity.value": "SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV+adQssw5c", + "audit.integrity.signer": "producer", + "audit.schema.version": "1.0.0" } } ``` From dd2a1550c96de6e23e647f32c9292dc6378b5d23 Mon Sep 17 00:00:00 2001 From: Hilmar Falkenberg Date: Wed, 9 Sep 2026 17:05:14 +0200 Subject: [PATCH 20/21] Base64url -> Base64 Signed-off-by: Hilmar Falkenberg --- docs/audit/audit-logs.md | 4 ++-- docs/registry/attributes/audit.md | 2 +- model/audit/registry.yaml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/audit/audit-logs.md b/docs/audit/audit-logs.md index 95af945476..4ca12ecdae 100644 --- a/docs/audit/audit-logs.md +++ b/docs/audit/audit-logs.md @@ -154,7 +154,7 @@ namespace. **[8] `audit.integrity.certificate`:** Required (as a Resource attribute, together with `audit.integrity.algorithm`) when `audit.integrity.value` is present on any record emitted from this resource. **[9] `audit.integrity.certificate`:** MUST be set as a Resource attribute (together with `audit.integrity.algorithm`) whenever `audit.integrity.value` is present on any record emitted by this resource. Because a service instance uses a single signing key for its entire lifetime, both `audit.integrity.algorithm` and `audit.integrity.certificate` are constant across all records from the same resource and therefore belong on the Resource, not on individual records. -Acceptable forms (in order of preference): a Key ID / `kid` (JOSE header parameter), a DER-encoded X.509 certificate Base64url-encoded, an X.509 certificate fingerprint (SHA-256 hex), or an Issuer + Serial Number pair. Receivers MUST NOT use this field alone for trust decisions; key validation MUST be performed out-of-band. +Acceptable forms (in order of preference): a Key ID / `kid` (JOSE header parameter), a DER-encoded X.509 certificate Base64-encoded, an X.509 certificate fingerprint (SHA-256 hex), or an Issuer + Serial Number pair. Receivers MUST NOT use this field alone for trust decisions; key validation MUST be performed out-of-band. **[10] `audit.sequence.end`:** Required on the final record of a gracefully closed stream (emitted during `ForceFlush` or `Shutdown`). Omit on all other records. @@ -288,7 +288,7 @@ was not altered in transit. **Resource attributes**. A service instance uses a single signing key for its entire lifetime, so both values are constant across all records emitted by the same resource. They MUST NOT be placed on individual records. -- `audit.integrity.value` is the per-record Base64url-encoded signature/MAC +- `audit.integrity.value` is the per-record Base64-encoded signature/MAC over the canonical serialization of the record (with `audit.integrity.value` itself absent from the input). - On acknowledgement, the sink returns an `AuditReceipt` containing an diff --git a/docs/registry/attributes/audit.md b/docs/registry/attributes/audit.md index 7be18d247f..6fab8a57e6 100644 --- a/docs/registry/attributes/audit.md +++ b/docs/registry/attributes/audit.md @@ -79,7 +79,7 @@ Attributes that provide cryptographic evidence that the audit record has not bee **[5] `audit.integrity.canonicalization`:** Defaults to `jcs` (RFC 8785 JSON Canonicalization Scheme). Set explicitly when any other canonicalization is used so that verifiers can reproduce the exact byte sequence that was signed. MUST be omitted when `jcs` is used. **[6] `audit.integrity.certificate`:** MUST be set as a Resource attribute (together with `audit.integrity.algorithm`) whenever `audit.integrity.value` is present on any record emitted by this resource. Because a service instance uses a single signing key for its entire lifetime, both `audit.integrity.algorithm` and `audit.integrity.certificate` are constant across all records from the same resource and therefore belong on the Resource, not on individual records. -Acceptable forms (in order of preference): a Key ID / `kid` (JOSE header parameter), a DER-encoded X.509 certificate Base64url-encoded, an X.509 certificate fingerprint (SHA-256 hex), or an Issuer + Serial Number pair. Receivers MUST NOT use this field alone for trust decisions; key validation MUST be performed out-of-band. +Acceptable forms (in order of preference): a Key ID / `kid` (JOSE header parameter), a DER-encoded X.509 certificate Base64-encoded, an X.509 certificate fingerprint (SHA-256 hex), or an Issuer + Serial Number pair. Receivers MUST NOT use this field alone for trust decisions; key validation MUST be performed out-of-band. **[7] `audit.integrity.signer`:** `producer` means the SDK computed the value before export. `collector` means a Tier-2 Collector signed or re-signed the record after receiving it. When absent, `producer` SHOULD be assumed. diff --git a/model/audit/registry.yaml b/model/audit/registry.yaml index 3e26ed3ca4..c73d14c9c1 100644 --- a/model/audit/registry.yaml +++ b/model/audit/registry.yaml @@ -299,7 +299,7 @@ groups: same resource and therefore belong on the Resource, not on individual records. Acceptable forms (in order of preference): a Key ID / `kid` (JOSE header - parameter), a DER-encoded X.509 certificate Base64url-encoded, an X.509 + parameter), a DER-encoded X.509 certificate Base64-encoded, an X.509 certificate fingerprint (SHA-256 hex), or an Issuer + Serial Number pair. Receivers MUST NOT use this field alone for trust decisions; key validation MUST be performed out-of-band. From 4264c1c066124062baaca7ae3ea3d345c67a6dec Mon Sep 17 00:00:00 2001 From: Hilmar Falkenberg Date: Wed, 9 Sep 2026 17:13:34 +0200 Subject: [PATCH 21/21] textlint requires lowercase Signed-off-by: Hilmar Falkenberg --- docs/audit/audit-logs.md | 4 ++-- docs/registry/attributes/audit.md | 2 +- model/audit/registry.yaml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/audit/audit-logs.md b/docs/audit/audit-logs.md index 4ca12ecdae..0a43c260f4 100644 --- a/docs/audit/audit-logs.md +++ b/docs/audit/audit-logs.md @@ -154,7 +154,7 @@ namespace. **[8] `audit.integrity.certificate`:** Required (as a Resource attribute, together with `audit.integrity.algorithm`) when `audit.integrity.value` is present on any record emitted from this resource. **[9] `audit.integrity.certificate`:** MUST be set as a Resource attribute (together with `audit.integrity.algorithm`) whenever `audit.integrity.value` is present on any record emitted by this resource. Because a service instance uses a single signing key for its entire lifetime, both `audit.integrity.algorithm` and `audit.integrity.certificate` are constant across all records from the same resource and therefore belong on the Resource, not on individual records. -Acceptable forms (in order of preference): a Key ID / `kid` (JOSE header parameter), a DER-encoded X.509 certificate Base64-encoded, an X.509 certificate fingerprint (SHA-256 hex), or an Issuer + Serial Number pair. Receivers MUST NOT use this field alone for trust decisions; key validation MUST be performed out-of-band. +Acceptable forms (in order of preference): a Key ID / `kid` (JOSE header parameter), a DER-encoded X.509 certificate base64-encoded, an X.509 certificate fingerprint (SHA-256 hex), or an Issuer + Serial Number pair. Receivers MUST NOT use this field alone for trust decisions; key validation MUST be performed out-of-band. **[10] `audit.sequence.end`:** Required on the final record of a gracefully closed stream (emitted during `ForceFlush` or `Shutdown`). Omit on all other records. @@ -288,7 +288,7 @@ was not altered in transit. **Resource attributes**. A service instance uses a single signing key for its entire lifetime, so both values are constant across all records emitted by the same resource. They MUST NOT be placed on individual records. -- `audit.integrity.value` is the per-record Base64-encoded signature/MAC +- `audit.integrity.value` is the per-record base64-encoded signature/MAC over the canonical serialization of the record (with `audit.integrity.value` itself absent from the input). - On acknowledgement, the sink returns an `AuditReceipt` containing an diff --git a/docs/registry/attributes/audit.md b/docs/registry/attributes/audit.md index 6fab8a57e6..0faa6237d0 100644 --- a/docs/registry/attributes/audit.md +++ b/docs/registry/attributes/audit.md @@ -79,7 +79,7 @@ Attributes that provide cryptographic evidence that the audit record has not bee **[5] `audit.integrity.canonicalization`:** Defaults to `jcs` (RFC 8785 JSON Canonicalization Scheme). Set explicitly when any other canonicalization is used so that verifiers can reproduce the exact byte sequence that was signed. MUST be omitted when `jcs` is used. **[6] `audit.integrity.certificate`:** MUST be set as a Resource attribute (together with `audit.integrity.algorithm`) whenever `audit.integrity.value` is present on any record emitted by this resource. Because a service instance uses a single signing key for its entire lifetime, both `audit.integrity.algorithm` and `audit.integrity.certificate` are constant across all records from the same resource and therefore belong on the Resource, not on individual records. -Acceptable forms (in order of preference): a Key ID / `kid` (JOSE header parameter), a DER-encoded X.509 certificate Base64-encoded, an X.509 certificate fingerprint (SHA-256 hex), or an Issuer + Serial Number pair. Receivers MUST NOT use this field alone for trust decisions; key validation MUST be performed out-of-band. +Acceptable forms (in order of preference): a Key ID / `kid` (JOSE header parameter), a DER-encoded X.509 certificate base64-encoded, an X.509 certificate fingerprint (SHA-256 hex), or an Issuer + Serial Number pair. Receivers MUST NOT use this field alone for trust decisions; key validation MUST be performed out-of-band. **[7] `audit.integrity.signer`:** `producer` means the SDK computed the value before export. `collector` means a Tier-2 Collector signed or re-signed the record after receiving it. When absent, `producer` SHOULD be assumed. diff --git a/model/audit/registry.yaml b/model/audit/registry.yaml index c73d14c9c1..132d859c53 100644 --- a/model/audit/registry.yaml +++ b/model/audit/registry.yaml @@ -299,7 +299,7 @@ groups: same resource and therefore belong on the Resource, not on individual records. Acceptable forms (in order of preference): a Key ID / `kid` (JOSE header - parameter), a DER-encoded X.509 certificate Base64-encoded, an X.509 + parameter), a DER-encoded X.509 certificate base64-encoded, an X.509 certificate fingerprint (SHA-256 hex), or an Issuer + Serial Number pair. Receivers MUST NOT use this field alone for trust decisions; key validation MUST be performed out-of-band.