diff --git a/lib/events/codes.go b/lib/events/codes.go index 5770c2bb49b78..fa3158df0b72f 100644 --- a/lib/events/codes.go +++ b/lib/events/codes.go @@ -282,6 +282,8 @@ const ( // Note: some requests (like exec into a pod) use other codes (like // ExecCode). KubeRequestCode = "T3009I" + // SCPDisallowedCode is the SCP disallowed event code. + SCPDisallowedCode = "T3010E" // KubernetesClusterCreateCode is the kube.create event code. KubernetesClusterCreateCode = "T3010I" @@ -329,6 +331,7 @@ const ( SFTPSymlinkFailureCode = "TS018E" SFTPLinkCode = "TS019I" SFTPLinkFailureCode = "TS019E" + SFTPDisallowedCode = "TS020E" // SessionCommandCode is a session command code. SessionCommandCode = "T4000I" diff --git a/lib/srv/exec.go b/lib/srv/exec.go index 56496682419a6..abc95f8643b8f 100644 --- a/lib/srv/exec.go +++ b/lib/srv/exec.go @@ -261,6 +261,16 @@ func (e *localExec) String() string { func (e *localExec) transformSecureCopy() error { isSCPCmd, err := checkSCPAllowed(e.Ctx, e.GetCommand()) if err != nil { + e.Ctx.GetServer().EmitAuditEvent(context.WithoutCancel(e.Ctx.Context), &apievents.SFTP{ + Metadata: apievents.Metadata{ + Code: events.SCPDisallowedCode, + Type: events.SCPEvent, + Time: time.Now(), + }, + UserMetadata: e.Ctx.Identity.GetUserMetadata(), + ServerMetadata: e.Ctx.GetServerMetadata(), + Error: err.Error(), + }) return trace.Wrap(err) } if !isSCPCmd { @@ -356,6 +366,16 @@ func (e *remoteExec) SetCommand(command string) { // ExecResult is only used to communicate an error while launching. func (e *remoteExec) Start(ctx context.Context, ch ssh.Channel) (*ExecResult, error) { if _, err := checkSCPAllowed(e.ctx, e.GetCommand()); err != nil { + e.ctx.GetServer().EmitAuditEvent(context.WithoutCancel(ctx), &apievents.SFTP{ + Metadata: apievents.Metadata{ + Code: events.SCPDisallowedCode, + Type: events.SCPEvent, + Time: time.Now(), + }, + UserMetadata: e.ctx.Identity.GetUserMetadata(), + ServerMetadata: e.ctx.GetServerMetadata(), + Error: err.Error(), + }) return nil, trace.Wrap(err) } diff --git a/lib/srv/forward/sshserver.go b/lib/srv/forward/sshserver.go index 8de88aad84757..8638e3b362566 100644 --- a/lib/srv/forward/sshserver.go +++ b/lib/srv/forward/sshserver.go @@ -27,6 +27,7 @@ import ( "strconv" "strings" "sync" + "time" "github.com/google/uuid" "github.com/gravitational/trace" @@ -1369,7 +1370,18 @@ func (s *Server) handleSubsystem(ctx context.Context, ch ssh.Channel, req *ssh.R // if SFTP was requested, check that if subsystem.subsytemName == teleport.SFTPSubsystem { - if err := serverContext.CheckSFTPAllowed(s.sessionRegistry); err != nil { + err := serverContext.CheckSFTPAllowed(s.sessionRegistry) + if err != nil { + s.EmitAuditEvent(context.WithoutCancel(ctx), &apievents.SFTP{ + Metadata: apievents.Metadata{ + Code: events.SFTPDisallowedCode, + Type: events.SFTPEvent, + Time: time.Now(), + }, + UserMetadata: serverContext.Identity.GetUserMetadata(), + ServerMetadata: serverContext.GetServerMetadata(), + Error: err.Error(), + }) return trace.Wrap(err) } } diff --git a/lib/srv/regular/sftp.go b/lib/srv/regular/sftp.go index 5382612c67c49..99ec9f6143e6a 100644 --- a/lib/srv/regular/sftp.go +++ b/lib/srv/regular/sftp.go @@ -25,6 +25,7 @@ import ( "io" "os" "os/exec" + "time" "github.com/gogo/protobuf/jsonpb" "github.com/gravitational/trace" @@ -33,6 +34,7 @@ import ( "github.com/gravitational/teleport" apievents "github.com/gravitational/teleport/api/types/events" + "github.com/gravitational/teleport/lib/events" "github.com/gravitational/teleport/lib/srv" "github.com/gravitational/teleport/lib/utils" ) @@ -66,6 +68,16 @@ func (s *sftpSubsys) Start(ctx context.Context, // this connection was proxied, the proxy doesn't know if file copying // is allowed for certain Nodes. if !serverCtx.AllowFileCopying { + serverCtx.GetServer().EmitAuditEvent(context.WithoutCancel(ctx), &apievents.SFTP{ + Metadata: apievents.Metadata{ + Code: events.SFTPDisallowedCode, + Type: events.SFTPEvent, + Time: time.Now(), + }, + UserMetadata: serverCtx.Identity.GetUserMetadata(), + ServerMetadata: serverCtx.GetServerMetadata(), + Error: srv.ErrNodeFileCopyingNotPermitted.Error(), + }) return srv.ErrNodeFileCopyingNotPermitted } diff --git a/lib/srv/regular/sshserver.go b/lib/srv/regular/sshserver.go index 4ef41c2467709..e6f35a4d05435 100644 --- a/lib/srv/regular/sshserver.go +++ b/lib/srv/regular/sshserver.go @@ -2154,7 +2154,18 @@ func (s *Server) parseSubsystemRequest(req *ssh.Request, ctx *srv.ServerContext) case r.Name == teleport.GetHomeDirSubsystem: return newHomeDirSubsys(), nil case r.Name == teleport.SFTPSubsystem: - if err := ctx.CheckSFTPAllowed(s.reg); err != nil { + err := ctx.CheckSFTPAllowed(s.reg) + if err != nil { + s.EmitAuditEvent(context.Background(), &apievents.SFTP{ + Metadata: apievents.Metadata{ + Code: events.SFTPDisallowedCode, + Type: events.SFTPEvent, + Time: time.Now(), + }, + UserMetadata: ctx.Identity.GetUserMetadata(), + ServerMetadata: ctx.GetServerMetadata(), + Error: err.Error(), + }) return nil, trace.Wrap(err) } diff --git a/web/packages/teleport/src/Audit/EventList/EventTypeCell.tsx b/web/packages/teleport/src/Audit/EventList/EventTypeCell.tsx index b2508d7c3dc67..8417e3ec0883a 100644 --- a/web/packages/teleport/src/Audit/EventList/EventTypeCell.tsx +++ b/web/packages/teleport/src/Audit/EventList/EventTypeCell.tsx @@ -47,6 +47,7 @@ const EventIconMap: Record = { [eventCodes.SCP_DOWNLOAD]: Icons.Download, [eventCodes.SCP_UPLOAD_FAILURE]: Icons.Upload, [eventCodes.SCP_UPLOAD]: Icons.Upload, + [eventCodes.SCP_DISALLOWED]: Icons.FolderPlus, [eventCodes.SFTP_OPEN_FAILURE]: Icons.FolderPlus, [eventCodes.SFTP_OPEN]: Icons.FolderPlus, [eventCodes.SFTP_CLOSE_FAILURE]: Icons.FolderPlus, @@ -83,6 +84,9 @@ const EventIconMap: Record = { [eventCodes.SFTP_READLINK]: Icons.FolderPlus, [eventCodes.SFTP_SYMLINK_FAILURE]: Icons.FolderPlus, [eventCodes.SFTP_SYMLINK]: Icons.FolderPlus, + [eventCodes.SFTP_LINK]: Icons.FolderPlus, + [eventCodes.SFTP_LINK_FAILURE]: Icons.FolderPlus, + [eventCodes.SFTP_DISALLOWED]: Icons.FolderPlus, [eventCodes.APP_SESSION_CHUNK]: Icons.Info, [eventCodes.APP_SESSION_START]: Icons.Info, [eventCodes.APP_SESSION_END]: Icons.Info, diff --git a/web/packages/teleport/src/services/audit/makeEvent.ts b/web/packages/teleport/src/services/audit/makeEvent.ts index 0a4029f224265..2f9adc78d50c4 100644 --- a/web/packages/teleport/src/services/audit/makeEvent.ts +++ b/web/packages/teleport/src/services/audit/makeEvent.ts @@ -281,6 +281,14 @@ export const formatters: Formatters = { rest['server_hostname'] || rest['addr.local'] }] failed [${exitError}]`, }, + [eventCodes.SCP_DISALLOWED]: { + type: 'scp', + desc: 'SCP Disallowed', + format: ({ user, ...rest }) => + `User [${user}] SCP file transfer on node [${ + rest['server_hostname'] || rest['addr.local'] + }] blocked`, + }, [eventCodes.SFTP_OPEN]: { type: 'sftp', desc: 'SFTP Open', @@ -569,6 +577,30 @@ export const formatters: Formatters = { rest['server_hostname'] || rest['addr.local'] }]: [${error}]`, }, + [eventCodes.SFTP_LINK]: { + type: 'sftp', + desc: 'SFTP Link', + format: ({ user, path, ...rest }) => + `User [${user}] created hard link [${path}] on node [${ + rest['server_hostname'] || rest['addr.local'] + }]`, + }, + [eventCodes.SFTP_LINK_FAILURE]: { + type: 'sftp', + desc: 'SFTP Link Failed', + format: ({ user, path, error, ...rest }) => + `User [${user}] failed to create hard link [${path}] on node [${ + rest['server_hostname'] || rest['addr.local'] + }]: [${error}]`, + }, + [eventCodes.SFTP_DISALLOWED]: { + type: 'sftp', + desc: 'SFTP Disallowed', + format: ({ user, ...rest }) => + `User [${user}] was blocked from creating an SFTP session on node [${ + rest['server_hostname'] || rest['addr.local'] + }]`, + }, [eventCodes.SESSION_JOIN]: { type: 'session.join', desc: 'User Joined', diff --git a/web/packages/teleport/src/services/audit/types.ts b/web/packages/teleport/src/services/audit/types.ts index 82f62634954a7..277685b689459 100644 --- a/web/packages/teleport/src/services/audit/types.ts +++ b/web/packages/teleport/src/services/audit/types.ts @@ -152,6 +152,7 @@ export const eventCodes = { SCP_DOWNLOAD: 'T3004I', SCP_UPLOAD_FAILURE: 'T3005E', SCP_UPLOAD: 'T3005I', + SCP_DISALLOWED: 'T3010E', SFTP_OPEN_FAILURE: 'TS001E', SFTP_OPEN: 'TS001I', SFTP_CLOSE_FAILURE: 'TS002E', @@ -188,6 +189,9 @@ export const eventCodes = { SFTP_READLINK: 'TS017I', SFTP_SYMLINK_FAILURE: 'TS018E', SFTP_SYMLINK: 'TS018I', + SFTP_LINK: 'TS019I', + SFTP_LINK_FAILURE: 'TS019E', + SFTP_DISALLOWED: 'TS020E', SESSION_COMMAND: 'T4000I', SESSION_DATA: 'T2006I', SESSION_DISK: 'T4001I', @@ -402,6 +406,12 @@ export type RawEvents = { exitError: string; } >; + [eventCodes.SCP_DISALLOWED]: RawEvent< + typeof eventCodes.SCP_DISALLOWED, + { + user: string; + } + >; [eventCodes.SFTP_OPEN]: RawEventSFTP; [eventCodes.SFTP_OPEN_FAILURE]: RawEventSFTP< typeof eventCodes.SFTP_OPEN_FAILURE @@ -474,6 +484,11 @@ export type RawEvents = { [eventCodes.SFTP_SYMLINK_FAILURE]: RawEventSFTP< typeof eventCodes.SFTP_SYMLINK_FAILURE >; + [eventCodes.SFTP_LINK]: RawEventSFTP; + [eventCodes.SFTP_LINK_FAILURE]: RawEventSFTP< + typeof eventCodes.SFTP_LINK_FAILURE + >; + [eventCodes.SFTP_DISALLOWED]: RawEventSFTP; [eventCodes.SESSION_COMMAND]: RawEventCommand< typeof eventCodes.SESSION_COMMAND >;