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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions cmd/client_audit_get.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ Requires audit:read permission.
if entry.OperationID != "" {
cli.PrintKV("Operation", entry.OperationID)
}
if entry.TraceID != "" {
cli.PrintKV("Trace ID", entry.TraceID)
}
},
}

Expand Down
7 changes: 7 additions & 0 deletions cmd/client_audit_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ response status, and duration. Requires audit:read permission.

rows := make([][]string, 0, len(resp.Data.Items))
for _, entry := range resp.Data.Items {
traceID := ""
if entry.TraceID != "" {
traceID = entry.TraceID[:16] + "…"
}

rows = append(rows, []string{
entry.ID,
entry.Timestamp.Format("2006-01-02 15:04:05"),
Expand All @@ -74,6 +79,7 @@ response status, and duration. Requires audit:read permission.
entry.Path,
strconv.Itoa(entry.ResponseCode),
strconv.FormatInt(entry.DurationMs, 10) + "ms",
traceID,
})
}

Expand All @@ -88,6 +94,7 @@ response status, and duration. Requires audit:read permission.
"PATH",
"STATUS",
"DURATION",
"TRACE ID",
},
Rows: rows,
},
Expand Down
29 changes: 24 additions & 5 deletions cmd/controller_setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -643,17 +643,36 @@ func createAuditStore(
nc NATSClient,
namespace string,
) (audit.Store, []api.Option) {
if appConfig.NATS.Audit.Bucket == "" {
if appConfig.NATS.Audit.Stream == "" {
return nil, nil
}

auditKVConfig := cli.BuildAuditKVConfig(namespace, appConfig.NATS.Audit)
auditKV, err := nc.CreateOrUpdateKVBucketWithConfig(ctx, auditKVConfig)
auditStreamConfig := cli.BuildAuditStreamConfig(
namespace,
appConfig.NATS.Audit,
)
if err := nc.CreateOrUpdateStreamWithConfig(
ctx,
auditStreamConfig,
); err != nil {
cli.LogFatal(log, "failed to create audit stream", err)
}

streamName := job.ApplyNamespaceToInfraName(
namespace,
appConfig.NATS.Audit.Stream,
)
stream, err := nc.Stream(ctx, streamName)
if err != nil {
cli.LogFatal(log, "failed to create audit KV bucket", err)
cli.LogFatal(log, "failed to get audit stream", err)
}

store := audit.NewKVStore(log, auditKV)
subject := job.ApplyNamespaceToSubjects(
namespace,
appConfig.NATS.Audit.Subject,
)

store := audit.NewStreamStore(log, stream, nc, subject)

return store, []api.Option{api.WithAuditStore(store)}
}
Expand Down
20 changes: 15 additions & 5 deletions cmd/nats_setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,11 +147,21 @@ func setupJetStream(
return fmt.Errorf("create KV bucket %s: %w", kvResponseBucket, err)
}

// Create audit KV bucket with configured settings
if appConfig.NATS.Audit.Bucket != "" {
auditKVConfig := cli.BuildAuditKVConfig(namespace, appConfig.NATS.Audit)
if _, err := nc.CreateOrUpdateKVBucketWithConfig(ctx, auditKVConfig); err != nil {
return fmt.Errorf("create audit KV bucket %s: %w", auditKVConfig.Bucket, err)
// Create audit stream with configured settings
if appConfig.NATS.Audit.Stream != "" {
auditStreamConfig := cli.BuildAuditStreamConfig(
namespace,
appConfig.NATS.Audit,
)
if err := nc.CreateOrUpdateStreamWithConfig(
ctx,
auditStreamConfig,
); err != nil {
return fmt.Errorf(
"create audit stream %s: %w",
auditStreamConfig.Name,
err,
)
}
}

Expand Down
7 changes: 4 additions & 3 deletions configs/osapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,11 @@ nats:
replicas: 1

audit:
bucket: audit-log
ttl: 720h
stream: 'AUDIT'
subject: 'audit'
max_age: '720h'
max_bytes: 52428800
storage: file
storage: 'file'
replicas: 1

registry:
Expand Down
13 changes: 11 additions & 2 deletions docs/docs/gen/api/get-audit-export.api.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ description: "Returns all audit log entries without pagination for export."
sidebar_label: "Export all audit log entries"
hide_title: true
hide_table_of_contents: true
api: eJztV21v4kYQ/iur+dRKBgwH6Z0/lbbJHae7NkqJIjVCaPEOsBd719kdJ6HI/72aNRAMpI3Uq9QP9wnbzMuz88zbrsEW6CRpa0YKEniPNCyVpvOnwjqCCBT61OmCBSCBK6TSGS9klgnJciKzC4GGnEYvHjUtbUmikAttgk0xt05gsNWGCEguPCS3EFxMP9nFdHg5mgZDMInAY1o6TStIbtfwE0qHbljSkjWCTOJQKphUkwgc+sIajx6SNfTimH+aUIc7iBt4DCC1htAQS8uiyHQaUHa+eFZZg0+XmEt+olWBkICdfcGUw1A4jhPp2iFZktlUE+Z+T1gbwgW6o6CNWVqYMp+hE3Z+jAqfZF5kCEl3EFcRHNqVzskVHH9/AZxWezKenDYLiGBuXS4JEihLrY4gXht9X6LQCg3puUYXiKMl7oFdNaDCYBDj234ct7D3btbqd1W/JX/onrX6/bOzwaDfj+M4hioC0jl6knnxt6iUJGyx6BG0myWagMThfYmexKP0onA2Re9RNTH14t5ZK+61et1xN07exEkc/8EYSo/ulPuDjClpyedPJaESrCO++3gzFr4Mgf6+6csW/sfNWzu1ObtxNsPXELfxXx1VF+uLubN5ODD7JnuHpuH4FqTKtYFJFUGOtLQn6W4a/jAeX4pauHmI9+djhlFIrrJ/snK1IeD66pNgjaapjrEKO0vrycgc2equs0xPp2TT+m8FmuHlSOy0xOiXA7BIv1qFH/ZceFu6FKf6ZHI17f+caTQkRpdCKuXQNysPuu967e7Z23a33a3zdtthpqlV+IoqDzHeKglPkkovWLfhpxdzhatyE5gX+seuLLShs/6LRGzNCG1ErrNMe0ytUc2T9XtVOM19qR0qzp9Q/89luSmPbfrusmqTFvtBPoxK8yQTtkohmvUM4aZxnOXjRlfhuVH3Gu15cGAbDvHud9ttMe35+qR9PbOuNtigqthEP+4eT4VrI0taWqf/RCVaghPuDldi6+4rzgh0zr6m6Yi9d54OXPlBV9BSkrBpWjp32OgupM5QCbLCIcfwYZtx7TreJHV2ouMcOVdK86PMxEZHyBlP8B2Ik25ViezaID1adyc4lWxJwfUri2W8O+RRhQziuKqe2T1nqSNm3xwze2HdTCuFRrTEyPhyPtdpqPgCXa6919Z8zRXgG73/Gb2DU+vcyBA6PolH94DuGf43Pv/ffO6tKbBA2o6VBDphCHRwe9OoieX7wd5V4Hemr2Zo/0KwQ7wk4rEUWOb3WRCCaPNwsR2kH2/GYa5oM7dBfTuoFtwiPksjF5jz4/ByBBEwkPro3XbcDvtAYT3lMuRU2D4SqO9Ip+9ChyFcP+fpv75E1ScnfKJOkUltwobrMnZSh3ZzXQo0heBOIuDFjP9Zr2fS47XLqoo/35foVnXIH6TTchZWTN4tlygVb823a7jDFYcqTbFgow8yK8N6e1hufDHbcc2rZQSySdcBPcH6dlk2qz3b63UtMeb9t6og2oAI+zBUk6qq/gJUqQ7w
api: eJztV1tv4kYU/iujeWolAwYM2fiptJvsstpto5QoUiOEBs8BZmPPODPHSSjyf6/OGAjGpI3UrdSHfcI25/LN+c5tNtzkYAUqo8eSx/wD4KiQCi+ec2ORB1yCS6zKSYDH/BqwsNoxkaZMkBxLzZKBRqvAsSeFK1Mgy8VSaW+TLYxl4G21ecBRLB2P77h3MftslrPR1XjmDfFpwB0khVW45vHdhv8MwoIdFbgiDS8TWxCST8tpwC243GgHjscb3gtD+qlDHe0hbuERgMRoBI0kLfI8VYlH2fnqSGXDXbKCTNATrnPgMTfzr5BQGHJLcUJVOUSDIp0phMwdCCuNsATbCNqEpJkusjlYZhZNVPAssjwFHncHYRnwY7vCWrHmze+vgFPyQMahVXrJA74wNhPIY14USjYg3mj1UABTEjSqhQLricMVHIBd16DywSCEd1EYtqB3Pm9FXRm1xFl32Iqi4XAwiKIwDENeBhxVBg5Flv8tKikQWiTagHa7Au2RWHgowCF7Eo7l1iTgHMg6pl7YG7bCXqvXnXTDuB/GYfgHYSgc2FPujzKmwBWdPxEIkpEO++HT7YS5wgf6x7ovk7uftm/txGTkxpoU3kLc1n/ZqC7SZwtrMn9g8o3mHnTN8R0XMlOaT8uAZ4Arc5LuuuGPk8kVq4Trh/hwMSEYuaAq+ycr11sCbq4/M9Kom+poI6GzMg61yICs7jvL7HRK1q3/loMeXY3ZXouN3x+BBfzVSPh44MKZwiYwUyeTq27/l1SBRja+YkJKC65eebx73mt3h+/a3Xa3yttdh5klRsIbqtzHeKfEHAosHCPdmp9eSBUui21gXukf+7JQGofRq0TszDClWabSVDlIjJb1k0U9KkIrKExvpGECKWSAds28Hhu/9+0gMdZC6j3WYxfNF+e9RX9wdjbvR1IMRT+B8965DCGE6Kw/5KWP50OhLEjKYN+BXhrDtkB3BbTP621iHtJ8zEs9llOyih5TNcWobTXrbFLrazS5qm6nHI0uaDfwHvb7XTkf+PqsXDU1r7fYeFmSiSjsNufSjRYFroxVf4JkLUYpfw9rtnP3DacUWGve0vbYwTvNJ+o9XpfhSiAzSVJYe9xqL4VKQTI0zALF8HGX8+0q3ihUeqLnNZxLqehRpGyrw8Scdog9iJNuZQHkWgM+GXvPKJVMgd71G8t1sj9ko0YHYViWL+xekFSD2X6T2Utj50pK0KzFxtoVi4VKfM/JwWbKOWX0t1xCvtP7n9E7OLVQjjWCpZM4sI9gX+B/5/P/zefBosSXgLuxEvOOHwId2N11KmLphnJwGfmd6KsYOryS7BGvEGkseZbpfe6FeLB9uNyN8k+3Ez9XlF4Yr74bVEtqEV+EFkvI6HF0NeYBJyDV0bvtsO03ktw4zITPKb//xLy6pZ2+jR2HcPOSp//6GledHOEZO3kqlPY7tk3JSRXa7YXN0+SDOw04rYb0z2YzFw5ubFqW9PmhALuuQv4orBJzv+TSdrsCIWlvv9vwe1hTqJIEcjL6KNLCL9jH5UZXwz3XtNwGXNTpOqLHW9+t63p9YHuzqSQmtIGXJQ+2IPxGzstpWZZ/AVrrOZ0=
sidebar_class_name: "get api-method"
info_path: gen/api/agent-management-api
custom_edit_url: null
Expand Down Expand Up @@ -242,6 +242,15 @@ Returns all audit log entries without pagination for export.
schema={{"type":"integer","format":"int64","description":"Request duration in milliseconds.","example":42}}
>

</SchemaItem><SchemaItem
collapsible={false}
name={"trace_id"}
required={false}
schemaName={"string"}
qualifierMessage={undefined}
schema={{"type":"string","description":"OpenTelemetry trace ID for correlation.","example":"4bf92f3577b34da6a3ce929d0e0e4736"}}
>

</SchemaItem><li>
<div
style={{"fontSize":"var(--ifm-code-font-size)","opacity":"0.6","marginLeft":"-.5rem"}}
Expand All @@ -259,7 +268,7 @@ Returns all audit log entries without pagination for export.
value={"Example (from schema)"}
>
<ResponseSamples
responseExample={"{\n \"total_items\": 150,\n \"items\": [\n {\n \"id\": \"550e8400-e29b-41d4-a716-446655440000\",\n \"timestamp\": \"2026-02-21T10:30:00Z\",\n \"user\": \"ops@example.com\",\n \"roles\": [\n \"admin\"\n ],\n \"method\": \"GET\",\n \"path\": \"/node/hostname\",\n \"operation_id\": \"GetNodeHostname\",\n \"source_ip\": \"192.168.1.100\",\n \"response_code\": 200,\n \"duration_ms\": 42\n }\n ]\n}"}
responseExample={"{\n \"total_items\": 150,\n \"items\": [\n {\n \"id\": \"550e8400-e29b-41d4-a716-446655440000\",\n \"timestamp\": \"2026-02-21T10:30:00Z\",\n \"user\": \"ops@example.com\",\n \"roles\": [\n \"admin\"\n ],\n \"method\": \"GET\",\n \"path\": \"/node/hostname\",\n \"operation_id\": \"GetNodeHostname\",\n \"source_ip\": \"192.168.1.100\",\n \"response_code\": 200,\n \"duration_ms\": 42,\n \"trace_id\": \"4bf92f3577b34da6a3ce929d0e0e4736\"\n }\n ]\n}"}
language={"json"}
>

Expand Down
13 changes: 11 additions & 2 deletions docs/docs/gen/api/get-audit-log-by-id.api.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ description: "Returns a single audit log entry by ID."
sidebar_label: "Get a single audit log entry"
hide_title: true
hide_table_of_contents: true
api: eJztV21v20YM/isHfmoB2ZFdJ2v1ae6atC66LcgcBFgQBGcdbV8j3al3VFrP0H8feJJfZDtJB3TABuSTJZsvD/mQNLkEW6CTpK0ZKUjgPdKwVJo+2dnbxegdRKDQp04XLAEJXCCVznghhddmlqGQLC0yOxNoyC3EZCFG77oQAcmZh+QagrnbT3Z2Ozwf3QZxuInAY1o6TQtIrpfwFqVDNyxpzhpBJnEoFdxUNxEU0skcCZ0PwkbmCAloBRFoxlRImkMEDr+U2qGChFyJEfh0jrmEZAm0KFjDk9NmBhFMrcslQQJlqRVUuzGO56uw6pA4Hsbh0BfWePRssx/H/NHWHG5pTW1pFCcitYbQEEvLosh0GrJ99NmzynIfpp18xpQggsIxN6Rrh8Hq02JaPR3xbsCXRn8pUWiFhvRUoxNT6wS108Ch4DeZFxlbPj6O8fUgjjvYfzPpDHpq0JE/9U46g8HJyfHxYBDHccyZJZ2jJ5kXj6JSkrDDonvQruZoAhJmFz2Jr9KLwtkUvUfVxtSP+yeduN/p98a9OHkVJ3H8J2MoPbpD7ne5oznHn0pCJVhHvPh4NRa+DIl+2fZlC/9z89ZNbc5unM1qCho/0jm54BolzP2+/72yu2B9MXU2DwGzb7J3aFqOr0GqXBu4qSLIkeb2IN1twx/G43NRC7eDeH86Zhihf560ctEQcHnxSbBG29SRsQqP5tZTaM8q2syV28Ml2bb+e4FmeD4Sa61mimyBRfrNKvyw5cLb0qV4qw8WV9v+L5lGQ2J0LqRSDr1vG++96Xd7J6+7vW6vrttVr9+mVuGWeW0IZ+gO53ilJDxJKr1g3Zaffhwz7WWTmFZZbCyv20IbOhk8SMTKjNBG5DrLtMfUGtWObNCvqu3ReF3PzU1bNu2xKt91VUWrsbpJ8m5W2pHcsFUK2Qxj8DTMq13v9RQ7KHvRGIeqYq1B3NsfsJdGljS3Tv+FSnQEV8wdLsTKw48ct87Z75kaYutd2Glo3aAraC5J2DQtndudVGdSZ6gEWeGQnMb7Vcl067FAUmcHRsaec6U0P8pMNDpCTmxJGxAH3aoS2bVB+mrdneBasCUF199Z7eN1kHslfhzHVbWh95Sl9ph9tc/smXUTrRQa0REj48vpVKehZQt0ufZeW+Of6f1/0Dt4fDMyln78dvTM57/F5/GhTXdkCB1H4tHdo9vAf+bzv83n1t4IM6TV/3wCR2HXP1pqVfG/fqCVD66tW+0PJq/mZ/tiW+OdE/GWEDjm90kQgqh5OFvtNR+vxmEx0GZqg/pqF5jxwP9VGjnDnB+H5yOIgIHUgfe6cTesZ4X1lMtQUc05+B7pwaN0N4HLTZX+k4O2DpLwGx0VmdQm3BYuY3t1DpvTFSJItOIlh/dh/nq5nEiPly6rKv76S4l8ynFq76XTchI2+yUo7flZQTKVmcdHUL+4aDael+LQtfoA2NVhYjgj9zIr+Q0iuMNFfVBXfFbMUSo+mK6XzQ/DNMWCtlT2Gpuv43VV8VURgWyXxk4pBOsH4SyXtcSYT5+qWqMLpxADrKq/AUdatiw=
api: eJztV9tu20YQ/ZXFPDUAJVMyJcd8qtLcFKSt4coIUMMwVtyRtDG5y+wOnagC/72YpW6UlEuBFGiBPImU5n5mjmZWYEt0krQ1YwUpvEIaVUrTWzt/thw/hwgU+szpkiUghWukyhkvpPDazHMUkqVFbucCDbmlmC7F+HkXIiA595DeQjB3/9bO70dX4/sgDncReMwqp2kJ6e0KnqF06EYVLVgjyKQOpYK7+i6CUjpZIKHzQdjIAiEFrSACzTGVkhYQgcMPlXaoICVXYQQ+W2AhIV0BLUvW8OS0mUMEM+sKSZBCVWkF9WGOk8UmrSYlzofjcOhLazx6ttmPY/5oa472tGa2MooLkVlDaIilZVnmOgvVPnvvWWV1HKadvseMIILSMTakG4fB6tfFtPp6xocJ3xj9oUKhFRrSM41OzKwT1C4Dp4KfZFHmbHkwiPFpEscd7F9OO0lPJR150Rt2kmQ4HAySJI7jmCtLukBPsii/GJWShB0WPQrt3QJNiITRRU/io/SidDZD71G1Y+rH/WEn7nf6vUkvTs/jNI7/5Bgqj+6U+0PsaMH5Z5JQCdYRP715NxG+CoV+0vZlS//z+q2b2YLdOJs3EKz9SOfkknuUsPDH/o/a7pr1xczZIiTMvsk+oGk5vgWpCm3gro6gQFrYk3C3Db+eTK5EI9xO4tWLCYcR5uerVq7XANxcvxWs0TZ1ZqzCs4X1FMazjna8cn+6JdvWfy/RjK7GYqu1ZpG9YJF+swpf77nwtnIZ3uuTzdW2/0uu0ZAYXwmplEPv28Z7l/1ub/i02+v2mr7dzPp9ZhXumdeGcI7udI03SsKTpMoL1m356ccxw16tC9Nqi53l7VhoQ8Pks0BszAhtRKHzXHvMrFHtzJI+D6GTXKZvhGGCORbIFBb0xPh5oIPMOod58NiuXTKdXfZn54OLi+l5ouRQnmd42b9UMcaYXJwPoa73yfm2Ye4dMawHdDNA276ONsS+g/kQl3Yt79gqhZgCEb8IjHnoveHRk7LXa+NQ16yVxL1jir8xsqKFdfovVKIjuGcfcCk2Hr4n4Ttnv4W3xN67sLNAHkFX0EKSsFlWOXfIlS+lzlEJssIhOY2Pm6btNsREUucnSOvIuVKaH2Uu1jpCTm1FuyBOulUVsmuD9NG6B8G9YCsKrr9x3ibbJI+GbBDHdb2D9wVLHSF7fozsS+umWik0oiPGxlezmc4CaZToCu29tsb/gPf/AW/y5d3MWPr++9kPPP8tPAendu2xIXSciUf3iG4X/g88/9t47m2uMEfa/M+ncBaujbOVVjX/6wdY+eTbuxb/YPAafPZvxm28CyLeEgLG/D4NQhCtH15uNqs37yZhMdBmZoP6ZheYM+H/Ko2cY8GPo6sxRMCBNIn3unE3LIil9VTI0FHrg/QV0mfP4sMCrnZd+k9O6iZJwk90VuZSm3DduJztNTVcH88QQaoVLzm8kfPXq9VUerxxeV3z1x8q5GOSS/sonZbTcFusQGnPzwrSmcw9fiHqn67XG88Tcepe/kywm9PIcEUeZV7xG0TwgMvmpK/5sFmgVHyy3a7WP4yyDEvaUzkabL7Pt13Fd00Est0aB60QrJ8MZ7VqJCZ8fNX1NrpwjHGAdf030A3g2Q==
sidebar_class_name: "get api-method"
info_path: gen/api/agent-management-api
custom_edit_url: null
Expand Down Expand Up @@ -251,6 +251,15 @@ Returns a single audit log entry by ID.
schema={{"type":"integer","format":"int64","description":"Request duration in milliseconds.","example":42}}
>

</SchemaItem><SchemaItem
collapsible={false}
name={"trace_id"}
required={false}
schemaName={"string"}
qualifierMessage={undefined}
schema={{"type":"string","description":"OpenTelemetry trace ID for correlation.","example":"4bf92f3577b34da6a3ce929d0e0e4736"}}
>

</SchemaItem>
</div>
</details>
Expand All @@ -262,7 +271,7 @@ Returns a single audit log entry by ID.
value={"Example (from schema)"}
>
<ResponseSamples
responseExample={"{\n \"entry\": {\n \"id\": \"550e8400-e29b-41d4-a716-446655440000\",\n \"timestamp\": \"2026-02-21T10:30:00Z\",\n \"user\": \"ops@example.com\",\n \"roles\": [\n \"admin\"\n ],\n \"method\": \"GET\",\n \"path\": \"/node/hostname\",\n \"operation_id\": \"GetNodeHostname\",\n \"source_ip\": \"192.168.1.100\",\n \"response_code\": 200,\n \"duration_ms\": 42\n }\n}"}
responseExample={"{\n \"entry\": {\n \"id\": \"550e8400-e29b-41d4-a716-446655440000\",\n \"timestamp\": \"2026-02-21T10:30:00Z\",\n \"user\": \"ops@example.com\",\n \"roles\": [\n \"admin\"\n ],\n \"method\": \"GET\",\n \"path\": \"/node/hostname\",\n \"operation_id\": \"GetNodeHostname\",\n \"source_ip\": \"192.168.1.100\",\n \"response_code\": 200,\n \"duration_ms\": 42,\n \"trace_id\": \"4bf92f3577b34da6a3ce929d0e0e4736\"\n }\n}"}
language={"json"}
>

Expand Down
Loading
Loading