Skip to content

Commit 882ee26

Browse files
authored
[kube] fixes duplicated session recordings in root and leaf clusters (#48740)
This PR addresses a bug in Kubernetes session recordings where both the root proxy and the leaf cluster's Kubernetes services were recording the same session, resulting in the session being available in both clusters. This behavior was inconsistent with other protocols, where recordings of leaf resources are only accessible in leaf clusters. To maintain consistency, this PR removes session recordings on the root clusters. Signed-off-by: Tiago Silva <tiago.silva@goteleport.com>
1 parent 378e901 commit 882ee26

File tree

7 files changed

+30
-28
lines changed

7 files changed

+30
-28
lines changed

integration/kube_integration_test.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -758,7 +758,7 @@ func testKubeTrustedClustersClientCert(t *testing.T, suite *KubeSuite) {
758758
loop:
759759
for {
760760
select {
761-
case event := <-main.UploadEventsC:
761+
case event := <-aux.UploadEventsC:
762762
sessionID = event.SessionID
763763
break loop
764764
case <-timeoutC:
@@ -767,7 +767,7 @@ loop:
767767
}
768768

769769
// read back the entire session and verify that it matches the stated output
770-
capturedStream, err := main.Process.GetAuthServer().GetSessionChunk(apidefaults.Namespace, session.ID(sessionID), 0, events.MaxChunkBytes)
770+
capturedStream, err := aux.Process.GetAuthServer().GetSessionChunk(apidefaults.Namespace, session.ID(sessionID), 0, events.MaxChunkBytes)
771771
require.NoError(t, err)
772772

773773
require.Equal(t, sessionStream, string(capturedStream))
@@ -1583,7 +1583,6 @@ func waitForContainer(ctx context.Context, podClient corev1client.PodInterface,
15831583
}
15841584

15851585
s := getContainerStatusByName(p, containerName)
1586-
fmt.Println("test", s)
15871586
if s == nil {
15881587
return false, nil
15891588
}

lib/kube/proxy/ephemeral_containers.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ func (f *Forwarder) ephemeralContainers(authCtx *authContext, w http.ResponseWri
104104
f.log.Errorf("Failed to set up forwarding headers: %v.", err)
105105
return nil, trace.Wrap(err)
106106
}
107-
if !f.isLocalKubeCluster(sess.teleportCluster.isRemote, sess.kubeClusterName) {
107+
if !sess.isLocalKubernetesCluster {
108108
sess.forwarder.ServeHTTP(w, req)
109109
return nil, nil
110110
}

lib/kube/proxy/forwarder.go

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,10 @@ type authContext struct {
438438
kubeServers []types.KubeServer
439439
// apiResource holds the information about the requested API resource.
440440
apiResource apiResource
441+
// isLocalKubernetesCluster is true if the target cluster is served by this teleport service.
442+
// It is false if the target cluster is served by another teleport service or a different
443+
// Teleport cluster.
444+
isLocalKubernetesCluster bool
441445
}
442446

443447
func (c authContext) String() string {
@@ -775,7 +779,8 @@ func (f *Forwarder) setupContext(
775779
return nil, trace.NotFound("Kubernetes cluster %q not found", kubeCluster)
776780
}
777781
}
778-
if f.isLocalKubeCluster(isRemoteCluster, kubeCluster) {
782+
isLocalKubernetesCluster := f.isLocalKubeCluster(isRemoteCluster, kubeCluster)
783+
if isLocalKubernetesCluster {
779784
kubeResource, apiResource, err = f.parseResourceFromRequest(req, kubeCluster)
780785
if err != nil {
781786
return nil, trace.Wrap(err)
@@ -809,10 +814,11 @@ func (f *Forwarder) setupContext(
809814
remoteAddr: utils.NetAddr{AddrNetwork: "tcp", Addr: req.RemoteAddr},
810815
isRemote: isRemoteCluster,
811816
},
812-
kubeServers: kubeServers,
813-
requestVerb: apiResource.getVerb(req),
814-
apiResource: apiResource,
815-
kubeResource: kubeResource,
817+
kubeServers: kubeServers,
818+
requestVerb: apiResource.getVerb(req),
819+
apiResource: apiResource,
820+
kubeResource: kubeResource,
821+
isLocalKubernetesCluster: isLocalKubernetesCluster,
816822
}, nil
817823
}
818824

@@ -865,9 +871,11 @@ func (f *Forwarder) emitAuditEvent(req *http.Request, sess *clusterSession, stat
865871
)
866872
defer span.End()
867873

868-
if sess.noAuditEvents {
874+
// If the session is not local, don't emit the event.
875+
if !sess.isLocalKubernetesCluster {
869876
return
870877
}
878+
871879
r := sess.apiResource
872880
if r.skipEvent {
873881
return
@@ -1161,7 +1169,7 @@ func (f *Forwarder) join(ctx *authContext, w http.ResponseWriter, req *http.Requ
11611169
return nil, trace.Wrap(err)
11621170
}
11631171

1164-
if !f.isLocalKubeCluster(ctx.teleportCluster.isRemote, ctx.kubeClusterName) {
1172+
if !sess.isLocalKubernetesCluster {
11651173
return f.remoteJoin(ctx, w, req, p, sess)
11661174
}
11671175

@@ -1658,7 +1666,7 @@ func (f *Forwarder) exec(authCtx *authContext, w http.ResponseWriter, req *http.
16581666
}
16591667
// proxy.Close closes the underlying connection and releases the resources.
16601668
defer proxy.Close()
1661-
if sess.noAuditEvents {
1669+
if !sess.isLocalKubernetesCluster {
16621670
// We're forwarding this to another kubernetes_service instance, let it handle multiplexing.
16631671
return f.remoteExec(authCtx, w, req, p, sess, request, proxy)
16641672
}
@@ -1777,7 +1785,7 @@ func (f *Forwarder) portForward(authCtx *authContext, w http.ResponseWriter, req
17771785
}
17781786

17791787
onPortForward := func(addr string, success bool) {
1780-
if sess.noAuditEvents {
1788+
if !sess.isLocalKubernetesCluster {
17811789
return
17821790
}
17831791
portForward := &apievents.PortForward{
@@ -2048,7 +2056,7 @@ func (f *Forwarder) catchAll(authCtx *authContext, w http.ResponseWriter, req *h
20482056
return nil, trace.Wrap(err)
20492057
}
20502058

2051-
isLocalKubeCluster := f.isLocalKubeCluster(sess.teleportCluster.isRemote, sess.kubeClusterName)
2059+
isLocalKubeCluster := sess.isLocalKubernetesCluster
20522060
isListRequest := authCtx.requestVerb == types.KubeVerbList
20532061
// Watch requests can be send to a single resource or to a collection of resources.
20542062
// isWatchingCollectionRequest is true when the request is a watch request and
@@ -2145,10 +2153,8 @@ type clusterSession struct {
21452153
// nil otherwise.
21462154
kubeAPICreds kubeCreds
21472155
forwarder *reverseproxy.Forwarder
2148-
// noAuditEvents is true if this teleport service should leave audit event
2149-
// logging to another service.
2150-
noAuditEvents bool
2151-
targetAddr string
2156+
// targetAddr is the address of the target cluster.
2157+
targetAddr string
21522158
// kubeAddress is the address of this session's active connection (if there is one)
21532159
kubeAddress string
21542160
// upgradeToHTTP2 indicates whether the transport should be configured to use HTTP2.
@@ -2357,11 +2363,8 @@ func (f *Forwarder) newClusterSessionLocal(ctx context.Context, authCtx authCont
23572363
func (f *Forwarder) newClusterSessionDirect(ctx context.Context, authCtx authContext) (*clusterSession, error) {
23582364
connCtx, cancel := context.WithCancelCause(ctx)
23592365
return &clusterSession{
2360-
parent: f,
2361-
authContext: authCtx,
2362-
// This session talks to a kubernetes_service, which should handle
2363-
// audit logging. Avoid duplicate logging.
2364-
noAuditEvents: true,
2366+
parent: f,
2367+
authContext: authCtx,
23652368
requestContext: ctx,
23662369
connCtx: connCtx,
23672370
connMonitorCancel: cancel,
@@ -2385,7 +2388,7 @@ func (f *Forwarder) makeSessionForwarder(sess *clusterSession) (*reverseproxy.Fo
23852388
reverseproxy.WithLogger(f.log),
23862389
reverseproxy.WithErrorHandler(f.formatForwardResponseError),
23872390
}
2388-
if f.isLocalKubeCluster(sess.teleportCluster.isRemote, sess.kubeClusterName) {
2391+
if sess.isLocalKubernetesCluster {
23892392
// If the target cluster is local, i.e. the cluster that is served by this
23902393
// teleport service, then we set up the forwarder to allow re-writing
23912394
// the response to the client to include user friendly error messages.

lib/kube/proxy/resource_deletecollection.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ func (f *Forwarder) deleteResourcesCollection(sess *clusterSession, w http.Respo
6060
defer span.End()
6161
req = req.WithContext(ctx)
6262
var (
63-
isLocalKubeCluster = f.isLocalKubeCluster(sess.teleportCluster.isRemote, sess.kubeClusterName)
63+
isLocalKubeCluster = sess.isLocalKubernetesCluster
6464
kubeObjType string
6565
namespace string
6666
)

lib/kube/proxy/resource_list.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ func (f *Forwarder) listResources(sess *clusterSession, w http.ResponseWriter, r
5050

5151
req = req.WithContext(ctx)
5252

53-
isLocalKubeCluster := f.isLocalKubeCluster(sess.teleportCluster.isRemote, sess.kubeClusterName)
53+
isLocalKubeCluster := sess.isLocalKubernetesCluster
5454
supportsType := false
5555
if isLocalKubeCluster {
5656
_, supportsType = sess.rbacSupportedResources.getTeleportResourceKindFromAPIResource(sess.apiResource)

lib/kube/proxy/self_subject_reviews.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ func (f *Forwarder) selfSubjectAccessReviews(authCtx *authContext, w http.Respon
7676

7777
// only allow self subject access reviews for the service that proxies the
7878
// request to the kubernetes API server.
79-
if f.isLocalKubeCluster(sess.teleportCluster.isRemote, sess.kubeClusterName) {
79+
if sess.isLocalKubernetesCluster {
8080
if err := f.validateSelfSubjectAccessReview(sess, w, req); trace.IsAccessDenied(err) {
8181
return nil, nil
8282
} else if err != nil {

lib/kube/proxy/sess.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -729,7 +729,7 @@ func (s *session) lockedSetupLaunch(request *remoteCommandRequest, eventPodMeta
729729
s.started = true
730730
sessionStart := s.forwarder.cfg.Clock.Now().UTC()
731731

732-
if !s.sess.noAuditEvents {
732+
if s.sess.isLocalKubernetesCluster {
733733
s.terminalSizeQueue.callback = func(termSize terminalResizeMessage) {
734734
s.mu.Lock()
735735
defer s.mu.Unlock()

0 commit comments

Comments
 (0)