mirror of
https://github.com/gravitational/teleport.git
synced 2026-09-24 16:17:11 +08:00
GitHub proxy: emit rbac failure event and add prometheus counters (#51878)
* GitHub proxy: emit rbac failure event and add prometheus counters * move device metadata to sshca.identity
This commit is contained in:
@@ -377,7 +377,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(),
|
||||
|
||||
+1
-17
@@ -1066,22 +1066,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 != "" {
|
||||
@@ -1093,7 +1077,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,
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}()
|
||||
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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{
|
||||
|
||||
Reference in New Issue
Block a user