Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Adds support for loading tctl creds from ~/.tsh profile #4678

Merged
merged 1 commit into from
Nov 10, 2020
Merged

Conversation

klizhentas
Copy link
Contributor

This commit fixes #4439

Please take a look at teleport.e counterpart

lib/client/keyagent.go Show resolved Hide resolved
lib/client/keystore_test.go Outdated Show resolved Hide resolved
lib/client/keystore_test.go Show resolved Hide resolved
lib/client/keystore_test.go Show resolved Hide resolved
lib/client/keystore_test.go Outdated Show resolved Hide resolved
lib/client/keystore_test.go Outdated Show resolved Hide resolved
lib/client/keystore_test.go Outdated Show resolved Hide resolved
lib/client/keystore_test.go Outdated Show resolved Hide resolved
tool/tctl/common/tctl.go Outdated Show resolved Hide resolved
tool/tctl/main.go Show resolved Hide resolved
@a-palchikov
Copy link
Contributor

Passing a specific configuration function via an exported API could be confusing.
How about factoring the act of loading the identity into an API:

type IdentityLoader func(*GlobalCLIFlags, *service.Config) (*AuthServiceClientConfig, error)

which could be part of the flags struct:

// GlobalCLIFlags keeps the CLI flags that apply to all tctl commands
type GlobalCLIFlags struct {
	...
	// IdentityLoader specifies the function to load the identity information
	IdentityLoader IdentityLoader
	...
}

And then multiple implementations could be provided:
[tool/tctl/common/tctl.go]

app.Flag("identity", "Path to the identity file exported with 'tctl auth sign'").
	Short('i').
	StringVar(&identityFilePath)
// ...
if identityFilePath != "" {
	ccf.IdentityLoader = loadIdentityFromFile(identityFilePath)
} else {
	ccf.IdentityLoader = loadIdentityFromHostUUID
}
// configure all commands with Teleport configuration (they share 'cfg')
clientConfig, err := applyConfig(&ccf, cfg)
if err != nil {
	utils.FatalError(err)
}
// ...

OSS implementations:

func loadIdentityFromFile(path string) IdentityLoader {
	return func(_ *GlobalCLIFlags, cfg *service.Config) (*AuthServiceClientConfig, error) {
		key, err := common.LoadIdentity(path)
		if err != nil {
			return nil, trace.Wrap(err)
		}
		authConfig := new(AuthServiceClientConfig)
		authConfig.TLS, err = key.ClientTLSConfig(cfg.CipherSuites)
		if err != nil {
			return nil, trace.Wrap(err)
		}
		authConfig.SSH, err = key.ClientSSHConfig()
		if err != nil {
			return nil, trace.Wrap(err)
		}
		return authConfig, nil
	}
}

func loadIdentityFromHostUUID(_ *GlobalCLIFlags, cfg *service.Config) (authConfig *AuthServiceClientConfig, err error) {
	// read the host UUID only in case the identity was not provided,
	// because it will be used for reading local auth server identity
	cfg.HostUUID, err = utils.ReadHostUUID(cfg.DataDir)
	if err != nil {
		return nil, trace.Wrap(err)
	}
	identity, err := auth.ReadLocalIdentity(filepath.Join(cfg.DataDir, teleport.ComponentProcess), auth.IdentityID{Role: teleport.RoleAdmin, HostUUID: cfg.HostUUID})
	if err != nil {
		// The "admin" identity is not present? This means the tctl is running
		// NOT on the auth server
		if trace.IsNotFound(err) {
			return nil, trace.AccessDenied("tctl must be either used on the auth server or provided with the identity file via --identity flag")
		}
		return nil, trace.Wrap(err)
	}
	tls, err := identity.TLSConfig(cfg.CipherSuites)
	if err != nil {
		return nil, trace.Wrap(err)
	}
	return &AuthServiceClientConfig{
		TLS: tls,
	}, nil
}

and pass them from corresponding main:

var ccf common.GlobalCLIFlags
ccf.IdentityLoader = loadIdentityCustom // override when necessary
common.Run(commands, ccf)

It is mostly the same but will make the read code better imho.

tool/tctl/common/tctl.go Outdated Show resolved Hide resolved
@benarent
Copy link
Contributor

benarent commented Nov 2, 2020

We should review our profile support after this is complete, #3089 to make tctl CLI UX as smooth as possible.

@webvictim
Copy link
Contributor

webvictim commented Nov 2, 2020

I built this from source and it seems to work, it's very slow though (8 seconds between pressing enter and getting a response):

$ time ~/go/src/github.com/gravitational/teleport/e/build/tctl status
Cluster  gus.cloud.gravitational.io                                              
Version  5.0.0-beta.8                                                            
User CA  never updated                                                           
Host CA  never updated                                                           
CA pin   sha256:dec0a2e0ded908af3e5ba8f124f1d44aeb8a316ce99df3ef0339a9e5951f723d 
~/go/src/github.com/gravitational/teleport/e/build/tctl status  0.08s user 0.02s system 1% cpu 8.147 total
$ time ~/go/src/github.com/gravitational/teleport/e/build/tctl -d status
DEBU             Debug logging has been enabled. common/tctl.go:303
DEBU [KEYSTORE]  Returning SSH certificate "/home/gus/.tsh/keys/gus.cloud.gravitational.io/admin-cert.pub" valid until "2020-11-03 01:29:45 -0400 AST", TLS certificate "/home/gus/.tsh/keys/gus.cloud.gravitational.io/admin-x509.pem" valid until "2020-11-03 05:29:45 +0000 UTC". client/keystore.go:277
DEBU             Found active profile: {https   gus.cloud.gravitational.io:443   false  } admin. tctl/profile.go:43
DEBU [KEYSTORE]  Returning SSH certificate "/home/gus/.tsh/keys/gus.cloud.gravitational.io/admin-cert.pub" valid until "2020-11-03 01:29:45 -0400 AST", TLS certificate "/home/gus/.tsh/keys/gus.cloud.gravitational.io/admin-x509.pem" valid until "2020-11-03 05:29:45 +0000 UTC". client/keystore.go:277
DEBU             Setting auth server to web proxy gus.cloud.gravitational.io:443. tctl/profile.go:75
DEBU             Connecting to auth servers: [{gus.cloud.gravitational.io:443 tcp }]. common/tctl.go:181
DEBU [CLIENT]    HTTPS client init(proxyAddr=gus.cloud.gravitational.io:443, insecure=false) client/weblogin.go:307
DEBU             Attempting to connect using reverse tunnel address gus.cloud.gravitational.io:3024. common/tctl.go:214
DEBU [HTTP:PROX] No valid environment variables found. proxy/proxy.go:222
DEBU [HTTP:PROX] No proxy set in environment, returning direct dialer. proxy/proxy.go:137
DEBU [CLIENT]    Validated host gus.cloud.gravitational.io:3024. client/keyagent.go:99
DEBU [AUTH]      GRPC(CLIENT): keep alive 1m0s count: 3. auth/clt.go:319
DEBU [HTTP:PROX] No valid environment variables found. proxy/proxy.go:222
DEBU [HTTP:PROX] No proxy set in environment, returning direct dialer. proxy/proxy.go:137
DEBU [CLIENT]    Validated host gus.cloud.gravitational.io:3024. client/keyagent.go:99
Cluster  gus.cloud.gravitational.io                                                        
Version  5.0.0-beta.8                                                                      
User CA  never updated, update_servers: Jan  1 00:00:00 UTC, complete: Jan  1 00:00:00 UTC 
Host CA  never updated, update_servers: Jan  1 00:00:00 UTC, complete: Jan  1 00:00:00 UTC 
CA pin   sha256:dec0a2e0ded908af3e5ba8f124f1d44aeb8a316ce99df3ef0339a9e5951f723d           
Remote clusters

~/go/src/github.com/gravitational/teleport/e/build/tctl -d status  0.09s user 0.02s system 1% cpu 8.227 total

My ping to cloud is 94ms, I don't think it should take this long?

[root@ip-10-0-0-239 ~]# ping <home IP>
PING <home IP> 56(84) bytes of data.
64 bytes from <home IP>: icmp_seq=1 ttl=35 time=93.9 ms
64 bytes from <home IP>: icmp_seq=2 ttl=35 time=94.0 ms
64 bytes from <home IP>: icmp_seq=3 ttl=35 time=93.7 ms
64 bytes from <home IP>: icmp_seq=4 ttl=35 time=94.4 ms
64 bytes from <home IP>: icmp_seq=5 ttl=35 time=93.6 ms

@klizhentas
Copy link
Contributor Author

Strange, takes 1 second for me.

time ./e/build/tctl status
Cluster  tea.cloud.gravitational.io                                              
Version  5.0.0-beta.9                                                            
User CA  never updated                                                           
Host CA  never updated                                                           
CA pin   sha256:904c2dad75a290cf4b7debf316ddfc12402e77fce452d71bc67dfd602a5a090f 

real	0m1.085s
user	0m0.268s
sys	0m0.095s

@webvictim
Copy link
Contributor

Weird, I ran it in a Docker container and it was quick. It seems to be quicker locally now as well. Must have been a glitch,

@russjones
Copy link
Contributor

@a-palchikov I see what you're saying refactoring of the identity loading code, but this will be deleted in a few weeks once 5.1.0 lands and OSS and Enterprise both support RBAC. I'm in-favor of leaving as-is till then, what do you think?

lib/client/keystore_test.go Outdated Show resolved Hide resolved
lib/client/keystore_test.go Outdated Show resolved Hide resolved
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

tctl.e client should use tsh credentials to perform admin actions.
5 participants