From ef1542931cce06ae4794fe782a0338a3dc505b73 Mon Sep 17 00:00:00 2001 From: Tim Buckley Date: Thu, 10 Mar 2022 15:08:07 -0700 Subject: [PATCH] Fix meaning of `bot_name` in bot join tokens (#11039) The `BotName` / `bot_name` was previously used to refer to the bot _username_ rather than the bot name as entered by users. This leads to confusion as the username is an implemention detail not obviously visible to users. This changes the meaning of the `bot_name` parameter to instead consistently accept a bot name, which is converted to a username on the backend where needed. --- lib/auth/bot.go | 8 ++++---- lib/auth/join.go | 7 +++++-- lib/auth/join_test.go | 15 +++++++++------ 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/lib/auth/bot.go b/lib/auth/bot.go index cbc0ddc729478..bfd01c7287537 100644 --- a/lib/auth/bot.go +++ b/lib/auth/bot.go @@ -242,7 +242,7 @@ func (s *Server) getBotUsers(ctx context.Context) ([]types.User, error) { // random dynamic provision token which allows bots to join with the given // botName. Returns the token and any error. func (s *Server) checkOrCreateBotToken(ctx context.Context, req *proto.CreateBotRequest) (types.ProvisionToken, error) { - resourceName := BotResourceName(req.Name) + botName := req.Name // if the request includes a TokenID it should already exist if req.TokenID != "" { @@ -258,9 +258,9 @@ func (s *Server) checkOrCreateBotToken(ctx context.Context, req *proto.CreateBot return nil, trace.BadParameter("token %q is not valid for role %q", req.TokenID, types.RoleBot) } - if provisionToken.GetBotName() != resourceName { + if provisionToken.GetBotName() != botName { return nil, trace.BadParameter("token %q is valid for bot with name %q, not %q", - req.TokenID, provisionToken.GetBotName(), resourceName) + req.TokenID, provisionToken.GetBotName(), botName) } switch provisionToken.GetJoinMethod() { case types.JoinMethodToken, types.JoinMethodIAM: @@ -286,7 +286,7 @@ func (s *Server) checkOrCreateBotToken(ctx context.Context, req *proto.CreateBot tokenSpec := types.ProvisionTokenSpecV2{ Roles: []types.SystemRole{types.RoleBot}, JoinMethod: types.JoinMethodToken, - BotName: resourceName, + BotName: botName, } token, err := types.NewProvisionTokenFromSpec(tokenName, time.Now().Add(ttl), tokenSpec) if err != nil { diff --git a/lib/auth/join.go b/lib/auth/join.go index 6c0754034a8db..c50401c55713f 100644 --- a/lib/auth/join.go +++ b/lib/auth/join.go @@ -108,7 +108,10 @@ func (a *Server) generateCerts(ctx context.Context, provisionToken types.Provisi if req.Role == types.RoleBot { // bots use this endpoint but get a user cert // botResourceName must be set, enforced in CheckAndSetDefaults - botResourceName := provisionToken.GetBotName() + botName := provisionToken.GetBotName() + + // Append `bot-` to the bot name to derive its username. + botResourceName := BotResourceName(botName) expires := a.GetClock().Now().Add(defaults.DefaultRenewableCertTTL) joinMethod := provisionToken.GetJoinMethod() @@ -141,7 +144,7 @@ func (a *Server) generateCerts(ctx context.Context, provisionToken types.Provisi return nil, trace.BadParameter("unsupported join method %q for bot", joinMethod) } - log.Infof("Bot %q has joined the cluster.", botResourceName) + log.Infof("Bot %q has joined the cluster.", botName) return certs, nil } // generate and return host certificate and keys diff --git a/lib/auth/join_test.go b/lib/auth/join_test.go index f6c8b04f32e26..55654b9f06ce2 100644 --- a/lib/auth/join_test.go +++ b/lib/auth/join_test.go @@ -254,11 +254,11 @@ func TestAuth_RegisterUsingToken(t *testing.T) { } } -func newBotToken(t *testing.T, tokenName, user string, role types.SystemRole, expiry time.Time) types.ProvisionToken { +func newBotToken(t *testing.T, tokenName, botName string, role types.SystemRole, expiry time.Time) types.ProvisionToken { t.Helper() token, err := types.NewProvisionTokenFromSpec(tokenName, expiry, types.ProvisionTokenSpecV2{ Roles: []types.SystemRole{role}, - BotName: user, + BotName: botName, }) require.NoError(t, err, "could not create bot token") return token @@ -271,19 +271,22 @@ func TestRegister_Bot(t *testing.T) { srv := newTestTLSServer(t) + botName := "test" + botResourceName := BotResourceName(botName) + _, err := createBotRole(context.Background(), srv.Auth(), "test", "bot-test", []string{}) require.NoError(t, err) - user, err := createBotUser(context.Background(), srv.Auth(), "test", "bot-test") + _, err = createBotUser(context.Background(), srv.Auth(), botName, botResourceName) require.NoError(t, err) later := srv.Clock().Now().Add(4 * time.Hour) - goodToken := newBotToken(t, "good-token", user.GetName(), types.RoleBot, later) - expiredToken := newBotToken(t, "expired", user.GetName(), types.RoleBot, srv.Clock().Now().Add(-1*time.Hour)) + goodToken := newBotToken(t, "good-token", botName, types.RoleBot, later) + expiredToken := newBotToken(t, "expired", botName, types.RoleBot, srv.Clock().Now().Add(-1*time.Hour)) wrongKind := newBotToken(t, "wrong-kind", "", types.RoleNode, later) wrongUser := newBotToken(t, "wrong-user", "llama", types.RoleBot, later) - invalidToken := newBotToken(t, "this-token-does-not-exist", user.GetName(), types.RoleBot, later) + invalidToken := newBotToken(t, "this-token-does-not-exist", botName, types.RoleBot, later) err = srv.Auth().UpsertToken(context.Background(), goodToken) require.NoError(t, err)