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 @@ -2151,7 +2151,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 @@ -2948,6 +2948,14 @@ message AppSessionStart {
(gogoproto.embed) = true,
(gogoproto.jsontag) = ""
];

// Error is an optional error message.
Comment thread
codingllama marked this conversation as resolved.
// Only present in failed start attempts.
string Error = 9 [(gogoproto.jsontag) = "error,omitempty"];

// UserMessage is an optional user-friendly error message.
Comment thread
codingllama marked this conversation as resolved.
// Only present in failed start attempts.
string UserMessage = 10 [(gogoproto.jsontag) = "message,omitempty"];
}

// AppSessionEnd is emitted when an application session ends.
Expand Down
2,545 changes: 1,319 additions & 1,226 deletions api/types/events/events.pb.go

Large diffs are not rendered by default.

19 changes: 19 additions & 0 deletions docs/pages/reference/audit-events.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -671,6 +671,10 @@ Example:

## app.session.start

There are multiple events with the `app.session.start` type.

### T2007I

App Session Started

Example:
Expand All @@ -692,6 +696,21 @@ Example:
}
```

### T2007E

App Session Start Failed

Example:

```json
{
"code": "T2007E",
"event": "app.session.start",
"time": "2020-06-05T16:24:05Z",
"uid": "68a83a99-73ce-4bd7-bbf7-99103c2ba6a0"
}
```

## app.update

Application Updated
Expand Down
1 change: 0 additions & 1 deletion integration/appaccess/appaccess_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -609,7 +609,6 @@ func testAuditEvents(p *Pack, t *testing.T) {
AppPublicAddr: p.rootAppPublicAddr,
AppName: p.rootAppName,
},
PublicAddr: p.rootAppPublicAddr,
}
return len(cmp.Diff(
expectedEvent,
Expand Down
108 changes: 77 additions & 31 deletions lib/auth/sessions.go
Original file line number Diff line number Diff line change
Expand Up @@ -445,8 +445,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
// SuggestedSessionID is a session ID suggested by the requester.
Expand Down Expand Up @@ -518,6 +516,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 @@ -557,6 +557,72 @@ 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,
UserRoles: req.Roles,
UserClusterName: req.ClusterName,
UserTraits: req.Traits,
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)
Comment thread
codingllama marked this conversation as resolved.
}

sessionID := req.SuggestedSessionID
if sessionID == "" {
// Create services.WebSession for this session.
Expand Down Expand Up @@ -669,35 +735,15 @@ 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 {
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)
}

Expand Down
Loading
Loading