Skip to content

Commit 64e28c6

Browse files
Created check for device trust after MFA before creating web session (#62019) (#63260)
1 parent c848217 commit 64e28c6

11 files changed

Lines changed: 1315 additions & 893 deletions

File tree

api/proto/teleport/legacy/types/events/events.proto

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2113,7 +2113,7 @@ message ClientDisconnect {
21132113
string Reason = 5 [(gogoproto.jsontag) = "reason"];
21142114
}
21152115

2116-
// AuthAttempt is emitted upon a failed or successfull authentication attempt.
2116+
// AuthAttempt is emitted upon a failed authentication attempt.
21172117
message AuthAttempt {
21182118
// Metadata is a common event metadata
21192119
Metadata Metadata = 1 [
@@ -2903,6 +2903,14 @@ message AppSessionStart {
29032903
(gogoproto.embed) = true,
29042904
(gogoproto.jsontag) = ""
29052905
];
2906+
2907+
// Error is an optional error message.
2908+
// Only present in failed start attempts.
2909+
string Error = 9 [(gogoproto.jsontag) = "error,omitempty"];
2910+
2911+
// UserMessage is an optional user-friendly error message.
2912+
// Only present in failed start attempts.
2913+
string UserMessage = 10 [(gogoproto.jsontag) = "message,omitempty"];
29062914
}
29072915

29082916
// AppSessionEnd is emitted when an application session ends.

api/types/events/events.pb.go

Lines changed: 952 additions & 859 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

integration/appaccess/appaccess_test.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -588,7 +588,6 @@ func testAuditEvents(p *Pack, t *testing.T) {
588588
AppPublicAddr: p.rootAppPublicAddr,
589589
AppName: p.rootAppName,
590590
},
591-
PublicAddr: p.rootAppPublicAddr,
592591
}
593592
return len(cmp.Diff(
594593
expectedEvent,

lib/auth/sessions.go

Lines changed: 75 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -427,8 +427,6 @@ type NewAppSessionRequest struct {
427427
AppURI string
428428
// AppTargetPort signifies that the session is made to a specific port of a multi-port TCP app.
429429
AppTargetPort int
430-
// Identity is the identity of the user.
431-
Identity tlsca.Identity
432430
// ClientAddr is a client (user's) address.
433431
ClientAddr string
434432

@@ -498,6 +496,8 @@ func (a *Server) CreateAppSession(ctx context.Context, req *proto.CreateAppSessi
498496
MFAVerified: verifiedMFADeviceID,
499497
AppName: req.AppName,
500498
AppURI: req.URI,
499+
BotName: identity.BotName,
500+
BotInstanceID: identity.BotInstanceID,
501501
DeviceExtensions: DeviceExtensions(identity.DeviceExtensions),
502502
})
503503
if err != nil {
@@ -543,6 +543,69 @@ func (a *Server) CreateAppSessionFromReq(ctx context.Context, req NewAppSessionR
543543
return nil, trace.Wrap(err)
544544
}
545545

546+
// Audit fields used for both success and failure
547+
sessionStartEvent := &apievents.AppSessionStart{
548+
Metadata: apievents.Metadata{
549+
Type: events.AppSessionStartEvent,
550+
ClusterName: req.ClusterName,
551+
},
552+
ServerMetadata: apievents.ServerMetadata{
553+
ServerVersion: teleport.Version,
554+
ServerID: a.ServerID,
555+
ServerNamespace: apidefaults.Namespace,
556+
},
557+
ConnectionMetadata: apievents.ConnectionMetadata{
558+
RemoteAddr: req.ClientAddr,
559+
},
560+
AppMetadata: apievents.AppMetadata{
561+
AppURI: req.AppURI,
562+
AppPublicAddr: req.PublicAddr,
563+
AppName: req.AppName,
564+
AppTargetPort: uint32(req.AppTargetPort),
565+
},
566+
}
567+
568+
// Enforce device trust early via the AccessChecker.
569+
if err = checker.CheckDeviceAccess(services.AccessState{
570+
DeviceVerified: dtauthz.IsTLSDeviceVerified((*tlsca.DeviceExtensions)(&req.DeviceExtensions)),
571+
EnableDeviceVerification: true,
572+
IsBot: req.BotName != "",
573+
}); err != nil {
574+
userKind := apievents.UserKind_USER_KIND_HUMAN
575+
if req.BotName != "" {
576+
userKind = apievents.UserKind_USER_KIND_BOT
577+
}
578+
579+
userMetadata := apievents.UserMetadata{
580+
User: req.User,
581+
BotName: req.BotName,
582+
BotInstanceID: req.BotInstanceID,
583+
UserKind: userKind,
584+
AWSRoleARN: req.AWSRoleARN,
585+
}
586+
587+
if req.DeviceExtensions.DeviceID != "" {
588+
userMetadata.TrustedDevice = &apievents.DeviceMetadata{
589+
DeviceId: req.DeviceExtensions.DeviceID,
590+
AssetTag: req.DeviceExtensions.AssetTag,
591+
CredentialId: req.DeviceExtensions.CredentialID,
592+
}
593+
}
594+
errMsg := "requires a trusted device"
595+
596+
sessionStartEvent.Metadata.SetCode(events.AppSessionStartFailureCode)
597+
sessionStartEvent.UserMetadata = userMetadata
598+
sessionStartEvent.SessionMetadata = apievents.SessionMetadata{
599+
WithMFA: req.MFAVerified,
600+
}
601+
sessionStartEvent.Error = err.Error()
602+
sessionStartEvent.UserMessage = errMsg
603+
604+
a.emitter.EmitAuditEvent(a.closeCtx, sessionStartEvent)
605+
// err swallowed/obscured on purpose.
606+
return nil, trace.AccessDenied("%s", errMsg)
607+
}
608+
546609
// Create certificate for this session.
547610
priv, err := cryptosuites.GenerateKey(ctx, cryptosuites.GetCurrentSuiteFromAuthPreference(a), cryptosuites.UserTLS)
548611
if err != nil {
@@ -641,36 +704,16 @@ func (a *Server) CreateAppSessionFromReq(ctx context.Context, req NewAppSessionR
641704
userMetadata.User = session.GetUser()
642705
userMetadata.AWSRoleARN = req.AWSRoleARN
643706

644-
err = a.emitter.EmitAuditEvent(a.closeCtx, &apievents.AppSessionStart{
645-
Metadata: apievents.Metadata{
646-
Type: events.AppSessionStartEvent,
647-
Code: events.AppSessionStartCode,
648-
ClusterName: req.ClusterName,
649-
},
650-
ServerMetadata: apievents.ServerMetadata{
651-
ServerVersion: teleport.Version,
652-
ServerID: a.ServerID,
653-
ServerNamespace: apidefaults.Namespace,
654-
},
655-
SessionMetadata: apievents.SessionMetadata{
656-
SessionID: session.GetName(),
657-
WithMFA: req.MFAVerified,
658-
PrivateKeyPolicy: string(req.Identity.PrivateKeyPolicy),
659-
},
660-
UserMetadata: userMetadata,
661-
ConnectionMetadata: apievents.ConnectionMetadata{
662-
RemoteAddr: req.ClientAddr,
663-
},
664-
PublicAddr: req.PublicAddr,
665-
AppMetadata: apievents.AppMetadata{
666-
AppURI: req.AppURI,
667-
AppPublicAddr: req.PublicAddr,
668-
AppName: req.AppName,
669-
AppTargetPort: uint32(req.AppTargetPort),
670-
},
671-
})
672-
if err != nil {
673-
log.WithError(err).Warn("Failed to emit app session start event")
707+
sessionStartEvent.Metadata.SetCode(events.AppSessionStartCode)
708+
sessionStartEvent.UserMetadata = userMetadata
709+
sessionStartEvent.SessionMetadata = apievents.SessionMetadata{
710+
SessionID: session.GetName(),
711+
WithMFA: req.MFAVerified,
712+
PrivateKeyPolicy: string(identity.PrivateKeyPolicy),
713+
}
714+
715+
if err := a.emitter.EmitAuditEvent(a.closeCtx, sessionStartEvent); err != nil {
716+
a.logger.WarnContext(ctx, "Failed to emit app session start event", "error", err)
674717
}
675718

676719
return session, nil

0 commit comments

Comments
 (0)