From 510859bfb857301ec25de58d48af6efd0cd4964a Mon Sep 17 00:00:00 2001 From: rosstimothy <39066650+rosstimothy@users.noreply.github.com> Date: Thu, 18 Jun 2026 12:17:40 -0400 Subject: [PATCH] Improve Scoped Token UX (#67819) Removes any externally visibile notions to end users that a token name and token secret are two different entities. This removes the need to output a token_name and token_secret value from `tctl scoped tokens add` as well as removing the token_secret from teleport.yaml and teleport CLIs. Internally, the name of a scoped_token is still NOT a secret. The secret is a separate field in the scoped_token.status. When the token is presented to a user it is done so as `:` and `:` This does contain a few breaking changes. The token_secret has been removed from the teleport.yaml file config and its equivalent CLI flags have been removed. Since scopes are still under active development and this only impacts scoped_tokens and not traditional tokens the impact of this change should be minimal. --- docs/pages/reference/cli/teleport.mdx | 2 - .../rbac-get-started/scopes.mdx | 8 ++-- lib/config/configuration.go | 13 ------ lib/config/fileconf.go | 1 - lib/scopes/joining/token.go | 27 +++++++++++++ lib/scopes/joining/token_test.go | 24 +++++++++++ lib/service/connect.go | 11 +++-- lib/service/servicecfg/config.go | 28 ------------- lib/tbot/tbot_test.go | 6 +-- lib/web/join_tokens.go | 8 +++- tool/tctl/common/resource_command_test.go | 12 ++++++ tool/tctl/common/resources/scoped_token.go | 16 ++++---- tool/tctl/common/scoped_ref.go | 16 ++++++-- tool/tctl/common/scoped_token_command.go | 19 ++++----- tool/tctl/common/token_command.go | 40 +++++++++---------- tool/teleport/common/teleport.go | 3 -- 16 files changed, 131 insertions(+), 103 deletions(-) diff --git a/docs/pages/reference/cli/teleport.mdx b/docs/pages/reference/cli/teleport.mdx index 1d6a14f5625..aadf6e9fb7a 100644 --- a/docs/pages/reference/cli/teleport.mdx +++ b/docs/pages/reference/cli/teleport.mdx @@ -802,7 +802,6 @@ Flags: |`--sshd-check-command`|`sshd -t -f`|Command to use when checking OpenSSH config for validity. (sshd -t -f \)| |`--sshd-restart-command`|*no default*|Command to use when restarting openssh.| |`--token`|*no default*|Invitation token or path to file with token value to register with an auth server.| -|`--token-secret`|*no default*|Invitation token secret or path to file with secret value. Used to register with an auth server \[none\]| ## teleport node configure @@ -867,7 +866,6 @@ Flags: |`--pid-file`|*no default*|Full path to the PID file. By default no PID file will be created| |`-r`, `--roles`|*no default*|Comma-separated list of roles to start with \[proxy,node,auth,app,db\]| |`--token`|*no default*|Invitation token or path to file with token value. Used to register with an auth server \[none\]| -|`--token-secret`|*no default*|Invitation token secret or path to file with secret value. Used to register with an auth server \[none\]| ## teleport status diff --git a/docs/pages/zero-trust-access/rbac-get-started/scopes.mdx b/docs/pages/zero-trust-access/rbac-get-started/scopes.mdx index 70e3abbeb5f..e97930cf12d 100644 --- a/docs/pages/zero-trust-access/rbac-get-started/scopes.mdx +++ b/docs/pages/zero-trust-access/rbac-get-started/scopes.mdx @@ -310,8 +310,7 @@ Run this on the new node to join the cluster: > teleport start \ --roles=node \ - --token=019ce8f7-f0d5-784d-af3f-075aa79c19cb \ - --token-secret=d5038b4ea0a733cccfc3f0f48ee04baf \ + --token=019ce8f7-f0d5-784d-af3f-075aa79c19cb~YzZlYzdlYTg1YTZjZTEwZjVjYjAxMTc3Mjc2NTk3NGY \ --auth-server=proxy.example.com:443 ``` @@ -334,8 +333,7 @@ spec: roles: - Node usage_mode: unlimited -status: - secret: '******' +status: {} version: v1 ``` @@ -395,7 +393,7 @@ spec: - Node usage_mode: single_use status: - secret: '******' + secret: {} usage: single_use: reusable_until: "2026-03-13T21:44:05.695268Z" diff --git a/lib/config/configuration.go b/lib/config/configuration.go index 5e85121b0c7..c9540d0d54f 100644 --- a/lib/config/configuration.go +++ b/lib/config/configuration.go @@ -83,8 +83,6 @@ type CommandLineFlags struct { AuthServerAddr []string // --token flag AuthToken string - // --token-secret flag - TokenSecret string // --join-method flag JoinMethod string // CAPins are the SKPI hashes of the CAs used to verify the Auth Server. @@ -2966,11 +2964,6 @@ func Configure(clf *CommandLineFlags, cfg *servicecfg.Config, legacyAppFlags boo cfg.SetToken(clf.AuthToken) } - if clf.TokenSecret != "" { - // store the value of the --token-secret flag: - cfg.SetTokenSecret(clf.TokenSecret) - } - // Apply flags used for the node to validate the Auth Server. if err = cfg.ApplyCAPins(clf.CAPins); err != nil { return trace.Wrap(err) @@ -3078,11 +3071,6 @@ func ConfigureOpenSSH(clf *CommandLineFlags, cfg *servicecfg.Config) error { cfg.SetToken(clf.AuthToken) } - if clf.TokenSecret != "" { - // store the value of the --token-secret flag: - cfg.SetTokenSecret(clf.TokenSecret) - } - // apply --skip-version-check flag. if clf.SkipVersionCheck { cfg.SkipVersionCheck = clf.SkipVersionCheck @@ -3284,7 +3272,6 @@ func applyTokenConfig(fc *FileConfig, cfg *servicecfg.Config) error { if fc.JoinParams != (JoinParams{}) { cfg.SetToken(fc.JoinParams.TokenName) - cfg.SetTokenSecret(fc.JoinParams.TokenSecret) if err := types.ValidateJoinMethod(fc.JoinParams.Method); err != nil { return trace.Wrap(err) diff --git a/lib/config/fileconf.go b/lib/config/fileconf.go index f8a32f0e5d8..b631e25c6e6 100644 --- a/lib/config/fileconf.go +++ b/lib/config/fileconf.go @@ -510,7 +510,6 @@ func (conf *FileConfig) CheckAndSetDefaults() error { // JoinParams configures the parameters for Simplified Node Joining. type JoinParams struct { TokenName string `yaml:"token_name"` - TokenSecret string `yaml:"token_secret,omitempty"` Method types.JoinMethod `yaml:"method"` Azure AzureJoinParams `yaml:"azure,omitempty"` BoundKeypair BoundKeypairParams `yaml:"bound_keypair,omitempty"` diff --git a/lib/scopes/joining/token.go b/lib/scopes/joining/token.go index 5fe8f9010ee..4c6cfc6fb31 100644 --- a/lib/scopes/joining/token.go +++ b/lib/scopes/joining/token.go @@ -19,6 +19,7 @@ package joining import ( "cmp" "crypto/sha256" + "encoding/base64" "encoding/binary" "encoding/hex" "net/url" @@ -402,6 +403,8 @@ func StrongValidateToken(token *joiningv1.ScopedToken) error { } if name := token.GetMetadata().GetName(); name == "" { return trace.BadParameter("missing name") + } else if strings.Contains(name, ":") { + return trace.BadParameter("scoped token names cannot contain colons") } if token.GetScope() == "" { @@ -976,3 +979,27 @@ func VerifyImmutableLabelsHash(labels *joiningv1.ImmutableLabels, hash string) b newHash := HashImmutableLabels(labels) return newHash == hash } + +const tokenNameAndSecretSeparator = ":" + +// EncodeScopedToken combines a token name and secret into a single encoded value. The encoded +// tokens are used when providing tokens externally to end users to ease UX. +func EncodeScopedToken(name, secret string) string { + return name + tokenNameAndSecretSeparator + base64.RawURLEncoding.EncodeToString([]byte(secret)) +} + +// DecodeScopedToken produces a token name and secret from an encoded value. If the token +// is not encoded the return value is token, "", false. +func DecodeScopedToken(token string) (name string, secret string, ok bool) { + name, base64Secret, ok := strings.Cut(token, tokenNameAndSecretSeparator) + if !ok { + return token, "", false + } + + s, err := base64.RawURLEncoding.DecodeString(base64Secret) + if err != nil { + return token, "", false + } + + return name, string(s), true +} diff --git a/lib/scopes/joining/token_test.go b/lib/scopes/joining/token_test.go index bb90ff4e5e3..ced1270478e 100644 --- a/lib/scopes/joining/token_test.go +++ b/lib/scopes/joining/token_test.go @@ -18,6 +18,7 @@ package joining_test import ( "cmp" + "encoding/base64" "fmt" "maps" "testing" @@ -1040,6 +1041,14 @@ func TestValidateScopedToken(t *testing.T) { }, expectedStrongErr: "scoped bot tokens do not support the `token` join method", }, + { + name: "tokens with semicolons are prevented", + baseToken: baseToken, + modFn: func(st *joiningv1.ScopedToken) { + st.GetMetadata().SetName("testing:testing") + }, + expectedStrongErr: "scoped token names cannot contain colons", + }, } for _, c := range cases { @@ -1474,3 +1483,18 @@ func TestValidateTokenForUse(t *testing.T) { assert.Error(t, strongValidateErr) assert.ErrorIs(t, strongValidateErr, joining.ValidateTokenForUse(token)) } + +func TestScopedTokenEncoding(t *testing.T) { + encoded := joining.EncodeScopedToken("TESTING", "SECRETSHERE") + require.Equal(t, "TESTING:"+base64.RawURLEncoding.EncodeToString([]byte("SECRETSHERE")), encoded) + + name, secret, ok := joining.DecodeScopedToken(encoded) + assert.True(t, ok) + assert.Equal(t, "TESTING", name) + assert.Equal(t, "SECRETSHERE", secret) + + name, secret, ok = joining.DecodeScopedToken("TESTING") + assert.False(t, ok) + assert.Equal(t, "TESTING", name) + assert.Empty(t, secret) +} diff --git a/lib/service/connect.go b/lib/service/connect.go index 1911009ee7c..737ae96cec1 100644 --- a/lib/service/connect.go +++ b/lib/service/connect.go @@ -59,6 +59,7 @@ import ( grpcmetrics "github.com/gravitational/teleport/lib/observability/metrics/grpc" "github.com/gravitational/teleport/lib/openssh" "github.com/gravitational/teleport/lib/reversetunnelclient" + "github.com/gravitational/teleport/lib/scopes/joining" servicebreaker "github.com/gravitational/teleport/lib/service/breaker" "github.com/gravitational/teleport/lib/service/servicecfg" "github.com/gravitational/teleport/lib/utils" @@ -788,14 +789,16 @@ func (process *TeleportProcess) makeJoinParams( if err != nil { return nil, trace.Wrap(err) } - tokenSecret, err := process.Config.TokenSecret() - if err != nil { - return nil, trace.Wrap(err) + + tokenName, tokenSecret := token, "" + if name, secret, ok := joining.DecodeScopedToken(token); ok { + tokenName = name + tokenSecret = secret } dataDir := cmp.Or(process.Config.DataDir, defaults.DataDir) joinParams := &joinclient.JoinParams{ - Token: token, + Token: tokenName, TokenSecret: tokenSecret, ID: id, AuthServers: process.Config.AuthServerAddresses(), diff --git a/lib/service/servicecfg/config.go b/lib/service/servicecfg/config.go index bcb32c38ec2..4d0def94a28 100644 --- a/lib/service/servicecfg/config.go +++ b/lib/service/servicecfg/config.go @@ -290,11 +290,6 @@ type Config struct { // using Token() token string - // tokenSecret is either the secret needed to join with the token defined for the config, or - // a path that contains the secret. This is private to avoid external packages reading the - // value - the value should be obtained using TokenSecret() - tokenSecret string - // v1, v2 - // AuthServers is a list of auth servers, proxies and peer auth servers to // connect to. Yes, this is not just auth servers, the field name is @@ -634,21 +629,6 @@ func (cfg *Config) Token() (string, error) { return token, nil } -// TokenSecret returns token secret needed to join the auth server with the configured token -// -// If the value stored points to a file, it will attempt to read the token secret from the file -// and return an error if it wasn't successful. -// If the value stored doesn't point to a file, it'll return the value stored. -// If the secret hasn't been set, an empty string will be returned -func (cfg *Config) TokenSecret() (string, error) { - secret, err := utils.TryReadValueAsFile(cfg.tokenSecret) - if err != nil { - return "", trace.Wrap(err) - } - - return secret, nil -} - // SetToken stores the value for --token or auth_token in the config // // This can be either the token or an absolute path to a file containing the token. @@ -656,14 +636,6 @@ func (cfg *Config) SetToken(token string) { cfg.token = token } -// SetTokenSecret stores the value for --token-secret or join_params.token_secret in the -// config. -// -// This can be either the secret or an absolute path to a file containing the secret. -func (cfg *Config) SetTokenSecret(secret string) { - cfg.tokenSecret = secret -} - // HasToken gives the ability to check if there has been a token value stored // in the config func (cfg *Config) HasToken() bool { diff --git a/lib/tbot/tbot_test.go b/lib/tbot/tbot_test.go index b380aad31ba..10a6fa411e2 100644 --- a/lib/tbot/tbot_test.go +++ b/lib/tbot/tbot_test.go @@ -1473,8 +1473,7 @@ func TestScopedBotSSH(t *testing.T) { nodeCfg.ScopesFeatures = scopes.Features{Enabled: true} nodeCfg.Hostname = nodeHostname nodeCfg.DataDir = t.TempDir() - nodeCfg.SetToken(nodeTokenResp.GetToken().GetMetadata().GetName()) - nodeCfg.SetTokenSecret(nodeTokenResp.GetToken().GetStatus().GetSecret()) + nodeCfg.SetToken(jointoken.EncodeScopedToken(nodeTokenResp.GetToken().GetMetadata().GetName(), nodeTokenResp.GetToken().GetStatus().GetSecret())) nodeCfg.SetAuthServerAddress(process.Config.Auth.ListenAddr) nodeCfg.Auth.Enabled = false nodeCfg.Proxy.Enabled = false @@ -1743,8 +1742,7 @@ func TestScopedBotKubernetes(t *testing.T) { kubeNodeCfg := servicecfg.MakeDefaultConfig() kubeNodeCfg.ScopesFeatures = scopes.Features{Enabled: true} kubeNodeCfg.DataDir = t.TempDir() - kubeNodeCfg.SetToken(kubeTokenResp.GetToken().GetMetadata().GetName()) - kubeNodeCfg.SetTokenSecret(kubeTokenResp.GetToken().GetStatus().GetSecret()) + kubeNodeCfg.SetToken(jointoken.EncodeScopedToken(kubeTokenResp.GetToken().GetMetadata().GetName(), kubeTokenResp.GetToken().GetStatus().GetSecret())) kubeNodeCfg.SetAuthServerAddress(process.Config.Auth.ListenAddr) kubeNodeCfg.Auth.Enabled = false kubeNodeCfg.Proxy.Enabled = false diff --git a/lib/web/join_tokens.go b/lib/web/join_tokens.go index 83b8f7c60a2..ac4bfe083d2 100644 --- a/lib/web/join_tokens.go +++ b/lib/web/join_tokens.go @@ -42,6 +42,7 @@ import ( "github.com/gravitational/teleport/lib/defaults" "github.com/gravitational/teleport/lib/httplib" "github.com/gravitational/teleport/lib/itertools/stream" + "github.com/gravitational/teleport/lib/scopes/joining" "github.com/gravitational/teleport/lib/services" "github.com/gravitational/teleport/lib/tlsca" "github.com/gravitational/teleport/lib/ui" @@ -645,9 +646,14 @@ func (h *Handler) getJoinScript(ctx context.Context, settings scriptSettings) (s return "", trace.Wrap(err, "Building install script options") } + tokenName := token.GetName() + if secret, ok := token.GetSecret(); ok { + tokenName = joining.EncodeScopedToken(tokenName, secret) + } + nodeInstallOpts := scripts.InstallNodeScriptOptions{ InstallOptions: installOpts, - Token: token.GetName(), + Token: tokenName, CAPins: caPins, // We are using the joinMethod from the script settings instead of the one from the token // to reproduce the previous script behavior. I'm also afraid that using the diff --git a/tool/tctl/common/resource_command_test.go b/tool/tctl/common/resource_command_test.go index 8cf9b4084b3..abdb6125366 100644 --- a/tool/tctl/common/resource_command_test.go +++ b/tool/tctl/common/resource_command_test.go @@ -3392,6 +3392,18 @@ func TestParseScopedRef(t *testing.T) { id: "/staging::my role", wantErr: true, }, + { + name: "scoped token with only name", + ref: "scoped_token", + id: "/test::test-token", + want: ScopedRef{Kind: "scoped_token", Scope: "/test", Name: "test-token"}, + }, + { + name: "scoped token with name and secret", + ref: "scoped_token", + id: "/test::test-token:YzZlYzdlYTg1YTZjZTEwZjVjYjAxMTc3Mjc2NTk3NGY", + want: ScopedRef{Kind: "scoped_token", Scope: "/test", Name: "test-token"}, + }, } for _, tt := range tests { diff --git a/tool/tctl/common/resources/scoped_token.go b/tool/tctl/common/resources/scoped_token.go index 423670fcc69..b0d084c0d43 100644 --- a/tool/tctl/common/resources/scoped_token.go +++ b/tool/tctl/common/resources/scoped_token.go @@ -20,7 +20,6 @@ import ( "context" "fmt" "io" - "slices" "strings" "time" @@ -33,6 +32,7 @@ import ( "github.com/gravitational/teleport/lib/auth/authclient" "github.com/gravitational/teleport/lib/itertools/stream" "github.com/gravitational/teleport/lib/scopes" + "github.com/gravitational/teleport/lib/scopes/joining" "github.com/gravitational/teleport/lib/services" ) @@ -191,14 +191,12 @@ func deleteScopedToken(ctx context.Context, client *authclient.Client, subKind s func ScopedTokenTextHelper(tokens []*joiningv1.ScopedToken, withSecrets bool) *bytes.Buffer { headers := []string{ "ID", + "Token", "Type", "Assigns Scope", "Labels", "Expiry Time (UTC)", } - if withSecrets { - headers = slices.Insert(headers, 1, "Secret") - } table := asciitable.MakeTable(headers) now := time.Now() @@ -210,16 +208,20 @@ func ScopedTokenTextHelper(tokens []*joiningv1.ScopedToken, withSecrets bool) *b expdur := expiresAt.Sub(now).Round(time.Second) expiry = fmt.Sprintf("%s (%s)", exptime, expdur.String()) } + + token := t.GetMetadata().GetName() + ":*****" + if withSecrets { + token = joining.EncodeScopedToken(t.GetMetadata().GetName(), t.GetStatus().GetSecret()) + } + row := []string{ scopes.QualifiedName{Scope: t.GetScope(), Name: t.GetMetadata().GetName()}.String(), + token, strings.Join(t.GetSpec().GetRoles(), ","), t.GetSpec().GetAssignedScope(), PrintMetadataLabels(t.GetMetadata().GetLabels()), expiry, } - if withSecrets { - row = slices.Insert(row, 1, t.GetStatus().GetSecret()) - } table.AddRow(row) } return table.AsBuffer() diff --git a/tool/tctl/common/scoped_ref.go b/tool/tctl/common/scoped_ref.go index 06e102a6583..52a804a3c54 100644 --- a/tool/tctl/common/scoped_ref.go +++ b/tool/tctl/common/scoped_ref.go @@ -23,6 +23,7 @@ import ( "github.com/gravitational/trace" + "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/lib/scopes" "github.com/gravitational/teleport/lib/services" ) @@ -106,13 +107,22 @@ func ParseScopedRef(ref, id string) (ScopedRef, error) { // is actually a subkind in the new format. subKind := r.Name if strings.Contains(id, scopes.QualifiedNameSeparator) { - if err := scopes.StrongValidateQualifiedName(id); err != nil { - return ScopedRef{}, trace.Wrap(err) - } qn, err := scopes.ParseQualifiedName(id) if err != nil { return ScopedRef{}, trace.Wrap(err) } + + // A user may provide the token name as either OR :. + // Both formats are supported to improve UX, however, only the token name is consumed + // for tctl commands to operate properly. Strip the secret after parsing the SQN so + // that the colon in the SQN separator is not mistaken for the token/secret separator. + if r.Kind == types.KindScopedToken { + qn.Name, _, _ = strings.Cut(qn.Name, ":") + } + + if err := qn.StrongValidate(); err != nil { + return ScopedRef{}, trace.Wrap(err) + } return ScopedRef{Kind: r.Kind, SubKind: subKind, Scope: qn.Scope, Name: qn.Name}, nil } return ScopedRef{Kind: r.Kind, SubKind: subKind, Name: id}, nil diff --git a/tool/tctl/common/scoped_token_command.go b/tool/tctl/common/scoped_token_command.go index 78d03db5958..f20d66e6bb4 100644 --- a/tool/tctl/common/scoped_token_command.go +++ b/tool/tctl/common/scoped_token_command.go @@ -225,15 +225,13 @@ func (c *ScopedTokensCommand) Add(ctx context.Context, client *authclient.Client return trace.Wrap(err, "creating scoped token") } - tokenName = tok.GetMetadata().GetName() - tokenSecret := tok.GetStatus().GetSecret() + token := joining.EncodeScopedToken(tok.GetMetadata().GetName(), tok.GetStatus().GetSecret()) // Print token information formatted with JSON, YAML, or just print the raw token. switch c.format { case teleport.JSON, teleport.YAML: expires := time.Now().Add(c.ttl) tokenInfo := map[string]any{ - "token": tokenName, - "token_secret": tokenSecret, + "token": token, "roles": roles, "scope": tok.GetScope(), "assign_scope": tok.GetSpec().GetAssignedScope(), @@ -256,17 +254,16 @@ func (c *ScopedTokensCommand) Add(ctx context.Context, client *authclient.Client return nil case teleport.Text: - fmt.Fprintln(c.Stdout, tokenName) + fmt.Fprintln(c.Stdout, token) return nil } return trace.Wrap(showJoinInstructions(ctx, joinInstructionsInput{ - out: c.Stdout, - ttl: c.ttl, - roles: roles, - tokenName: tokenName, - tokenSecret: tokenSecret, - client: client, + out: c.Stdout, + ttl: c.ttl, + roles: roles, + token: token, + client: client, })) } diff --git a/tool/tctl/common/token_command.go b/tool/tctl/common/token_command.go index b736e1a53ad..8eddc7bc671 100644 --- a/tool/tctl/common/token_command.go +++ b/tool/tctl/common/token_command.go @@ -320,7 +320,7 @@ func (c *TokensCommand) Add(ctx context.Context, client *authclient.Client) erro out: c.Stdout, client: client, roles: roles, - tokenName: token, + token: token, ttl: c.ttl, appName: c.appName, appURI: c.appURI, @@ -903,18 +903,17 @@ func generateAgentValues(params valueGeneratorParams) ([]byte, error) { } type joinInstructionsInput struct { - client *authclient.Client - roles types.SystemRoles - out io.Writer - tokenName string - tokenSecret string - ttl time.Duration - appName string - appURI string - dbName string - dbURI string - dbProtocol string - caPins []string + client *authclient.Client + roles types.SystemRoles + out io.Writer + token string + ttl time.Duration + appName string + appURI string + dbName string + dbURI string + dbProtocol string + caPins []string } func showJoinInstructions(ctx context.Context, in joinInstructionsInput) error { @@ -949,7 +948,7 @@ func showJoinInstructions(ctx context.Context, in joinInstructionsInput) error { return kubeMessageTemplate.Execute(in.out, map[string]any{ "proxy_server": proxies[0].GetPublicAddr(), - "token": in.tokenName, + "token": in.token, "minutes": in.ttl.Minutes(), "set_roles": setRoles, "version": proxies[0].GetTeleportVersion(), @@ -969,7 +968,7 @@ func showJoinInstructions(ctx context.Context, in joinInstructionsInput) error { return appMessageTemplate.Execute(in.out, map[string]any{ - "token": in.tokenName, + "token": in.token, "minutes": in.ttl.Minutes(), "ca_pins": in.caPins, "proxy_server": proxies[0].GetPublicAddr(), @@ -990,7 +989,7 @@ func showJoinInstructions(ctx context.Context, in joinInstructionsInput) error { } return dbMessageTemplate.Execute(in.out, map[string]any{ - "token": in.tokenName, + "token": in.token, "minutes": in.ttl.Minutes(), "ca_pins": in.caPins, "proxy_server": proxies[0].GetPublicAddr(), @@ -1000,24 +999,23 @@ func showJoinInstructions(ctx context.Context, in joinInstructionsInput) error { }) case in.roles.Include(types.RoleTrustedCluster): fmt.Fprintf(in.out, trustedClusterMessage, - in.tokenName, + in.token, int(in.ttl.Minutes())) case in.roles.Include(types.RoleWindowsDesktop): return desktopMessageTemplate.Execute(in.out, map[string]any{ - "token": in.tokenName, + "token": in.token, "minutes": in.ttl.Minutes(), }) case in.roles.Include(types.RoleMDM): return mdmTokenAddTemplate.Execute(in.out, map[string]any{ - "token": in.tokenName, + "token": in.token, "minutes": in.ttl.Minutes(), "ca_pins": in.caPins, }) default: return nodeMessageTemplate.Execute(in.out, map[string]any{ - "token": in.tokenName, - "secret": in.tokenSecret, + "token": in.token, "roles": strings.ToLower(in.roles.String()), "minutes": int(in.ttl.Minutes()), "ca_pins": in.caPins, diff --git a/tool/teleport/common/teleport.go b/tool/teleport/common/teleport.go index 083dff1fd9a..b972c1775dd 100644 --- a/tool/teleport/common/teleport.go +++ b/tool/teleport/common/teleport.go @@ -148,8 +148,6 @@ func Run(options Options) (app *kingpin.Application, executedCommand string, con start.Flag("token", "Invitation token or path to file with token value. Used to register with an auth server [none]"). StringVar(&ccf.AuthToken) - start.Flag("token-secret", "Invitation token secret or path to file with secret value. Used to register with an auth server [none]"). - StringVar(&ccf.TokenSecret) start.Flag("ca-pin", "CA pin to validate the Auth Server (can be repeated for multiple pins)"). StringsVar(&ccf.CAPins) @@ -496,7 +494,6 @@ func Run(options Options) (app *kingpin.Application, executedCommand string, con joinOpenSSH.Flag("proxy-server", "Address of the proxy server.").StringVar(&ccf.ProxyServer) joinOpenSSH.Flag("token", "Invitation token or path to file with token value to register with an auth server.").StringVar(&ccf.AuthToken) joinOpenSSH.Flag("join-method", "Method to use to join the cluster.").EnumVar(&ccf.JoinMethod, "token", "iam", "ec2") - joinOpenSSH.Flag("token-secret", "Invitation token secret or path to file with secret value. Used to register with an auth server [none]").StringVar(&ccf.TokenSecret) joinOpenSSH.Flag("openssh-config", fmt.Sprintf("Path to the OpenSSH config file [%v].", "/etc/ssh/sshd_config")).Default("/etc/ssh/sshd_config").StringVar(&ccf.OpenSSHConfigPath) joinOpenSSH.Flag("data-dir", fmt.Sprintf("Path to directory to store teleport data [%v].", defaults.DataDir)).Default(defaults.DataDir).StringVar(&ccf.DataDir) joinOpenSSH.Flag("restart-sshd", "Restart OpenSSH.").Default("true").BoolVar(&ccf.RestartOpenSSH)