Skip to content

Commit e76c8dc

Browse files
[v18] use new join service for host and bot joins (#60293)
* [v18] use new join service for bot joins Backport #59550 to branch/v18 * [v18] use new join service for host joins Backport #59778 to branch/v18 * [v18] heal instance identity by re-joining via new join service Backport #59872 to branch/v18 * use set from utils package in v18 * [v18] fix: keep instance host ID when healing identity Backport #60706 to branch/v18 * [v18] avoid join fallback attempts on legitimate join failure Backport #60673 to branch/v18 * [v18] fix: deflake connection problem detection during joining Backport #60896 to branch/v18 --------- Co-authored-by: Forrest <30576607+fspmarshall@users.noreply.github.com>
1 parent 72cb1be commit e76c8dc

File tree

13 files changed

+522
-160
lines changed

13 files changed

+522
-160
lines changed

integration/proxy/proxy_helpers.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,10 @@ import (
5252
"github.com/gravitational/teleport/api/utils/retryutils"
5353
"github.com/gravitational/teleport/integration/helpers"
5454
"github.com/gravitational/teleport/lib"
55-
"github.com/gravitational/teleport/lib/auth/join"
5655
"github.com/gravitational/teleport/lib/auth/state"
5756
"github.com/gravitational/teleport/lib/client"
5857
"github.com/gravitational/teleport/lib/defaults"
58+
"github.com/gravitational/teleport/lib/join/joinclient"
5959
"github.com/gravitational/teleport/lib/kube/kubeconfig"
6060
testingkubemock "github.com/gravitational/teleport/lib/kube/proxy/testing/kube_server"
6161
"github.com/gravitational/teleport/lib/reversetunnelclient"
@@ -653,11 +653,10 @@ func mustRegisterUsingIAMMethod(t *testing.T, proxyAddr utils.NetAddr, token str
653653
t.Setenv("AWS_REGION", "us-west-2")
654654

655655
node := uuid.NewString()
656-
_, err = join.Register(context.TODO(), join.RegisterParams{
656+
_, err = joinclient.Join(t.Context(), joinclient.JoinParams{
657657
Token: token,
658658
ID: state.IdentityID{
659-
Role: types.RoleNode,
660-
HostUUID: node,
659+
Role: types.RoleInstance,
661660
NodeName: node,
662661
},
663662
ProxyServer: proxyAddr,

lib/auth/bot_test.go

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,6 @@ import (
6060
"github.com/gravitational/teleport/lib/auth"
6161
"github.com/gravitational/teleport/lib/auth/authclient"
6262
"github.com/gravitational/teleport/lib/auth/authtest"
63-
"github.com/gravitational/teleport/lib/auth/join"
6463
"github.com/gravitational/teleport/lib/auth/machineid/machineidv1"
6564
"github.com/gravitational/teleport/lib/auth/state"
6665
"github.com/gravitational/teleport/lib/auth/testauthority"
@@ -69,6 +68,7 @@ import (
6968
"github.com/gravitational/teleport/lib/events/eventstest"
7069
"github.com/gravitational/teleport/lib/fixtures"
7170
"github.com/gravitational/teleport/lib/join/iamjoin"
71+
"github.com/gravitational/teleport/lib/join/joinclient"
7272
"github.com/gravitational/teleport/lib/kube/token"
7373
"github.com/gravitational/teleport/lib/oidc/fakeissuer"
7474
"github.com/gravitational/teleport/lib/reversetunnelclient"
@@ -158,7 +158,7 @@ func TestRegisterBotCertificateGenerationCheck(t *testing.T) {
158158
require.NoError(t, err)
159159
require.NoError(t, client.CreateToken(ctx, token))
160160

161-
result, err := join.Register(ctx, join.RegisterParams{
161+
result, err := joinclient.Join(ctx, joinclient.JoinParams{
162162
Token: token.GetName(),
163163
ID: state.IdentityID{
164164
Role: types.RoleBot,
@@ -298,7 +298,7 @@ func TestBotJoinAttrs_Kubernetes(t *testing.T) {
298298
require.NoError(t, err)
299299
require.NoError(t, client.CreateToken(ctx, tok))
300300

301-
result, err := join.Register(ctx, join.RegisterParams{
301+
result, err := joinclient.Join(ctx, joinclient.JoinParams{
302302
Token: tok.GetName(),
303303
JoinMethod: types.JoinMethodKubernetes,
304304
ID: state.IdentityID{
@@ -410,7 +410,7 @@ func TestRegisterBotInstance(t *testing.T) {
410410
require.NoError(t, err)
411411
require.NoError(t, client.CreateToken(ctx, token))
412412

413-
result, err := join.Register(ctx, join.RegisterParams{
413+
result, err := joinclient.Join(ctx, joinclient.JoinParams{
414414
Token: token.GetName(),
415415
ID: state.IdentityID{
416416
Role: types.RoleBot,
@@ -556,7 +556,7 @@ func TestRegisterBotCertificateGenerationStolen(t *testing.T) {
556556
require.NoError(t, err)
557557
require.NoError(t, client.CreateToken(ctx, token))
558558

559-
result, err := join.Register(ctx, join.RegisterParams{
559+
result, err := joinclient.Join(ctx, joinclient.JoinParams{
560560
Token: token.GetName(),
561561
ID: state.IdentityID{
562562
Role: types.RoleBot,
@@ -632,7 +632,7 @@ func TestRegisterBotCertificateExtensions(t *testing.T) {
632632
require.NoError(t, err)
633633
require.NoError(t, client.CreateToken(ctx, token))
634634

635-
result, err := join.Register(ctx, join.RegisterParams{
635+
result, err := joinclient.Join(ctx, joinclient.JoinParams{
636636
Token: token.GetName(),
637637
ID: state.IdentityID{
638638
Role: types.RoleBot,
@@ -875,8 +875,8 @@ func defaultIdentityRequestTemplateInput(challenge string) identityRequestTempla
875875
}
876876

877877
// authClientForRegisterResult is a test helper that creats an auth client for
878-
// the given [*join.RegisterResult].
879-
func authClientForRegisterResult(t *testing.T, ctx context.Context, addr *utils.NetAddr, result *join.RegisterResult) *authclient.Client {
878+
// the given [*joinclient.JoinResult].
879+
func authClientForRegisterResult(t *testing.T, ctx context.Context, addr *utils.NetAddr, result *joinclient.JoinResult) *authclient.Client {
880880
privateKeyPEM, err := keys.MarshalPrivateKey(result.PrivateKey)
881881
require.NoError(t, err)
882882
sshPub, err := ssh.NewPublicKey(result.PrivateKey.Public())
@@ -947,14 +947,14 @@ func instanceIDFromCerts(t *testing.T, certs *proto.Certs) (string, uint64) {
947947
return ident.BotInstanceID, ident.Generation
948948
}
949949

950-
// registerHelper calls `join.Register` with the given token, prefilling params
950+
// registerHelper calls `joinclient.Join` with the given token, prefilling params
951951
// where possible. Overrides may be applied with `fns`.
952952
func registerHelper(
953953
ctx context.Context, token types.ProvisionToken,
954954
addr *utils.NetAddr,
955-
fns ...func(*join.RegisterParams),
956-
) (*join.RegisterResult, error) {
957-
params := join.RegisterParams{
955+
fns ...func(*joinclient.JoinParams),
956+
) (*joinclient.JoinResult, error) {
957+
params := joinclient.JoinParams{
958958
JoinMethod: token.GetJoinMethod(),
959959
Token: token.GetName(),
960960
ID: state.IdentityID{
@@ -970,7 +970,7 @@ func registerHelper(
970970
fn(&params)
971971
}
972972

973-
result, err := join.Register(ctx, params)
973+
result, err := joinclient.Join(ctx, params)
974974
return result, trace.Wrap(err)
975975
}
976976

@@ -1067,7 +1067,7 @@ func TestRegisterBot_BotInstanceRejoin(t *testing.T) {
10671067
require.NoError(t, a.UpsertToken(ctx, awsToken))
10681068

10691069
// Join as a "bot" with both token types.
1070-
k8sResult, err := registerHelper(ctx, k8sToken, addr, func(p *join.RegisterParams) {
1070+
k8sResult, err := registerHelper(ctx, k8sToken, addr, func(p *joinclient.JoinParams) {
10711071
p.KubernetesReadFileFunc = k8sReadFileFunc
10721072
})
10731073
require.NoError(t, err)
@@ -1087,7 +1087,7 @@ func TestRegisterBot_BotInstanceRejoin(t *testing.T) {
10871087
// Rejoin using the k8s client and make sure we're issued certs with the
10881088
// same instance ID.
10891089
k8sClient := authClientForRegisterResult(t, ctx, addr, k8sResult)
1090-
rejoinedK8sResult, err := registerHelper(ctx, k8sToken, addr, func(p *join.RegisterParams) {
1090+
rejoinedK8sResult, err := registerHelper(ctx, k8sToken, addr, func(p *joinclient.JoinParams) {
10911091
p.KubernetesReadFileFunc = k8sReadFileFunc
10921092
p.AuthClient = k8sClient
10931093
})
@@ -1101,7 +1101,7 @@ func TestRegisterBot_BotInstanceRejoin(t *testing.T) {
11011101
// join service, the instance ID must be provided to auth by the proxy as
11021102
// part of the `RegisterUsingTokenRequest`.
11031103
iamClient := authClientForRegisterResult(t, ctx, addr, awsResult)
1104-
rejoinedAWSResult, err := registerHelper(ctx, awsToken, addr, func(p *join.RegisterParams) {
1104+
rejoinedAWSResult, err := registerHelper(ctx, awsToken, addr, func(p *joinclient.JoinParams) {
11051105
p.AuthClient = iamClient
11061106
})
11071107
require.NoError(t, err)
@@ -1281,7 +1281,7 @@ func TestRegisterBotMultipleTokens(t *testing.T) {
12811281
require.NoError(t, err)
12821282
require.NoError(t, client.CreateToken(ctx, tokenB))
12831283

1284-
resultA, err := join.Register(ctx, join.RegisterParams{
1284+
resultA, err := joinclient.Join(ctx, joinclient.JoinParams{
12851285
Token: tokenA.GetName(),
12861286
ID: state.IdentityID{
12871287
Role: types.RoleBot,
@@ -1294,7 +1294,7 @@ func TestRegisterBotMultipleTokens(t *testing.T) {
12941294
initialInstanceA, _ := instanceIDFromCerts(t, certsA)
12951295
require.NotEmpty(t, initialInstanceA)
12961296

1297-
resultB, err := join.Register(ctx, join.RegisterParams{
1297+
resultB, err := joinclient.Join(ctx, joinclient.JoinParams{
12981298
Token: tokenB.GetName(),
12991299
ID: state.IdentityID{
13001300
Role: types.RoleBot,

lib/auth/join/join.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,10 @@ type RegisterResult struct {
286286
// running on a different host than the auth server. This method requires a
287287
// provision token that will be used to authenticate as an identity that should
288288
// be allowed to join the cluster.
289+
//
290+
// Deprecated: this function is superceded by lib/join/joinclient.Join
291+
//
292+
// TODO(nklaassen): DELETE IN 20
289293
func Register(ctx context.Context, params RegisterParams) (result *RegisterResult, err error) {
290294
ctx, span := tracer.Start(ctx, "Register")
291295
defer func() { tracing.EndSpan(span, err) }()

lib/auth/join_test.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,12 @@ import (
3636
"github.com/gravitational/teleport/api/utils/sshutils"
3737
"github.com/gravitational/teleport/lib/auth"
3838
"github.com/gravitational/teleport/lib/auth/authtest"
39-
"github.com/gravitational/teleport/lib/auth/join"
4039
"github.com/gravitational/teleport/lib/auth/machineid/machineidv1"
4140
"github.com/gravitational/teleport/lib/auth/state"
4241
"github.com/gravitational/teleport/lib/auth/testauthority"
4342
"github.com/gravitational/teleport/lib/defaults"
4443
"github.com/gravitational/teleport/lib/events"
44+
"github.com/gravitational/teleport/lib/join/joinclient"
4545
"github.com/gravitational/teleport/lib/tlsca"
4646
"github.com/gravitational/teleport/lib/utils"
4747
)
@@ -299,9 +299,9 @@ func newBotToken(t *testing.T, tokenName, botName string, role types.SystemRole,
299299
return token
300300
}
301301

302-
// TestRegister_Bot tests that a provision token can be used to generate
302+
// TestJoin_Bot tests that a provision token can be used to generate
303303
// renewable certificates for a non-interactive user.
304-
func TestRegister_Bot(t *testing.T) {
304+
func TestJoin_Bot(t *testing.T) {
305305
t.Parallel()
306306
ctx := context.Background()
307307

@@ -369,7 +369,7 @@ func TestRegister_Bot(t *testing.T) {
369369
} {
370370
t.Run(test.desc, func(t *testing.T) {
371371
start := srv.Clock().Now()
372-
result, err := join.Register(ctx, join.RegisterParams{
372+
result, err := joinclient.Join(ctx, joinclient.JoinParams{
373373
Token: test.token.GetName(),
374374
ID: state.IdentityID{
375375
Role: types.RoleBot,
@@ -413,9 +413,9 @@ func TestRegister_Bot(t *testing.T) {
413413
}
414414
}
415415

416-
// TestRegister_Bot_Expiry checks that bot certificate expiry can be set, and
416+
// TestJoin_Bot_Expiry checks that bot certificate expiry can be set, and
417417
// does not exceed the limit.
418-
func TestRegister_Bot_Expiry(t *testing.T) {
418+
func TestJoin_Bot_Expiry(t *testing.T) {
419419
t.Parallel()
420420
ctx := context.Background()
421421

@@ -465,7 +465,7 @@ func TestRegister_Bot_Expiry(t *testing.T) {
465465
tok := newBotToken(t, uuid.NewString(), botName, types.RoleBot, srv.Clock().Now().Add(time.Hour))
466466
require.NoError(t, srv.Auth().UpsertToken(ctx, tok))
467467

468-
result, err := join.Register(ctx, join.RegisterParams{
468+
result, err := joinclient.Join(ctx, joinclient.JoinParams{
469469
Token: tok.GetName(),
470470
ID: state.IdentityID{
471471
Role: types.RoleBot,

lib/auth/machineid/workloadidentityv1/workloadidentityv1_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,12 @@ import (
5656
"github.com/gravitational/teleport/api/utils/keys"
5757
"github.com/gravitational/teleport/lib/auth/authclient"
5858
"github.com/gravitational/teleport/lib/auth/authtest"
59-
"github.com/gravitational/teleport/lib/auth/join"
6059
"github.com/gravitational/teleport/lib/auth/machineid/workloadidentityv1"
6160
"github.com/gravitational/teleport/lib/auth/state"
6261
"github.com/gravitational/teleport/lib/cryptosuites"
6362
libevents "github.com/gravitational/teleport/lib/events"
6463
"github.com/gravitational/teleport/lib/events/eventstest"
64+
"github.com/gravitational/teleport/lib/join/joinclient"
6565
libjwt "github.com/gravitational/teleport/lib/jwt"
6666
"github.com/gravitational/teleport/lib/modules"
6767
"github.com/gravitational/teleport/lib/oidc/fakeissuer"
@@ -298,7 +298,7 @@ func TestIssueWorkloadIdentityE2E(t *testing.T) {
298298
require.NoError(t, err)
299299

300300
// With the basic setup complete, we can now "fake" a join.
301-
botCerts, err := join.Register(ctx, join.RegisterParams{
301+
botCerts, err := joinclient.Join(ctx, joinclient.JoinParams{
302302
Token: token.GetName(),
303303
JoinMethod: types.JoinMethodKubernetes,
304304
ID: state.IdentityID{

lib/auth/storage/storage.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,31 @@ func readHostIDFromStorages(ctx context.Context, dataDir string, kubeBackend sta
382382
return hostID, trace.Wrap(err)
383383
}
384384

385+
// PersistAssignedHostID writes an assigned host ID to state storage and the
386+
// host_uuid file. This should not be called in the same process as
387+
// ReadOrGenerateHostID, it is intended to persist a host UUID assigned by the
388+
// Auth service that was not generated locally. With the new auth-assigned host
389+
// persisted to storage to maintain compatibility with any other processes that
390+
// UUID flow the agent doesn't even need to read the host ID, it is only
391+
// may read it.
392+
func (p *ProcessStorage) PersistAssignedHostID(ctx context.Context, cfg *servicecfg.Config, hostID string) error {
393+
if p.stateStorage != nil {
394+
if _, err := p.stateStorage.Put(
395+
ctx,
396+
backend.Item{
397+
Key: backend.NewKey(hostid.FileName),
398+
Value: []byte(hostID),
399+
},
400+
); err != nil {
401+
return trace.Wrap(err, "persisting host ID to state storage")
402+
}
403+
}
404+
if err := hostid.WriteFile(cfg.DataDir, hostID); err != nil {
405+
return trace.Wrap(err, "persisting host ID to file")
406+
}
407+
return nil
408+
}
409+
385410
// persistHostIDToStorages writes the host ID to local data and to
386411
// Kubernetes Secret if this process is running on a Kubernetes Cluster.
387412
func persistHostIDToStorages(ctx context.Context, cfg *servicecfg.Config, hostID string, kubeBackend stateBackend) error {

0 commit comments

Comments
 (0)