mirror of
https://github.com/gravitational/teleport.git
synced 2026-10-11 22:49:54 +00:00
support where RBAC on application session recordings (#69630)
* support `where` RBAC on application session recordings application session recordings are backed by AppSessionChunk events, but those events were never wired into the session recording RBAC path, so `where` clauses on `kind: session` rules could not match them. Fixes https://github.com/gravitational/teleport/issues/67775 Signed-off-by: Tiago Silva <[email protected]> * fix unit test * handle feedback --------- Signed-off-by: Tiago Silva <[email protected]>
This commit is contained in:
@@ -3279,6 +3279,10 @@ message AppSessionChunk {
|
|||||||
(gogoproto.embed) = true,
|
(gogoproto.embed) = true,
|
||||||
(gogoproto.jsontag) = ""
|
(gogoproto.jsontag) = ""
|
||||||
];
|
];
|
||||||
|
// Participants is the list of participants in a session.
|
||||||
|
// App sessions only have one participant but we keep it a repeated field
|
||||||
|
// to keep compatibility with other session end events.
|
||||||
|
repeated string Participants = 8 [(gogoproto.jsontag) = "participants,omitempty"];
|
||||||
}
|
}
|
||||||
|
|
||||||
// AppSessionRequest is an HTTP request and response.
|
// AppSessionRequest is an HTTP request and response.
|
||||||
|
|||||||
@@ -126,4 +126,6 @@ const (
|
|||||||
EventProtocolTDP = "tdp"
|
EventProtocolTDP = "tdp"
|
||||||
// EventProtocolDB specifies database as a type of captured protocol
|
// EventProtocolDB specifies database as a type of captured protocol
|
||||||
EventProtocolDB = "db"
|
EventProtocolDB = "db"
|
||||||
|
// EventProtocolApp specifies app as a type of captured protocol
|
||||||
|
EventProtocolApp = "app"
|
||||||
)
|
)
|
||||||
|
|||||||
+1633
-1582
File diff suppressed because it is too large
Load Diff
@@ -595,9 +595,8 @@ resource type and the session creator (user who initiated the session) roles and
|
|||||||
| Session Field | Description | Type |
|
| Session Field | Description | Type |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `session.id` | The unique identifier of the session. | `string` |
|
| `session.id` | The unique identifier of the session. | `string` |
|
||||||
| `session.kind` | The kind of session (e.g., "ssh", "kube", "db", "rdp"). | `string` |
|
|
||||||
| `session.participants` | The list of users who participated in the session. | `array<string>` |
|
| `session.participants` | The list of users who participated in the session. | `array<string>` |
|
||||||
| `session.proto` | The proto used for the session (e.g., "ssh", "kube", "db", "rdp"). | `string` |
|
| `session.proto` | The proto used for the session (e.g., "ssh", "kube", "db", "tdp", "app"). | `string` |
|
||||||
| `session.user` | The user who initiated the session. | `string` |
|
| `session.user` | The user who initiated the session. | `string` |
|
||||||
| `session.user_roles` | The roles assigned to the user who initiated the session. | `array<string>` |
|
| `session.user_roles` | The roles assigned to the user who initiated the session. | `array<string>` |
|
||||||
| `session.user_traits` | The traits assigned to the user who initiated the session. | `dict<string, array<string>>` |
|
| `session.user_traits` | The traits assigned to the user who initiated the session. | `dict<string, array<string>>` |
|
||||||
@@ -669,6 +668,22 @@ for Windows Desktop sessions together with the user and session fields above.
|
|||||||
| `session.windows_user` | The username used to log in to the Windows desktop during the session. | `string` |
|
| `session.windows_user` | The username used to log in to the Windows desktop during the session. | `string` |
|
||||||
| `session.desktop_labels` | The labels assigned to the Windows desktop where the session took place. | `dict<string, string>` |
|
| `session.desktop_labels` | The labels assigned to the Windows desktop where the session took place. | `dict<string, string>` |
|
||||||
|
|
||||||
|
</TabItem>
|
||||||
|
<TabItem value="Application Sessions" label="Application Sessions">
|
||||||
|
|
||||||
|
The following application session fields can be used in `where` expressions to filter access
|
||||||
|
for application sessions together with the user and session fields above.
|
||||||
|
|
||||||
|
| Application Session Field | Description | Type |
|
||||||
|
|---|---|---|
|
||||||
|
| `session.app_name` | The name of the application where the session took place. | `string` |
|
||||||
|
| `session.app_uri` | The endpoint of the application where the session took place. | `string` |
|
||||||
|
| `session.app_public_addr` | The public address of the application where the session took place. | `string` |
|
||||||
|
| `session.app_labels` | The labels assigned to the application where the session took place. | `dict<string, string>` |
|
||||||
|
|
||||||
|
Only HTTP/HTTPS applications produce session recordings, so these fields are not
|
||||||
|
available for TCP applications.
|
||||||
|
|
||||||
</TabItem>
|
</TabItem>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
|
||||||
|
|||||||
@@ -753,6 +753,7 @@ func testAuditEvents(p *Pack, t *testing.T) {
|
|||||||
AppPublicAddr: p.rootAppPublicAddr,
|
AppPublicAddr: p.rootAppPublicAddr,
|
||||||
AppName: p.rootAppName,
|
AppName: p.rootAppName,
|
||||||
},
|
},
|
||||||
|
Participants: []string{p.username},
|
||||||
}
|
}
|
||||||
return len(cmp.Diff(
|
return len(cmp.Diff(
|
||||||
expectedEvent,
|
expectedEvent,
|
||||||
@@ -760,6 +761,7 @@ func testAuditEvents(p *Pack, t *testing.T) {
|
|||||||
cmpopts.IgnoreTypes(apievents.ServerMetadata{}, apievents.SessionMetadata{}, apievents.UserMetadata{}, apievents.ConnectionMetadata{}),
|
cmpopts.IgnoreTypes(apievents.ServerMetadata{}, apievents.SessionMetadata{}, apievents.UserMetadata{}, apievents.ConnectionMetadata{}),
|
||||||
cmpopts.IgnoreFields(apievents.Metadata{}, "ID", "Time", "Index"),
|
cmpopts.IgnoreFields(apievents.Metadata{}, "ID", "Time", "Index"),
|
||||||
cmpopts.IgnoreFields(apievents.AppSessionChunk{}, "SessionChunkID"),
|
cmpopts.IgnoreFields(apievents.AppSessionChunk{}, "SessionChunkID"),
|
||||||
|
cmpopts.IgnoreFields(apievents.AppMetadata{}, "AppLabels"),
|
||||||
)) == 0
|
)) == 0
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -843,10 +843,10 @@ func (p *Pack) startRootAppServers(t *testing.T, count int, opts AppTestOptions)
|
|||||||
URI: p.rootTCPMultiPortAppURI,
|
URI: p.rootTCPMultiPortAppURI,
|
||||||
PublicAddr: p.rootTCPMultiPortPublicAddr,
|
PublicAddr: p.rootTCPMultiPortPublicAddr,
|
||||||
TCPPorts: []servicecfg.PortRange{
|
TCPPorts: []servicecfg.PortRange{
|
||||||
servicecfg.PortRange{
|
{
|
||||||
Port: p.rootTCPMultiPortAppPortAlpha,
|
Port: p.rootTCPMultiPortAppPortAlpha,
|
||||||
},
|
},
|
||||||
servicecfg.PortRange{
|
{
|
||||||
Port: p.rootTCPMultiPortAppPortBeta,
|
Port: p.rootTCPMultiPortAppPortBeta,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -1008,10 +1008,10 @@ func (p *Pack) startLeafAppServers(t *testing.T, count int, opts AppTestOptions)
|
|||||||
URI: p.leafTCPMultiPortAppURI,
|
URI: p.leafTCPMultiPortAppURI,
|
||||||
PublicAddr: p.leafTCPMultiPortPublicAddr,
|
PublicAddr: p.leafTCPMultiPortPublicAddr,
|
||||||
TCPPorts: []servicecfg.PortRange{
|
TCPPorts: []servicecfg.PortRange{
|
||||||
servicecfg.PortRange{
|
{
|
||||||
Port: p.leafTCPMultiPortAppPortAlpha,
|
Port: p.leafTCPMultiPortAppPortAlpha,
|
||||||
},
|
},
|
||||||
servicecfg.PortRange{
|
{
|
||||||
Port: p.leafTCPMultiPortAppPortBeta,
|
Port: p.leafTCPMultiPortAppPortBeta,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -60,6 +60,8 @@ const (
|
|||||||
EventProtocolTDP = apievents.EventProtocolTDP
|
EventProtocolTDP = apievents.EventProtocolTDP
|
||||||
// EventProtocolDB specifies database as a type of captured protocol
|
// EventProtocolDB specifies database as a type of captured protocol
|
||||||
EventProtocolDB = apievents.EventProtocolDB
|
EventProtocolDB = apievents.EventProtocolDB
|
||||||
|
// EventProtocolApp specifies app as a type of captured protocol
|
||||||
|
EventProtocolApp = apievents.EventProtocolApp
|
||||||
// LocalAddr is a target address on the host
|
// LocalAddr is a target address on the host
|
||||||
LocalAddr = "addr.local"
|
LocalAddr = "addr.local"
|
||||||
// RemoteAddr is a client (user's) address
|
// RemoteAddr is a client (user's) address
|
||||||
|
|||||||
@@ -480,7 +480,7 @@ func (ctx *Context) GetIdentifier(fields []string) (any, error) {
|
|||||||
case SessionIdentifier:
|
case SessionIdentifier:
|
||||||
var session events.AuditEvent = &events.SessionEnd{}
|
var session events.AuditEvent = &events.SessionEnd{}
|
||||||
switch ctx.Session.(type) {
|
switch ctx.Session.(type) {
|
||||||
case *events.SessionEnd, *events.WindowsDesktopSessionEnd, *events.LinuxDesktopSessionEnd, *events.DatabaseSessionEnd:
|
case *events.SessionEnd, *events.WindowsDesktopSessionEnd, *events.LinuxDesktopSessionEnd, *events.DatabaseSessionEnd, *events.AppSessionChunk:
|
||||||
session = ctx.Session
|
session = ctx.Session
|
||||||
}
|
}
|
||||||
v, origErr := predicate.GetFieldByTag(session, teleport.JSON, fields[1:])
|
v, origErr := predicate.GetFieldByTag(session, teleport.JSON, fields[1:])
|
||||||
@@ -537,7 +537,7 @@ func (ctx *Context) GetIdentifier(fields []string) (any, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getMissingEmptyFieldForSessionEnd(fields []string) (any, error) {
|
func getMissingEmptyFieldForSessionEnd(fields []string) (any, error) {
|
||||||
for _, emptySession := range []events.AuditEvent{&events.SessionEnd{}, &events.WindowsDesktopSessionEnd{}, &events.DatabaseSessionEnd{}} {
|
for _, emptySession := range []events.AuditEvent{&events.SessionEnd{}, &events.WindowsDesktopSessionEnd{}, &events.DatabaseSessionEnd{}, &events.AppSessionChunk{}} {
|
||||||
v, err := predicate.GetFieldByTag(emptySession, teleport.JSON, fields[1:])
|
v, err := predicate.GetFieldByTag(emptySession, teleport.JSON, fields[1:])
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return v, nil
|
return v, nil
|
||||||
|
|||||||
@@ -11245,6 +11245,9 @@ func TestSessionRecordingRBAC(t *testing.T) {
|
|||||||
NodeLabels: types.Labels{
|
NodeLabels: types.Labels{
|
||||||
"env": []string{"prod"},
|
"env": []string{"prod"},
|
||||||
},
|
},
|
||||||
|
AppLabels: types.Labels{
|
||||||
|
"env": []string{"prod"},
|
||||||
|
},
|
||||||
Rules: allowRules,
|
Rules: allowRules,
|
||||||
},
|
},
|
||||||
Deny: types.RoleConditions{
|
Deny: types.RoleConditions{
|
||||||
@@ -11270,6 +11273,25 @@ func TestSessionRecordingRBAC(t *testing.T) {
|
|||||||
"env": "dev",
|
"env": "dev",
|
||||||
})
|
})
|
||||||
|
|
||||||
|
newApp := func(name string, labels map[string]string) types.Application {
|
||||||
|
app, err := types.NewAppV3(types.Metadata{
|
||||||
|
Name: name,
|
||||||
|
Labels: labels,
|
||||||
|
}, types.AppSpecV3{
|
||||||
|
URI: "http://localhost:8080",
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
return app
|
||||||
|
}
|
||||||
|
|
||||||
|
appWithAccess := newApp("app-with-access", map[string]string{
|
||||||
|
"env": "prod",
|
||||||
|
})
|
||||||
|
|
||||||
|
appWithoutAccess := newApp("app-without-access", map[string]string{
|
||||||
|
"env": "dev",
|
||||||
|
})
|
||||||
|
|
||||||
alice := newUser(
|
alice := newUser(
|
||||||
"alice",
|
"alice",
|
||||||
map[string][]string{
|
map[string][]string{
|
||||||
@@ -11764,6 +11786,70 @@ func TestSessionRecordingRBAC(t *testing.T) {
|
|||||||
},
|
},
|
||||||
errCheck: require.NoError,
|
errCheck: require.NoError,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "24 - bob can read app session because his group matches with env label for app",
|
||||||
|
roles: RoleSet{
|
||||||
|
newRole(&types.Rule{
|
||||||
|
Resources: []string{types.KindSession},
|
||||||
|
Verbs: []string{types.VerbRead},
|
||||||
|
Where: `contains(user.spec.traits["group"], session.app_labels["env"])`,
|
||||||
|
}, nil),
|
||||||
|
},
|
||||||
|
context: Context{
|
||||||
|
User: bob,
|
||||||
|
Session: newAppSessionChunkEvent(),
|
||||||
|
Resource: appWithAccess,
|
||||||
|
},
|
||||||
|
errCheck: require.NoError,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "25 - john can not read app session because his group does not match with env label for app",
|
||||||
|
roles: RoleSet{
|
||||||
|
newRole(&types.Rule{
|
||||||
|
Resources: []string{types.KindSession},
|
||||||
|
Verbs: []string{types.VerbRead},
|
||||||
|
Where: `contains(user.spec.traits["group"], session.app_labels["env"])`,
|
||||||
|
}, nil),
|
||||||
|
},
|
||||||
|
context: Context{
|
||||||
|
User: john,
|
||||||
|
Session: newAppSessionChunkEvent(),
|
||||||
|
Resource: appWithAccess,
|
||||||
|
},
|
||||||
|
errCheck: requireAccessDenied,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "26 - bob can read app session because he has access to the app",
|
||||||
|
roles: RoleSet{
|
||||||
|
newRole(&types.Rule{
|
||||||
|
Resources: []string{types.KindSession},
|
||||||
|
Verbs: []string{types.VerbRead},
|
||||||
|
Where: `can_view()`,
|
||||||
|
}, nil),
|
||||||
|
},
|
||||||
|
context: Context{
|
||||||
|
User: bob,
|
||||||
|
Session: newAppSessionChunkEvent(),
|
||||||
|
Resource: appWithAccess,
|
||||||
|
},
|
||||||
|
errCheck: require.NoError,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "27 - bob can not read app session because he has no access to the app",
|
||||||
|
roles: RoleSet{
|
||||||
|
newRole(&types.Rule{
|
||||||
|
Resources: []string{types.KindSession},
|
||||||
|
Verbs: []string{types.VerbRead},
|
||||||
|
Where: `can_view()`,
|
||||||
|
}, nil),
|
||||||
|
},
|
||||||
|
context: Context{
|
||||||
|
User: bob,
|
||||||
|
Session: newAppSessionChunkEvent(),
|
||||||
|
Resource: appWithoutAccess,
|
||||||
|
},
|
||||||
|
errCheck: requireAccessDenied,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
@@ -11865,6 +11951,37 @@ func newDatabaseSessionEndEvent() *apievents.DatabaseSessionEnd {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newAppSessionChunkEvent() *apievents.AppSessionChunk {
|
||||||
|
return &apievents.AppSessionChunk{
|
||||||
|
Metadata: apievents.Metadata{
|
||||||
|
Index: 20,
|
||||||
|
Type: "app.session.chunk",
|
||||||
|
ID: "da455e0f-c27d-459f-a218-4e83b3db9426",
|
||||||
|
Code: "T2008I",
|
||||||
|
Time: time.Date(2020, 3, 30, 15, 58, 54, 561*int(time.Millisecond), time.UTC),
|
||||||
|
},
|
||||||
|
AppMetadata: apievents.AppMetadata{
|
||||||
|
AppName: "app-with-access",
|
||||||
|
AppURI: "http://localhost:8080",
|
||||||
|
AppPublicAddr: "app.example.com",
|
||||||
|
AppLabels: map[string]string{"env": "prod"},
|
||||||
|
},
|
||||||
|
ConnectionMetadata: apievents.ConnectionMetadata{
|
||||||
|
Protocol: apievents.EventProtocolApp,
|
||||||
|
},
|
||||||
|
UserMetadata: apievents.UserMetadata{
|
||||||
|
User: "alice",
|
||||||
|
UserRoles: []string{"role1"},
|
||||||
|
UserTraits: map[string][]string{
|
||||||
|
"group": {"prod"},
|
||||||
|
"team": {"engineering"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Participants: []string{"alice"},
|
||||||
|
SessionChunkID: "cb116fb0-9227-4889-9392-aedd13a914a6",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestCheckSubmitForUser(t *testing.T) {
|
func TestCheckSubmitForUser(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
|
|||||||
@@ -106,6 +106,23 @@ func rebuildResourceFromSessionEndEvent(event apievents.AuditEvent) types.Resour
|
|||||||
Domain: sEnd.Domain,
|
Domain: sEnd.Domain,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
case *apievents.AppSessionChunk:
|
||||||
|
if sEnd == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &types.AppV3{
|
||||||
|
Kind: types.KindApp,
|
||||||
|
Version: types.V3,
|
||||||
|
Metadata: types.Metadata{
|
||||||
|
Name: sEnd.AppName,
|
||||||
|
Namespace: apidefaults.Namespace,
|
||||||
|
Labels: sEnd.AppLabels,
|
||||||
|
},
|
||||||
|
Spec: types.AppSpecV3{
|
||||||
|
URI: sEnd.AppURI,
|
||||||
|
PublicAddr: sEnd.AppPublicAddr,
|
||||||
|
},
|
||||||
|
}
|
||||||
case *apievents.DatabaseSessionEnd:
|
case *apievents.DatabaseSessionEnd:
|
||||||
if sEnd == nil {
|
if sEnd == nil {
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -53,6 +53,11 @@ func TestRebuildResourceFromSessionEndEvent(t *testing.T) {
|
|||||||
event: (*apievents.DatabaseSessionEnd)(nil),
|
event: (*apievents.DatabaseSessionEnd)(nil),
|
||||||
want: nil,
|
want: nil,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "nil with type set app.session.chunk",
|
||||||
|
event: (*apievents.AppSessionChunk)(nil),
|
||||||
|
want: nil,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "non session.end event",
|
name: "non session.end event",
|
||||||
event: &apievents.UserLogin{
|
event: &apievents.UserLogin{
|
||||||
@@ -188,6 +193,36 @@ func TestRebuildResourceFromSessionEndEvent(t *testing.T) {
|
|||||||
Spec: types.DatabaseSpecV3{},
|
Spec: types.DatabaseSpecV3{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "app session chunk",
|
||||||
|
event: &apievents.AppSessionChunk{
|
||||||
|
AppMetadata: apievents.AppMetadata{
|
||||||
|
AppName: "app-name",
|
||||||
|
AppURI: "http://localhost:8080",
|
||||||
|
AppPublicAddr: "app.example.com",
|
||||||
|
AppLabels: map[string]string{
|
||||||
|
"env": "prod",
|
||||||
|
"team": "web",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: &types.AppV3{
|
||||||
|
Kind: types.KindApp,
|
||||||
|
Version: types.V3,
|
||||||
|
Metadata: types.Metadata{
|
||||||
|
Name: "app-name",
|
||||||
|
Namespace: "default",
|
||||||
|
Labels: map[string]string{
|
||||||
|
"env": "prod",
|
||||||
|
"team": "web",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Spec: types.AppSpecV3{
|
||||||
|
URI: "http://localhost:8080",
|
||||||
|
PublicAddr: "app.example.com",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
|||||||
@@ -29,7 +29,9 @@ import (
|
|||||||
apidefaults "github.com/gravitational/teleport/api/defaults"
|
apidefaults "github.com/gravitational/teleport/api/defaults"
|
||||||
"github.com/gravitational/teleport/api/types"
|
"github.com/gravitational/teleport/api/types"
|
||||||
apievents "github.com/gravitational/teleport/api/types/events"
|
apievents "github.com/gravitational/teleport/api/types/events"
|
||||||
|
"github.com/gravitational/teleport/lib/authz"
|
||||||
"github.com/gravitational/teleport/lib/events"
|
"github.com/gravitational/teleport/lib/events"
|
||||||
|
"github.com/gravitational/teleport/lib/services"
|
||||||
"github.com/gravitational/teleport/lib/tlsca"
|
"github.com/gravitational/teleport/lib/tlsca"
|
||||||
awsutils "github.com/gravitational/teleport/lib/utils/aws"
|
awsutils "github.com/gravitational/teleport/lib/utils/aws"
|
||||||
)
|
)
|
||||||
@@ -156,6 +158,14 @@ func (a *audit) OnSessionEnd(ctx context.Context, serverID string, identity *tls
|
|||||||
|
|
||||||
// OnSessionChunk is called when a new session chunk is created.
|
// OnSessionChunk is called when a new session chunk is created.
|
||||||
func (a *audit) OnSessionChunk(ctx context.Context, serverID, chunkID string, identity *tlsca.Identity, app types.Application) error {
|
func (a *audit) OnSessionChunk(ctx context.Context, serverID, chunkID string, identity *tlsca.Identity, app types.Application) error {
|
||||||
|
// Enforce IP Pinning if it is present in the user's certificate.
|
||||||
|
var clientAddr string
|
||||||
|
if clientSrcAddr, err := authz.ClientSrcAddrFromContext(ctx); err == nil {
|
||||||
|
clientAddr = clientSrcAddr.String()
|
||||||
|
} else {
|
||||||
|
clientAddr = identity.LoginIP
|
||||||
|
}
|
||||||
|
|
||||||
event := &apievents.AppSessionChunk{
|
event := &apievents.AppSessionChunk{
|
||||||
Metadata: apievents.Metadata{
|
Metadata: apievents.Metadata{
|
||||||
Type: events.AppSessionChunkEvent,
|
Type: events.AppSessionChunkEvent,
|
||||||
@@ -167,15 +177,28 @@ func (a *audit) OnSessionChunk(ctx context.Context, serverID, chunkID string, id
|
|||||||
ServerID: serverID,
|
ServerID: serverID,
|
||||||
ServerNamespace: apidefaults.Namespace,
|
ServerNamespace: apidefaults.Namespace,
|
||||||
},
|
},
|
||||||
|
ConnectionMetadata: apievents.ConnectionMetadata{
|
||||||
|
LocalAddr: clientAddr,
|
||||||
|
RemoteAddr: app.GetURI(),
|
||||||
|
Protocol: events.EventProtocolApp,
|
||||||
|
},
|
||||||
SessionMetadata: getSessionMetadata(identity),
|
SessionMetadata: getSessionMetadata(identity),
|
||||||
UserMetadata: identity.GetUserMetadata(),
|
UserMetadata: identity.GetUserMetadata(),
|
||||||
AppMetadata: apievents.AppMetadata{
|
AppMetadata: apievents.AppMetadata{
|
||||||
AppURI: app.GetURI(),
|
AppURI: app.GetURI(),
|
||||||
AppPublicAddr: app.GetPublicAddr(),
|
AppPublicAddr: app.GetPublicAddr(),
|
||||||
AppName: app.GetName(),
|
AppName: app.GetName(),
|
||||||
|
AppLabels: app.GetAllLabels(),
|
||||||
// Session chunks are not created for TCP apps, so there's no need to pass TargetPort here.
|
// Session chunks are not created for TCP apps, so there's no need to pass TargetPort here.
|
||||||
},
|
},
|
||||||
SessionChunkID: chunkID,
|
SessionChunkID: chunkID,
|
||||||
|
Participants: []string{services.UsernameForCluster(
|
||||||
|
services.UsernameForClusterConfig{
|
||||||
|
User: identity.Username,
|
||||||
|
OriginClusterName: identity.OriginClusterName,
|
||||||
|
LocalClusterName: identity.TeleportCluster,
|
||||||
|
},
|
||||||
|
)},
|
||||||
}
|
}
|
||||||
return trace.Wrap(a.EmitEvent(ctx, event))
|
return trace.Wrap(a.EmitEvent(ctx, event))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -644,7 +644,6 @@ func TestShutdown(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}, 10*time.Second, 100*time.Millisecond)
|
}, 10*time.Second, 100*time.Millisecond)
|
||||||
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -1037,7 +1036,6 @@ func TestRewriteJWT(t *testing.T) {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestAuthorize verifies that only authorized requests are handled.
|
// TestAuthorize verifies that only authorized requests are handled.
|
||||||
@@ -1293,7 +1291,12 @@ func TestRequestAuditEvents(t *testing.T) {
|
|||||||
AppURI: app.Spec.URI,
|
AppURI: app.Spec.URI,
|
||||||
AppPublicAddr: app.Spec.PublicAddr,
|
AppPublicAddr: app.Spec.PublicAddr,
|
||||||
AppName: app.Metadata.Name,
|
AppName: app.Metadata.Name,
|
||||||
|
AppLabels: map[string]string{
|
||||||
|
"bar": "baz",
|
||||||
|
"qux": "4",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
Participants: []string{"foo"},
|
||||||
}
|
}
|
||||||
require.Empty(t, gocmp.Diff(
|
require.Empty(t, gocmp.Diff(
|
||||||
expectedEvent,
|
expectedEvent,
|
||||||
@@ -1370,7 +1373,12 @@ func TestRequestAuditEvents(t *testing.T) {
|
|||||||
AppURI: app.Spec.URI,
|
AppURI: app.Spec.URI,
|
||||||
AppPublicAddr: app.Spec.PublicAddr,
|
AppPublicAddr: app.Spec.PublicAddr,
|
||||||
AppName: app.Metadata.Name,
|
AppName: app.Metadata.Name,
|
||||||
|
AppLabels: map[string]string{
|
||||||
|
"bar": "baz",
|
||||||
|
"qux": "4",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
Participants: []string{"foo"},
|
||||||
}
|
}
|
||||||
require.Empty(t, gocmp.Diff(
|
require.Empty(t, gocmp.Diff(
|
||||||
expectedEvent,
|
expectedEvent,
|
||||||
|
|||||||
Reference in New Issue
Block a user