Skip to content

Commit

Permalink
Emit port-forward event only the first time, add port-forward-end eve…
Browse files Browse the repository at this point in the history
…nt. Include cluster and pod metadta in event. (#49897)
  • Loading branch information
creack authored Dec 6, 2024
1 parent c500727 commit f7ebb21
Show file tree
Hide file tree
Showing 8 changed files with 1,210 additions and 1,057 deletions.
15 changes: 15 additions & 0 deletions api/proto/teleport/legacy/types/events/events.proto
Original file line number Diff line number Diff line change
Expand Up @@ -1605,6 +1605,21 @@ message PortForward {

// Addr is a target port forwarding address
string Addr = 5 [(gogoproto.jsontag) = "addr"];

// KubernetesCluster has information about a kubernetes cluster, if
// applicable.
KubernetesClusterMetadata KubernetesCluster = 6 [
(gogoproto.nullable) = false,
(gogoproto.embed) = true,
(gogoproto.jsontag) = ""
];

// KubernetesPod has information about a kubernetes pod, if applicable.
KubernetesPodMetadata KubernetesPod = 7 [
(gogoproto.nullable) = false,
(gogoproto.embed) = true,
(gogoproto.jsontag) = ""
];
}

// X11Forward is emitted when a user requests X11 protocol forwarding
Expand Down
2,202 changes: 1,149 additions & 1,053 deletions api/types/events/events.pb.go

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions lib/events/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -773,21 +773,21 @@ const (

// IntegrationCreateEvent is emitted when an integration resource is created.
IntegrationCreateEvent = "integration.create"
//IntegrationUpdateEvent is emitted when an integration resource is updated.
// IntegrationUpdateEvent is emitted when an integration resource is updated.
IntegrationUpdateEvent = "integration.update"
// IntegrationDeleteEvent is emitted when an integration resource is deleted.
IntegrationDeleteEvent = "integration.delete"

// PluginCreateEvent is emitted when a plugin resource is created.
PluginCreateEvent = "plugin.create"
//PluginUpdateEvent is emitted when a plugin resource is updated.
// PluginUpdateEvent is emitted when a plugin resource is updated.
PluginUpdateEvent = "plugin.update"
// PluginDeleteEvent is emitted when a plugin resource is deleted.
PluginDeleteEvent = "plugin.delete"

// CrownJewelCreateEvent is emitted when a crown jewel resource is created.
CrownJewelCreateEvent = "access_graph.crown_jewel.create"
//CrownJewelUpdateEvent is emitted when a crown jewel resource is updated.
// CrownJewelUpdateEvent is emitted when a crown jewel resource is updated.
CrownJewelUpdateEvent = "access_graph.crown_jewel.update"
// CrownJewelDeleteEvent is emitted when a crown jewel resource is deleted.
CrownJewelDeleteEvent = "access_graph.crown_jewel.delete"
Expand Down
2 changes: 2 additions & 0 deletions lib/events/codes.go
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,8 @@ const (
ExecFailureCode = "T3002E"
// PortForwardCode is the port forward event code.
PortForwardCode = "T3003I"
// PortForwardStopCode is the port forward stop event code.
PortForwardStopCode = "T3003S"
// PortForwardFailureCode is the port forward failure event code.
PortForwardFailureCode = "T3003E"
// SCPDownloadCode is the file download event code.
Expand Down
34 changes: 33 additions & 1 deletion lib/kube/proxy/forwarder.go
Original file line number Diff line number Diff line change
Expand Up @@ -1744,10 +1744,12 @@ func (f *Forwarder) portForward(authCtx *authContext, w http.ResponseWriter, req
return nil, trace.Wrap(err)
}

auditSent := map[string]bool{} // Set of `addr`. Can be multiple ports on single call. Using bool to simplify the check.
onPortForward := func(addr string, success bool) {
if !sess.isLocalKubernetesCluster {
if !sess.isLocalKubernetesCluster || auditSent[addr] {
return
}
auditSent[addr] = true
portForward := &apievents.PortForward{
Metadata: apievents.Metadata{
Type: events.PortForwardEvent,
Expand All @@ -1763,6 +1765,11 @@ func (f *Forwarder) portForward(authCtx *authContext, w http.ResponseWriter, req
Status: apievents.Status{
Success: success,
},
KubernetesClusterMetadata: sess.eventClusterMeta(req),
KubernetesPodMetadata: apievents.KubernetesPodMetadata{
KubernetesPodNamespace: p.ByName("podNamespace"),
KubernetesPodName: p.ByName("podName"),
},
}
if !success {
portForward.Code = events.PortForwardFailureCode
Expand All @@ -1771,6 +1778,31 @@ func (f *Forwarder) portForward(authCtx *authContext, w http.ResponseWriter, req
f.log.WithError(err).Warn("Failed to emit event.")
}
}
defer func() {
for addr := range auditSent {
portForward := &apievents.PortForward{
Metadata: apievents.Metadata{
Type: events.PortForwardEvent,
Code: events.PortForwardStopCode,
},
UserMetadata: authCtx.eventUserMeta(),
ConnectionMetadata: apievents.ConnectionMetadata{
LocalAddr: sess.kubeAddress,
RemoteAddr: req.RemoteAddr,
Protocol: events.EventProtocolKube,
},
Addr: addr,
KubernetesClusterMetadata: sess.eventClusterMeta(req),
KubernetesPodMetadata: apievents.KubernetesPodMetadata{
KubernetesPodNamespace: p.ByName("podNamespace"),
KubernetesPodName: p.ByName("podName"),
},
}
if err := f.cfg.Emitter.EmitAuditEvent(f.ctx, portForward); err != nil {
f.log.WithError(err).Warn("Failed to emit event.")
}
}
}()

q := req.URL.Query()
request := portForwardRequest{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ const EventIconMap: Record<EventCode, any> = {
[eventCodes.CLIENT_DISCONNECT]: Icons.Info,
[eventCodes.PORTFORWARD]: Icons.Info,
[eventCodes.PORTFORWARD_FAILURE]: Icons.Info,
[eventCodes.PORTFORWARD_STOP]: Icons.Info,
[eventCodes.SUBSYSTEM]: Icons.Info,
[eventCodes.SUBSYSTEM_FAILURE]: Icons.Info,
[eventCodes.LOCK_CREATED]: Icons.Lock,
Expand Down
5 changes: 5 additions & 0 deletions web/packages/teleport/src/services/audit/makeEvent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,11 @@ export const formatters: Formatters = {
format: ({ user, error }) =>
`User [${user}] port forwarding request failed: ${error}`,
},
[eventCodes.PORTFORWARD_STOP]: {
type: 'port',
desc: 'Port Forwarding Stopped',
format: ({ user }) => `User [${user}] stopped port forwarding`,
},
[eventCodes.SAML_CONNECTOR_CREATED]: {
type: 'saml.created',
desc: 'SAML Connector Created',
Expand Down
2 changes: 2 additions & 0 deletions web/packages/teleport/src/services/audit/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ export const eventCodes = {
OIDC_CONNECTOR_DELETED: 'T8101I',
OIDC_CONNECTOR_UPDATED: 'T8102I',
PORTFORWARD_FAILURE: 'T3003E',
PORTFORWARD_STOP: 'T3003S',
PORTFORWARD: 'T3003I',
RECOVERY_TOKEN_CREATED: 'T6001I',
PRIVILEGE_TOKEN_CREATED: 'T6002I',
Expand Down Expand Up @@ -399,6 +400,7 @@ export type RawEvents = {
typeof eventCodes.OIDC_CONNECTOR_UPDATED
>;
[eventCodes.PORTFORWARD]: RawEvent<typeof eventCodes.PORTFORWARD>;
[eventCodes.PORTFORWARD_STOP]: RawEvent<typeof eventCodes.PORTFORWARD_STOP>;
[eventCodes.PORTFORWARD_FAILURE]: RawEvent<
typeof eventCodes.PORTFORWARD_FAILURE,
{
Expand Down

0 comments on commit f7ebb21

Please sign in to comment.