From c5c2bf0782e8b977d99e4d3827e1748d5f46af35 Mon Sep 17 00:00:00 2001 From: Ramon Smits Date: Wed, 8 Jul 2026 09:54:23 +0200 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Add=20ecs.version=20to=20the=20audi?= =?UTF-8?q?t=20log=20ECS=20documents?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The authorization and message-action audit documents omitted the ecs.version field. ECS-consuming pipelines (Elasticsearch's built-in logs-*-* index template, Elastic Security, other SIEMs) use ecs.version to select the matching field mappings, so a conformant document should declare it. Both streams now emit "ecs": { "version": "8.11.0" } — the latest ECS schema release, whose event.category/type/outcome and user.* fields are what these documents already use. Additive, non-breaking output change. First shipped in 6.18.0 without the field, so this targets the next patch (6.18.1) or minor (6.19.0). ECS version field: https://www.elastic.co/guide/en/ecs/current/ecs-ecs.html event.type allowed values (allowed/denied/change/deletion): https://www.elastic.co/guide/en/ecs/current/ecs-allowed-values-event-type.html ECS releases: https://github.com/elastic/ecs/releases --- .../Auth/AuthorizationAuditLogTests.cs | 1 + .../Auth/MessageActionAuditLogTests.cs | 1 + .../Auth/AuthorizationAuditLog.cs | 7 +++++++ .../Auth/MessageActionAuditLog.cs | 1 + 4 files changed, 10 insertions(+) diff --git a/src/ServiceControl.Infrastructure.Tests/Auth/AuthorizationAuditLogTests.cs b/src/ServiceControl.Infrastructure.Tests/Auth/AuthorizationAuditLogTests.cs index 1db40a1b6c..c6b65e5565 100644 --- a/src/ServiceControl.Infrastructure.Tests/Auth/AuthorizationAuditLogTests.cs +++ b/src/ServiceControl.Infrastructure.Tests/Auth/AuthorizationAuditLogTests.cs @@ -27,6 +27,7 @@ public void Decision_allow_emits_one_entry_on_audit_category() Assert.That(ecs.GetProperty("user").GetProperty("id").GetString(), Is.EqualTo("alice-sub-001")); Assert.That(ecs.GetProperty("user").GetProperty("name").GetString(), Is.EqualTo("Alice Smith")); Assert.That(ecs.GetProperty("event").GetProperty("action").GetString(), Is.EqualTo("error:messages:retry")); + Assert.That(ecs.GetProperty("ecs").GetProperty("version").GetString(), Is.EqualTo("8.11.0")); Assert.That(entries[0].Level, Is.EqualTo(LogLevel.Information)); } diff --git a/src/ServiceControl.Infrastructure.Tests/Auth/MessageActionAuditLogTests.cs b/src/ServiceControl.Infrastructure.Tests/Auth/MessageActionAuditLogTests.cs index f2092f5022..31ebebc0fc 100644 --- a/src/ServiceControl.Infrastructure.Tests/Auth/MessageActionAuditLogTests.cs +++ b/src/ServiceControl.Infrastructure.Tests/Auth/MessageActionAuditLogTests.cs @@ -41,6 +41,7 @@ public void Operation_emits_one_entry_on_operation_category() Assert.That(ecs.GetProperty("servicecontrol").GetProperty("resource").GetString(), Is.EqualTo("group-1")); Assert.That(ecs.GetProperty("servicecontrol").GetProperty("count").GetInt32(), Is.EqualTo(42)); Assert.That(ecs.GetProperty("servicecontrol").GetProperty("operation").GetProperty("id").GetString(), Is.EqualTo("op-1")); + Assert.That(ecs.GetProperty("ecs").GetProperty("version").GetString(), Is.EqualTo("8.11.0")); } [Test] diff --git a/src/ServiceControl.Infrastructure/Auth/AuthorizationAuditLog.cs b/src/ServiceControl.Infrastructure/Auth/AuthorizationAuditLog.cs index 83e75e0f7c..8c4ea1b54b 100644 --- a/src/ServiceControl.Infrastructure/Auth/AuthorizationAuditLog.cs +++ b/src/ServiceControl.Infrastructure/Auth/AuthorizationAuditLog.cs @@ -16,6 +16,12 @@ public sealed class AuthorizationAuditLog(ILoggerFactory loggerFactory) : IAutho { public const string AuditCategory = "ServiceControl.Audit"; // Logger name is used in logging configuration to write audit entries to a separate file. + // The ECS version the emitted documents conform to, surfaced as the ecs.version field so downstream + // pipelines can pick the matching mappings. 8.11.0 is the latest ECS schema release; the fields used + // here (event.category/type/outcome, user.*) are stable across the 8.x line. Shared with + // MessageActionAuditLog so both streams declare the same version. + internal const string EcsVersion = "8.11.0"; + readonly ILogger logger = loggerFactory.CreateLogger(AuditCategory); // Relaxed escaping keeps the JSON readable for log sinks (no \uXXXX for '+', '<', accented names, …); @@ -49,6 +55,7 @@ static string BuildEcsEvent(string subjectId, string subjectName, string permiss var ecs = new Dictionary { ["@timestamp"] = DateTimeOffset.UtcNow.ToString("O"), + ["ecs"] = new { version = EcsVersion }, ["event"] = new { kind = "event", diff --git a/src/ServiceControl.Infrastructure/Auth/MessageActionAuditLog.cs b/src/ServiceControl.Infrastructure/Auth/MessageActionAuditLog.cs index abe63658b4..958724d309 100644 --- a/src/ServiceControl.Infrastructure/Auth/MessageActionAuditLog.cs +++ b/src/ServiceControl.Infrastructure/Auth/MessageActionAuditLog.cs @@ -66,6 +66,7 @@ static string BuildEcsEvent(AuditUser user, MessageActionKind kind, string permi var ecs = new Dictionary { ["@timestamp"] = DateTimeOffset.UtcNow.ToString("O"), + ["ecs"] = new { version = AuthorizationAuditLog.EcsVersion }, ["event"] = new { kind = "event",