Skip to content
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
10 changes: 9 additions & 1 deletion api/proto/teleport/legacy/types/events/events.proto
Original file line number Diff line number Diff line change
Expand Up @@ -2113,7 +2113,7 @@ message ClientDisconnect {
string Reason = 5 [(gogoproto.jsontag) = "reason"];
}

// AuthAttempt is emitted upon a failed or successfull authentication attempt.
// AuthAttempt is emitted upon a failed authentication attempt.
message AuthAttempt {
// Metadata is a common event metadata
Metadata Metadata = 1 [
Expand Down Expand Up @@ -2903,6 +2903,14 @@ message AppSessionStart {
(gogoproto.embed) = true,
(gogoproto.jsontag) = ""
];

// Error is an optional error message.
// Only present in failed start attempts.
string Error = 9 [(gogoproto.jsontag) = "error,omitempty"];

// UserMessage is an optional user-friendly error message.
// Only present in failed start attempts.
string UserMessage = 10 [(gogoproto.jsontag) = "message,omitempty"];
}

// AppSessionEnd is emitted when an application session ends.
Expand Down
1,811 changes: 952 additions & 859 deletions api/types/events/events.pb.go

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion integration/appaccess/appaccess_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -588,7 +588,6 @@ func testAuditEvents(p *Pack, t *testing.T) {
AppPublicAddr: p.rootAppPublicAddr,
AppName: p.rootAppName,
},
PublicAddr: p.rootAppPublicAddr,
}
return len(cmp.Diff(
expectedEvent,
Expand Down
107 changes: 75 additions & 32 deletions lib/auth/sessions.go
Original file line number Diff line number Diff line change
Expand Up @@ -427,8 +427,6 @@ type NewAppSessionRequest struct {
AppURI string
// AppTargetPort signifies that the session is made to a specific port of a multi-port TCP app.
AppTargetPort int
// Identity is the identity of the user.
Identity tlsca.Identity
// ClientAddr is a client (user's) address.
ClientAddr string

Expand Down Expand Up @@ -498,6 +496,8 @@ func (a *Server) CreateAppSession(ctx context.Context, req *proto.CreateAppSessi
MFAVerified: verifiedMFADeviceID,
AppName: req.AppName,
AppURI: req.URI,
BotName: identity.BotName,
BotInstanceID: identity.BotInstanceID,
DeviceExtensions: DeviceExtensions(identity.DeviceExtensions),
})
if err != nil {
Expand Down Expand Up @@ -543,6 +543,69 @@ func (a *Server) CreateAppSessionFromReq(ctx context.Context, req NewAppSessionR
return nil, trace.Wrap(err)
}

// Audit fields used for both success and failure
sessionStartEvent := &apievents.AppSessionStart{
Metadata: apievents.Metadata{
Type: events.AppSessionStartEvent,
ClusterName: req.ClusterName,
},
ServerMetadata: apievents.ServerMetadata{
ServerVersion: teleport.Version,
ServerID: a.ServerID,
ServerNamespace: apidefaults.Namespace,
},
ConnectionMetadata: apievents.ConnectionMetadata{
RemoteAddr: req.ClientAddr,
},
AppMetadata: apievents.AppMetadata{
AppURI: req.AppURI,
AppPublicAddr: req.PublicAddr,
AppName: req.AppName,
AppTargetPort: uint32(req.AppTargetPort),
},
}

// Enforce device trust early via the AccessChecker.
if err = checker.CheckDeviceAccess(services.AccessState{
DeviceVerified: dtauthz.IsTLSDeviceVerified((*tlsca.DeviceExtensions)(&req.DeviceExtensions)),
EnableDeviceVerification: true,
IsBot: req.BotName != "",
}); err != nil {
userKind := apievents.UserKind_USER_KIND_HUMAN
if req.BotName != "" {
userKind = apievents.UserKind_USER_KIND_BOT
}

userMetadata := apievents.UserMetadata{
User: req.User,
BotName: req.BotName,
BotInstanceID: req.BotInstanceID,
UserKind: userKind,
AWSRoleARN: req.AWSRoleARN,
}

if req.DeviceExtensions.DeviceID != "" {
userMetadata.TrustedDevice = &apievents.DeviceMetadata{
DeviceId: req.DeviceExtensions.DeviceID,
AssetTag: req.DeviceExtensions.AssetTag,
CredentialId: req.DeviceExtensions.CredentialID,
}
}
errMsg := "requires a trusted device"

sessionStartEvent.Metadata.SetCode(events.AppSessionStartFailureCode)
sessionStartEvent.UserMetadata = userMetadata
sessionStartEvent.SessionMetadata = apievents.SessionMetadata{
WithMFA: req.MFAVerified,
}
sessionStartEvent.Error = err.Error()
sessionStartEvent.UserMessage = errMsg

a.emitter.EmitAuditEvent(a.closeCtx, sessionStartEvent)
// err swallowed/obscured on purpose.
return nil, trace.AccessDenied("%s", errMsg)
}

// Create certificate for this session.
priv, err := cryptosuites.GenerateKey(ctx, cryptosuites.GetCurrentSuiteFromAuthPreference(a), cryptosuites.UserTLS)
if err != nil {
Expand Down Expand Up @@ -641,36 +704,16 @@ func (a *Server) CreateAppSessionFromReq(ctx context.Context, req NewAppSessionR
userMetadata.User = session.GetUser()
userMetadata.AWSRoleARN = req.AWSRoleARN

err = a.emitter.EmitAuditEvent(a.closeCtx, &apievents.AppSessionStart{
Metadata: apievents.Metadata{
Type: events.AppSessionStartEvent,
Code: events.AppSessionStartCode,
ClusterName: req.ClusterName,
},
ServerMetadata: apievents.ServerMetadata{
ServerVersion: teleport.Version,
ServerID: a.ServerID,
ServerNamespace: apidefaults.Namespace,
},
SessionMetadata: apievents.SessionMetadata{
SessionID: session.GetName(),
WithMFA: req.MFAVerified,
PrivateKeyPolicy: string(req.Identity.PrivateKeyPolicy),
},
UserMetadata: userMetadata,
ConnectionMetadata: apievents.ConnectionMetadata{
RemoteAddr: req.ClientAddr,
},
PublicAddr: req.PublicAddr,
AppMetadata: apievents.AppMetadata{
AppURI: req.AppURI,
AppPublicAddr: req.PublicAddr,
AppName: req.AppName,
AppTargetPort: uint32(req.AppTargetPort),
},
})
if err != nil {
log.WithError(err).Warn("Failed to emit app session start event")
sessionStartEvent.Metadata.SetCode(events.AppSessionStartCode)
sessionStartEvent.UserMetadata = userMetadata
sessionStartEvent.SessionMetadata = apievents.SessionMetadata{
SessionID: session.GetName(),
WithMFA: req.MFAVerified,
PrivateKeyPolicy: string(identity.PrivateKeyPolicy),
}

if err := a.emitter.EmitAuditEvent(a.closeCtx, sessionStartEvent); err != nil {
a.logger.WarnContext(ctx, "Failed to emit app session start event", "error", err)
}

return session, nil
Expand Down
Loading
Loading