Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[v15] Include k8s metadata in port-forward event #49897

Merged
merged 1 commit into from
Dec 6, 2024
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
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 @@ -1743,10 +1743,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 @@ -1762,6 +1764,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 @@ -1770,6 +1777,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
Loading