diff --git a/lib/srv/authhandlers.go b/lib/srv/authhandlers.go index 7c575ef2b463b..27fc0ca29eec7 100644 --- a/lib/srv/authhandlers.go +++ b/lib/srv/authhandlers.go @@ -367,7 +367,7 @@ func (h *AuthHandlers) UserKeyAuth(conn ssh.ConnMetadata, key ssh.PublicKey) (*s UserMetadata: apievents.UserMetadata{ Login: principal, User: ident.Username, - TrustedDevice: eventDeviceMetadataFromIdentity(ident), + TrustedDevice: ident.GetDeviceMetadata(), }, ConnectionMetadata: apievents.ConnectionMetadata{ LocalAddr: conn.LocalAddr().String(), diff --git a/lib/srv/ctx.go b/lib/srv/ctx.go index 5d0aacb94d4a5..c640aa9bdd014 100644 --- a/lib/srv/ctx.go +++ b/lib/srv/ctx.go @@ -1060,22 +1060,6 @@ func (c *ServerContext) ExecCommand() (*ExecCommand, error) { }, nil } -func eventDeviceMetadataFromIdentity(ident *sshca.Identity) *apievents.DeviceMetadata { - if ident == nil { - return nil - } - - if ident.DeviceID == "" && ident.DeviceAssetTag == "" && ident.DeviceCredentialID == "" { - return nil - } - - return &apievents.DeviceMetadata{ - DeviceId: ident.DeviceID, - AssetTag: ident.DeviceAssetTag, - CredentialId: ident.DeviceCredentialID, - } -} - func (id *IdentityContext) GetUserMetadata() apievents.UserMetadata { userKind := apievents.UserKind_USER_KIND_HUMAN if id.BotName != "" { @@ -1087,7 +1071,7 @@ func (id *IdentityContext) GetUserMetadata() apievents.UserMetadata { User: id.TeleportUser, Impersonator: id.Impersonator, AccessRequests: id.ActiveRequests, - TrustedDevice: eventDeviceMetadataFromIdentity(id.UnmappedIdentity), + TrustedDevice: id.UnmappedIdentity.GetDeviceMetadata(), UserKind: userKind, BotName: id.BotName, BotInstanceID: id.BotInstanceID, diff --git a/lib/srv/git/forward.go b/lib/srv/git/forward.go index e3c68fd7515e8..7fbed8cacec00 100644 --- a/lib/srv/git/forward.go +++ b/lib/srv/git/forward.go @@ -28,6 +28,7 @@ import ( "github.com/google/uuid" "github.com/gravitational/trace" "github.com/jonboulle/clockwork" + "github.com/prometheus/client_golang/prometheus" "golang.org/x/crypto/ssh" "github.com/gravitational/teleport" @@ -37,6 +38,7 @@ import ( "github.com/gravitational/teleport/lib/auth/authclient" "github.com/gravitational/teleport/lib/bpf" "github.com/gravitational/teleport/lib/events" + "github.com/gravitational/teleport/lib/observability/metrics" "github.com/gravitational/teleport/lib/service/servicecfg" "github.com/gravitational/teleport/lib/services" "github.com/gravitational/teleport/lib/srv" @@ -46,6 +48,38 @@ import ( logutils "github.com/gravitational/teleport/lib/utils/log" ) +var ( + execSessionCounter = prometheus.NewCounter(prometheus.CounterOpts{ + Namespace: teleport.MetricNamespace, + Subsystem: teleport.ComponentGit, + Name: "exec_sessions_total", + }) + + execFailureCounter = prometheus.NewCounter(prometheus.CounterOpts{ + Namespace: teleport.MetricNamespace, + Subsystem: teleport.ComponentGit, + Name: "exec_failures_total", + }) + + userKeyAuthFailureCounter = prometheus.NewCounter(prometheus.CounterOpts{ + Namespace: teleport.MetricNamespace, + Subsystem: teleport.ComponentGit, + Name: "userkeyauth_failures_total", + }) + + rbacFailureCounter = prometheus.NewCounter(prometheus.CounterOpts{ + Namespace: teleport.MetricNamespace, + Subsystem: teleport.ComponentGit, + Name: "rbac_failures_total", + }) + + forwardServerPrometheusCollectors = []prometheus.Collector{ + execSessionCounter, + userKeyAuthFailureCounter, + rbacFailureCounter, + } +) + // ForwardServerConfig is the configuration for the ForwardServer. type ForwardServerConfig struct { // ParentContext is a parent context, used to signal global @@ -172,6 +206,10 @@ func NewForwardServer(cfg *ForwardServerConfig) (*ForwardServer, error) { return nil, trace.Wrap(err) } + if err := metrics.RegisterPrometheusCollectors(forwardServerPrometheusCollectors...); err != nil { + return nil, trace.Wrap(err) + } + serverConn, clientConn, err := utils.DualPipeNetConn(cfg.SrcAddr, cfg.DstAddr) if err != nil { return nil, trace.Wrap(err) @@ -282,6 +320,7 @@ func (s *ForwardServer) userKeyAuth(conn ssh.ConnMetadata, key ssh.PublicKey) (* // Use auth.UserKeyAuth to verify user cert is signed by UserCA. permissions, err := s.auth.UserKeyAuth(conn, key) if err != nil { + userKeyAuthFailureCounter.Inc() return nil, trace.Wrap(err) } @@ -295,6 +334,26 @@ func (s *ForwardServer) userKeyAuth(conn ssh.ConnMetadata, key ssh.PublicKey) (* "fingerprint", sshutils.Fingerprint(key), "user", cert.KeyId, ) + rbacFailureCounter.Inc() + s.emitEvent(&apievents.AuthAttempt{ + Metadata: apievents.Metadata{ + Type: events.AuthAttemptEvent, + Code: events.AuthAttemptFailureCode, + }, + UserMetadata: apievents.UserMetadata{ + Login: gitUser, + User: ident.Username, + TrustedDevice: ident.GetDeviceMetadata(), + }, + ConnectionMetadata: apievents.ConnectionMetadata{ + LocalAddr: conn.LocalAddr().String(), + RemoteAddr: conn.RemoteAddr().String(), + }, + Status: apievents.Status{ + Success: false, + Error: err.Error(), + }, + }) return nil, trace.Wrap(err) } return permissions, nil @@ -445,7 +504,10 @@ func (s *ForwardServer) handleExec(ctx context.Context, sctx *sessionContext, re var r sshutils.ExecReq defer func() { if err != nil { + execFailureCounter.Inc() s.emitEvent(s.makeGitCommandEvent(sctx, r.Command, err)) + } else { + execSessionCounter.Inc() } }() diff --git a/lib/srv/git/forward_test.go b/lib/srv/git/forward_test.go index 4ea3566bd9744..a2d5a2471c255 100644 --- a/lib/srv/git/forward_test.go +++ b/lib/srv/git/forward_test.go @@ -136,6 +136,14 @@ func TestForwardServer(t *testing.T) { clientLogin: "git", verifyRemoteHost: ssh.InsecureIgnoreHostKey(), wantNewClientError: true, + verifyEvent: func(t *testing.T, event apievents.AuditEvent) { + authFailureEvent, ok := event.(*apievents.AuthAttempt) + require.True(t, ok) + assert.Equal(t, libevents.AuthAttemptEvent, authFailureEvent.Metadata.Type) + assert.Equal(t, libevents.AuthAttemptFailureCode, authFailureEvent.Metadata.Code) + assert.Equal(t, "alice", authFailureEvent.User) + assert.Contains(t, authFailureEvent.Error, "access denied") + }, }, { name: "failed client login check", diff --git a/lib/sshca/identity.go b/lib/sshca/identity.go index 54616691dd453..d9e189a7ae8f4 100644 --- a/lib/sshca/identity.go +++ b/lib/sshca/identity.go @@ -32,6 +32,7 @@ import ( "github.com/gravitational/teleport" "github.com/gravitational/teleport/api/constants" "github.com/gravitational/teleport/api/types" + apievents "github.com/gravitational/teleport/api/types/events" "github.com/gravitational/teleport/api/types/wrappers" "github.com/gravitational/teleport/api/utils/keys" "github.com/gravitational/teleport/lib/utils" @@ -306,6 +307,22 @@ func (i *Identity) Encode(certFormat string) (*ssh.Certificate, error) { return cert, nil } +// GetDeviceMetadata returns information about user's trusted device. +func (i *Identity) GetDeviceMetadata() *apievents.DeviceMetadata { + if i == nil { + return nil + } + if i.DeviceID == "" && i.DeviceAssetTag == "" && i.DeviceCredentialID == "" { + return nil + } + + return &apievents.DeviceMetadata{ + DeviceId: i.DeviceID, + AssetTag: i.DeviceAssetTag, + CredentialId: i.DeviceCredentialID, + } +} + // DecodeIdentity decodes an ssh certificate into an identity. func DecodeIdentity(cert *ssh.Certificate) (*Identity, error) { ident := &Identity{