From 635f7e1f72cc2587d0231e2d988dfdad4a5b9c52 Mon Sep 17 00:00:00 2001 From: Tim Ross Date: Thu, 8 Feb 2024 12:55:36 -0500 Subject: [PATCH] Prevent leaking gRPC clients when connecting to the cluster fails There are a few scenarios during agent registration that may result in an auth client being created but never closed. One particular scenario that can hit this path is a v12 agent trying to join a >=v14 control plane. The first thing agents do after validating that the client was created succesfully is retrieve the Host CA for the cluster. If that fails then the error is returned but the client is never closed and the agent will try connecting again in the future. This behavior is particularly troublesome because in v12 the API responsible for that was the auth HTTP API, in V13 it was deprecated in favor of a gRPC API and in v14 the HTTP API was removed entirely. So any v12 agents trying to connect to a >=v14 control plane will continuously fail getting the Host CA because the HTTP request they issue will result in a 404. --- lib/service/connect.go | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/lib/service/connect.go b/lib/service/connect.go index aa386697ab3f3..4f7467a7af72d 100644 --- a/lib/service/connect.go +++ b/lib/service/connect.go @@ -543,21 +543,19 @@ func (process *TeleportProcess) firstTimeConnect(role types.SystemRole) (*Connec Type: types.HostCA, }, false) if err != nil { - return nil, trace.Wrap(err) + return nil, trace.NewAggregate(err, connector.Close()) } - err = process.storage.WriteIdentity(auth.IdentityCurrent, *identity) - if err != nil { + if err := process.storage.WriteIdentity(auth.IdentityCurrent, *identity); err != nil { process.log.Warningf("Failed to write %v identity: %v.", role, err) } - err = process.storage.WriteState(role, auth.StateV2{ + if err := process.storage.WriteState(role, auth.StateV2{ Spec: auth.StateSpecV2{ Rotation: ca.GetRotation(), }, - }) - if err != nil { - return nil, trace.Wrap(err) + }); err != nil { + return nil, trace.NewAggregate(err, connector.Close()) } process.log.Infof("The process successfully wrote the credentials and state of %v to the disk.", role) return connector, nil