mirror of
https://github.com/gravitational/teleport.git
synced 2026-08-28 21:12:20 +08:00
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 `<token_name>:<base64(token_secret)`. The leading token_name is not encoded to allow users to visually dentify tokens they may have created with a specific name. The `~` separator was chosen because it is neither a valid backend key, scope separator, and does not need any special encoding if included in a URL. The token_secret is base64 encoded so that it appears as opaque text to users and can be included in a URL. Additionally, the tctl scoped ref parsing has been updated such that tctl get/edit/rm honors both `<token_name>` and `<token_name>:<base64(token_secret)>` 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.
This commit is contained in:
@@ -802,7 +802,6 @@ Flags:
|
||||
|`--sshd-check-command`|`sshd -t -f`|Command to use when checking OpenSSH config for validity. (sshd -t -f \<sshd_config\>)|
|
||||
|`--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
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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"`
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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 <token_name> OR <token_name>:<encoded_secret>.
|
||||
// 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
|
||||
|
||||
@@ -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,
|
||||
}))
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user