Add audit events for Classifier create and update (#67762)

* Add audit events for Classifier create and update

* Add failure codes for Classifier create and update audit events

* Add web UI and docs support for Classifier create and update audit events
This commit is contained in:
Ryan Clark
2026-06-16 19:26:07 +00:00
committed by GitHub
parent 1f6d537330
commit 543e9d3522
12 changed files with 2945 additions and 1526 deletions
@@ -5201,6 +5201,8 @@ message OneOf {
events.BeamsConfigCreate BeamsConfigCreate = 257;
events.BeamsConfigUpdate BeamsConfigUpdate = 258;
events.BeamsConfigDelete BeamsConfigDelete = 259;
events.ClassifierCreate ClassifierCreate = 260;
events.ClassifierUpdate ClassifierUpdate = 261;
}
}
@@ -10737,3 +10739,91 @@ message BeamsConfigDelete {
(gogoproto.jsontag) = ""
];
}
// ClassifierCreate is emitted when a classifier is created.
message ClassifierCreate {
// Metadata is a common event metadata
Metadata Metadata = 1 [
(gogoproto.nullable) = false,
(gogoproto.embed) = true,
(gogoproto.jsontag) = ""
];
// ResourceMetadata is a common resource event metadata
ResourceMetadata Resource = 2 [
(gogoproto.nullable) = false,
(gogoproto.embed) = true,
(gogoproto.jsontag) = ""
];
// User is a common user event metadata
UserMetadata User = 3 [
(gogoproto.nullable) = false,
(gogoproto.embed) = true,
(gogoproto.jsontag) = ""
];
// ConnectionMetadata holds information about the connection
ConnectionMetadata Connection = 4 [
(gogoproto.nullable) = false,
(gogoproto.embed) = true,
(gogoproto.jsontag) = ""
];
// Status indicates whether the creation was successful.
Status Status = 5 [
(gogoproto.nullable) = false,
(gogoproto.embed) = true,
(gogoproto.jsontag) = ""
];
// Payload contains the classifier data.
google.protobuf.Struct Payload = 6 [
(gogoproto.jsontag) = "payload,omitempty",
(gogoproto.casttype) = "Struct"
];
}
// ClassifierUpdate is emitted when a classifier is updated.
message ClassifierUpdate {
// Metadata is a common event metadata
Metadata Metadata = 1 [
(gogoproto.nullable) = false,
(gogoproto.embed) = true,
(gogoproto.jsontag) = ""
];
// ResourceMetadata is a common resource event metadata
ResourceMetadata Resource = 2 [
(gogoproto.nullable) = false,
(gogoproto.embed) = true,
(gogoproto.jsontag) = ""
];
// User is a common user event metadata
UserMetadata User = 3 [
(gogoproto.nullable) = false,
(gogoproto.embed) = true,
(gogoproto.jsontag) = ""
];
// ConnectionMetadata holds information about the connection
ConnectionMetadata Connection = 4 [
(gogoproto.nullable) = false,
(gogoproto.embed) = true,
(gogoproto.jsontag) = ""
];
// Status indicates whether the update was successful.
Status Status = 5 [
(gogoproto.nullable) = false,
(gogoproto.embed) = true,
(gogoproto.jsontag) = ""
];
// Payload contains the classifier data.
google.protobuf.Struct Payload = 6 [
(gogoproto.jsontag) = "payload,omitempty",
(gogoproto.casttype) = "Struct"
];
}
+8
View File
@@ -3038,3 +3038,11 @@ func (m *BeamsConfigUpdate) TrimToMaxSize(int) AuditEvent {
func (m *BeamsConfigDelete) TrimToMaxSize(int) AuditEvent {
return m
}
func (m *ClassifierCreate) TrimToMaxSize(_ int) AuditEvent {
return m
}
func (m *ClassifierUpdate) TrimToMaxSize(_ int) AuditEvent {
return m
}
+2538 -1526
View File
File diff suppressed because it is too large Load Diff
+8
View File
@@ -1056,6 +1056,14 @@ func ToOneOf(in AuditEvent) (*OneOf, error) {
out.Event = &OneOf_BeamsConfigDelete{
BeamsConfigDelete: e,
}
case *ClassifierCreate:
out.Event = &OneOf_ClassifierCreate{
ClassifierCreate: e,
}
case *ClassifierUpdate:
out.Event = &OneOf_ClassifierUpdate{
ClassifierUpdate: e,
}
default:
slog.ErrorContext(context.Background(), "Attempted to convert dynamic event of unknown type into protobuf event.", "event_type", in.GetType())
+154
View File
@@ -1666,6 +1666,160 @@ Example:
}
```
## classifier.create
There are multiple events with the `classifier.create` type.
### INF014I
Classifier Created
Example:
```json
{
"addr.remote": "127.0.0.1:62460",
"cluster_name": "teleport.dev",
"code": "INF014I",
"ei": 0,
"event": "classifier.create",
"name": "my-classifier",
"success": true,
"time": "2025-03-04T16:01:21.869Z",
"uid": "ae973df2-4bee-4a67-9925-575c1d38cc80",
"user": "08fcd522-edcb-492d-8752-90494a28b70e.teleport.dev",
"user_cluster_name": "teleport.dev",
"user_kind": 3,
"user_roles": [
"Admin"
],
"payload": {
"metadata": {
"name": "my-classifier"
},
"spec": {
"kinds": [
"ssh",
"k8s"
],
"resource_labels": [
{
"name": "env",
"values": [
"prod"
]
}
],
"v1": {}
}
}
}
```
### INF014E
Classifier Creation Failed
Example:
```json
{
"addr.remote": "127.0.0.1:62460",
"cluster_name": "teleport.dev",
"code": "INF014E",
"ei": 0,
"event": "classifier.create",
"name": "my-classifier",
"error": "classifier \"my-classifier\" already exists",
"success": false,
"time": "2025-03-04T16:01:31.869Z",
"uid": "b1973df2-4bee-4a67-9925-575c1d38cc80",
"user": "08fcd522-edcb-492d-8752-90494a28b70e.teleport.dev",
"user_cluster_name": "teleport.dev",
"user_kind": 3,
"user_roles": [
"Admin"
]
}
```
## classifier.update
There are multiple events with the `classifier.update` type.
### INF015I
Classifier Updated
Example:
```json
{
"addr.remote": "127.0.0.1:62460",
"cluster_name": "teleport.dev",
"code": "INF015I",
"ei": 0,
"event": "classifier.update",
"name": "my-classifier",
"success": true,
"time": "2025-03-04T16:02:21.869Z",
"uid": "af973df2-4bee-4a67-9925-575c1d38cc80",
"user": "08fcd522-edcb-492d-8752-90494a28b70e.teleport.dev",
"user_cluster_name": "teleport.dev",
"user_kind": 3,
"user_roles": [
"Admin"
],
"payload": {
"metadata": {
"name": "my-classifier"
},
"spec": {
"kinds": [
"ssh"
],
"resource_labels": [
{
"name": "env",
"values": [
"prod",
"staging"
]
}
],
"v1": {}
}
}
}
```
### INF015E
Classifier Update Failed
Example:
```json
{
"addr.remote": "127.0.0.1:62460",
"cluster_name": "teleport.dev",
"code": "INF015E",
"ei": 0,
"event": "classifier.update",
"name": "my-classifier",
"error": "classifier \"my-classifier\" doesn't exist",
"success": false,
"time": "2025-03-04T16:02:31.869Z",
"uid": "b2973df2-4bee-4a67-9925-575c1d38cc80",
"user": "08fcd522-edcb-492d-8752-90494a28b70e.teleport.dev",
"user_cluster_name": "teleport.dev",
"user_kind": 3,
"user_roles": [
"Admin"
]
}
```
## client.disconnect
Client Disconnected
+5
View File
@@ -1038,6 +1038,11 @@ const (
// RetrievalModelDeleteEvent is emitted when a retrieval model resource is deleted.
RetrievalModelDeleteEvent = "retrieval_model.delete"
// ClassifierCreateEvent is emitted when a classifier resource is created.
ClassifierCreateEvent = "classifier.create"
// ClassifierUpdateEvent is emitted when a classifier resource is updated.
ClassifierUpdateEvent = "classifier.update"
// SessionSummarizedEvent is emitted when a session summary is created.
SessionSummarizedEvent = "session.summarized"
+9
View File
@@ -898,6 +898,15 @@ const (
// RetrievalModelDeleteCode is the retrieval model delete event code.
RetrievalModelDeleteCode = "INF013I"
// ClassifierCreateCode is the classifier create event code.
ClassifierCreateCode = "INF014I"
// ClassifierCreateFailureCode is the classifier create failure event code.
ClassifierCreateFailureCode = "INF014E"
// ClassifierUpdateCode is the classifier update event code.
ClassifierUpdateCode = "INF015I"
// ClassifierUpdateFailureCode is the classifier update failure event code.
ClassifierUpdateFailureCode = "INF015E"
// CertAuthOverrideCreateCode is the cert_auth_override create event code.
CertAuthOverrideCreateCode = "TCO01I"
// CertAuthOverrideUpdateCode is the cert_auth_override update event code.
+5
View File
@@ -634,6 +634,11 @@ func FromEventFields(fields EventFields) (events.AuditEvent, error) {
case RetrievalModelDeleteEvent:
e = &events.RetrievalModelDelete{}
case ClassifierCreateEvent:
e = &events.ClassifierCreate{}
case ClassifierUpdateEvent:
e = &events.ClassifierUpdate{}
case SessionSummarizedEvent:
e = &events.SessionSummarized{}
@@ -373,6 +373,10 @@ export const EventIconMap: Record<EventCode, any> = {
[eventCodes.RETRIEVAL_MODEL_CREATE]: Icons.Info,
[eventCodes.RETRIEVAL_MODEL_UPDATE]: Icons.Info,
[eventCodes.RETRIEVAL_MODEL_DELETE]: Icons.Info,
[eventCodes.CLASSIFIER_CREATE]: Icons.Info,
[eventCodes.CLASSIFIER_CREATE_FAILURE]: Icons.Warning,
[eventCodes.CLASSIFIER_UPDATE]: Icons.Info,
[eventCodes.CLASSIFIER_UPDATE_FAILURE]: Icons.Warning,
[eventCodes.SESSION_SUMMARIZED]: Icons.Info,
[eventCodes.SESSION_SUMMARIZED_FAILURE]: Icons.Warning,
[eventCodes.CERT_AUTH_OVERRIDE_CREATE]: Icons.Info,
@@ -4901,6 +4901,88 @@ export const events = [
user_kind: 3,
user_roles: ['Admin'],
},
{
'addr.remote': '127.0.0.1:62460',
cluster_name: 'teleport.dev',
code: 'INF014I',
ei: 0,
event: 'classifier.create',
name: 'my-classifier',
success: true,
time: '2025-03-04T16:01:21.869Z',
uid: 'ae973df2-4bee-4a67-9925-575c1d38cc80',
user: '08fcd522-edcb-492d-8752-90494a28b70e.teleport.dev',
user_cluster_name: 'teleport.dev',
user_kind: 3,
user_roles: ['Admin'],
payload: {
metadata: {
name: 'my-classifier',
},
spec: {
kinds: ['ssh', 'k8s'],
resource_labels: [{ name: 'env', values: ['prod'] }],
v1: {},
},
},
},
{
'addr.remote': '127.0.0.1:62460',
cluster_name: 'teleport.dev',
code: 'INF014E',
ei: 0,
event: 'classifier.create',
name: 'my-classifier',
error: 'classifier "my-classifier" already exists',
success: false,
time: '2025-03-04T16:01:31.869Z',
uid: 'b1973df2-4bee-4a67-9925-575c1d38cc80',
user: '08fcd522-edcb-492d-8752-90494a28b70e.teleport.dev',
user_cluster_name: 'teleport.dev',
user_kind: 3,
user_roles: ['Admin'],
},
{
'addr.remote': '127.0.0.1:62460',
cluster_name: 'teleport.dev',
code: 'INF015I',
ei: 0,
event: 'classifier.update',
name: 'my-classifier',
success: true,
time: '2025-03-04T16:02:21.869Z',
uid: 'af973df2-4bee-4a67-9925-575c1d38cc80',
user: '08fcd522-edcb-492d-8752-90494a28b70e.teleport.dev',
user_cluster_name: 'teleport.dev',
user_kind: 3,
user_roles: ['Admin'],
payload: {
metadata: {
name: 'my-classifier',
},
spec: {
kinds: ['ssh'],
resource_labels: [{ name: 'env', values: ['prod', 'staging'] }],
v1: {},
},
},
},
{
'addr.remote': '127.0.0.1:62460',
cluster_name: 'teleport.dev',
code: 'INF015E',
ei: 0,
event: 'classifier.update',
name: 'my-classifier',
error: 'classifier "my-classifier" doesn\'t exist',
success: false,
time: '2025-03-04T16:02:31.869Z',
uid: 'b2973df2-4bee-4a67-9925-575c1d38cc80',
user: '08fcd522-edcb-492d-8752-90494a28b70e.teleport.dev',
user_cluster_name: 'teleport.dev',
user_kind: 3,
user_roles: ['Admin'],
},
{
cluster_name: 'teleport.dev',
code: 'INF010I',
@@ -2647,6 +2647,28 @@ export const formatters: Formatters = {
format: ({ name, user }) =>
`Retrieval Model [${name}] was deleted by [${user}]`,
},
[eventCodes.CLASSIFIER_CREATE]: {
type: 'classifier.create',
desc: 'Classifier Created',
format: ({ name, user }) => `Classifier [${name}] was created by [${user}]`,
},
[eventCodes.CLASSIFIER_CREATE_FAILURE]: {
type: 'classifier.create',
desc: 'Classifier Creation Failed',
format: ({ name, user }) =>
`Classifier [${name}] failed to be created by [${user}]`,
},
[eventCodes.CLASSIFIER_UPDATE]: {
type: 'classifier.update',
desc: 'Classifier Updated',
format: ({ name, user }) => `Classifier [${name}] was updated by [${user}]`,
},
[eventCodes.CLASSIFIER_UPDATE_FAILURE]: {
type: 'classifier.update',
desc: 'Classifier Update Failed',
format: ({ name, user }) =>
`Classifier [${name}] failed to be updated by [${user}]`,
},
[eventCodes.SESSION_SUMMARIZED]: {
type: 'session.summarized',
desc: 'Session Summarized',
@@ -397,6 +397,10 @@ export const eventCodes = {
RETRIEVAL_MODEL_CREATE: 'INF011I',
RETRIEVAL_MODEL_UPDATE: 'INF012I',
RETRIEVAL_MODEL_DELETE: 'INF013I',
CLASSIFIER_CREATE: 'INF014I',
CLASSIFIER_CREATE_FAILURE: 'INF014E',
CLASSIFIER_UPDATE: 'INF015I',
CLASSIFIER_UPDATE_FAILURE: 'INF015E',
CERT_AUTH_OVERRIDE_CREATE: 'TCO01I',
CERT_AUTH_OVERRIDE_UPDATE: 'TCO02I',
CERT_AUTH_OVERRIDE_UPSERT: 'TCO03I',
@@ -2334,6 +2338,22 @@ export type RawEvents = {
typeof eventCodes.RETRIEVAL_MODEL_DELETE,
HasName
>;
[eventCodes.CLASSIFIER_CREATE]: RawEvent<
typeof eventCodes.CLASSIFIER_CREATE,
HasName
>;
[eventCodes.CLASSIFIER_CREATE_FAILURE]: RawEvent<
typeof eventCodes.CLASSIFIER_CREATE_FAILURE,
HasName
>;
[eventCodes.CLASSIFIER_UPDATE]: RawEvent<
typeof eventCodes.CLASSIFIER_UPDATE,
HasName
>;
[eventCodes.CLASSIFIER_UPDATE_FAILURE]: RawEvent<
typeof eventCodes.CLASSIFIER_UPDATE_FAILURE,
HasName
>;
[eventCodes.SESSION_SUMMARIZED]: RawEvent<
typeof eventCodes.SESSION_SUMMARIZED,
{