Skip to content

Commit

Permalink
Update tsh login to select clusters.
Browse files Browse the repository at this point in the history
The following changes have been introduced
to tsh login behavior:

1. tsh login now accepts cluster name
as an optional positional argument:

$ tsh login clustername

2. If tsh login is called without arguments
and the current credentials are valid,
tsh login now prints status, previous behavior
always forced login:

$ tsh login
... print status if logged in...

2. If tsh login is called with the proxy
equal to current, tsh login selects cluster,
otherwise it will re-login to another proxy:

$ tsh login one
... selected cluster one

$ tsh login two
... selected cluster two

$ tsh login --proxy=example.com three
... selected cluster three because
proxy is the same

$ tsh login --proxy=acme.example.com four
...will switch to proxy acme.example.com
and cluster four
  • Loading branch information
klizhentas committed Jun 26, 2018
1 parent f8b8de0 commit e570b24
Show file tree
Hide file tree
Showing 8 changed files with 151 additions and 21 deletions.
2 changes: 1 addition & 1 deletion integration/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -889,7 +889,7 @@ func (i *TeleInstance) NewUnauthenticatedClient(cfg ClientConfig) (tc *client.Te
SiteName: cfg.Cluster,
ForwardAgent: cfg.ForwardAgent,
}
cconf.SetProxy(proxyHost, proxyWebPort, proxySSHPort)
cconf.SetProxy(proxyHost, proxyWebPort, proxySSHPort, 0)

return client.NewClient(cconf)
}
Expand Down
56 changes: 53 additions & 3 deletions lib/client/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ import (
"github.com/gravitational/teleport/lib/utils"

"github.com/gravitational/trace"
"github.com/jonboulle/clockwork"
"github.com/moby/moby/pkg/term"
log "github.com/sirupsen/logrus"
"golang.org/x/crypto/ssh"
Expand Down Expand Up @@ -233,6 +234,14 @@ type ProfileStatus struct {

// Extensions is a list of enabled SSH features for the certificate.
Extensions []string

// Cluster is a selected cluster
Cluster string
}

// IsExpired returns true if profile is not expired yet
func (p *ProfileStatus) IsExpired(clock clockwork.Clock) bool {
return p.ValidUntil.Sub(clock.Now()) <= 0
}

// readProfile reads in the profile as well as the associated certificate
Expand Down Expand Up @@ -301,6 +310,7 @@ func readProfile(profileDir string, profileName string) (*ProfileStatus, error)
ValidUntil: validUntil,
Extensions: extensions,
Roles: roles,
Cluster: profile.SiteName,
}, nil
}

Expand Down Expand Up @@ -336,6 +346,15 @@ func Status(profileDir string, proxyHost string) (*ProfileStatus, []*ProfileStat
var profile *ProfileStatus
var others []*ProfileStatus

// remove ports from proxy host, because profile name is stored
// by host name
if proxyHost != "" {
proxyHost, err = utils.Host(proxyHost)
if err != nil {
return nil, nil, trace.Wrap(err)
}
}

// Construct the full path to the profile requested and make sure it exists.
profileDir = FullProfilePath(profileDir)
stat, err := os.Stat(profileDir)
Expand Down Expand Up @@ -381,6 +400,11 @@ func Status(profileDir string, proxyHost string) (*ProfileStatus, []*ProfileStat
}
ps, err := readProfile(profileDir, file.Name())
if err != nil {
// parts of profile are missing?
// status skips these files
if trace.IsNotFound(err) {
continue
}
return nil, nil, trace.Wrap(err)
}
others = append(others, ps)
Expand All @@ -403,7 +427,7 @@ func (c *Config) LoadProfile(profileDir string, proxyName string) error {
return trace.Wrap(err)
}
// apply the profile to the current configuration:
c.SetProxy(cp.ProxyHost, cp.ProxyWebPort, cp.ProxySSHPort)
c.SetProxy(cp.ProxyHost, cp.ProxyWebPort, cp.ProxySSHPort, cp.ProxyKubePort)
c.Username = cp.Username
c.SiteName = cp.SiteName
c.LocalForwardPorts, err = ParsePortForwardSpec(cp.ForwardedPorts)
Expand All @@ -427,6 +451,7 @@ func (c *Config) SaveProfile(profileDir string, profileOptions ...ProfileOptions
cp.Username = c.Username
cp.ProxySSHPort = c.ProxySSHPort()
cp.ProxyWebPort = c.ProxyWebPort()
cp.ProxyKubePort = c.ProxyKubePort()
cp.ForwardedPorts = c.LocalForwardPorts.ToStringSpec()
cp.SiteName = c.SiteName

Expand All @@ -446,8 +471,12 @@ func (c *Config) SaveProfile(profileDir string, profileOptions ...ProfileOptions
return nil
}

func (c *Config) SetProxy(host string, webPort, sshPort int) {
c.ProxyHostPort = fmt.Sprintf("%s:%d,%d", host, webPort, sshPort)
func (c *Config) SetProxy(host string, webPort, sshPort, kubePort int) {
if kubePort != 0 {
c.ProxyHostPort = fmt.Sprintf("%s:%d,%d,%d", host, webPort, sshPort, kubePort)
} else {
c.ProxyHostPort = fmt.Sprintf("%s:%d,%d", host, webPort, sshPort)
}
}

// ProxyHost returns the hostname of the proxy server (without any port numbers)
Expand All @@ -472,6 +501,10 @@ func (c *Config) ProxyWebHostPort() string {
return net.JoinHostPort(c.ProxyHost(), strconv.Itoa(c.ProxyWebPort()))
}

func (c *Config) ProxyKubeHostPort() string {
return net.JoinHostPort(c.ProxyHost(), strconv.Itoa(c.ProxyKubePort()))
}

// ProxyWebPort returns the port number of teleport HTTP proxy stored in the config
// usually 3080 by default.
func (c *Config) ProxyWebPort() (retval int) {
Expand Down Expand Up @@ -506,6 +539,23 @@ func (c *Config) ProxySSHPort() (retval int) {
return retval
}

// ProxyKubePort returns the port number of teleport Kubernetes proxy stored in the config
// usually 3026 by default.
func (c *Config) ProxyKubePort() (retval int) {
retval = defaults.KubeProxyListenPort
_, port, err := net.SplitHostPort(c.ProxyHostPort)
if err == nil && len(port) > 0 {
ports := strings.Split(port, ",")
if len(ports) > 2 {
retval, err = strconv.Atoi(ports[2])
if err != nil {
log.Warnf("invalid proxy Kubernetes port: '%v': %v", ports, err)
}
}
}
return retval
}

// ProxySpecified returns true if proxy has been specified
func (c *Config) ProxySpecified() bool {
return len(c.ProxyHostPort) > 0
Expand Down
8 changes: 7 additions & 1 deletion lib/client/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func (s *APITestSuite) TestConfig(c *check.C) {
c.Assert(conf.ProxySSHHostPort(), check.Equals, "example.org:3023")
c.Assert(conf.ProxyWebHostPort(), check.Equals, "example.org:3080")

conf.SetProxy("example.org", 100, 200)
conf.SetProxy("example.org", 100, 200, 0)
c.Assert(conf.ProxyWebHostPort(), check.Equals, "example.org:100")
c.Assert(conf.ProxySSHHostPort(), check.Equals, "example.org:200")

Expand All @@ -54,6 +54,12 @@ func (s *APITestSuite) TestConfig(c *check.C) {
conf.ProxyHostPort = "example.org:,200"
c.Assert(conf.ProxySSHHostPort(), check.Equals, "example.org:200")
c.Assert(conf.ProxyWebHostPort(), check.Equals, "example.org:3080")

conf.SetProxy("example.org", 100, 200, 300)
c.Assert(conf.ProxyWebHostPort(), check.Equals, "example.org:100")
c.Assert(conf.ProxySSHHostPort(), check.Equals, "example.org:200")
c.Assert(conf.ProxyKubeHostPort(), check.Equals, "example.org:300")

}

func (s *APITestSuite) TestNew(c *check.C) {
Expand Down
7 changes: 4 additions & 3 deletions lib/client/profile.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,10 @@ type ClientProfile struct {
//
// proxy configuration
//
ProxyHost string `yaml:"proxy_host,omitempty"`
ProxySSHPort int `yaml:"proxy_port,omitempty"`
ProxyWebPort int `yaml:"proxy_web_port,omitempty"`
ProxyHost string `yaml:"proxy_host,omitempty"`
ProxySSHPort int `yaml:"proxy_port,omitempty"`
ProxyWebPort int `yaml:"proxy_web_port,omitempty"`
ProxyKubePort int `yaml:"proxy_kube_port,omitempty"`

//
// auth/identity
Expand Down
7 changes: 4 additions & 3 deletions lib/kube/client/kubeclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (

"github.com/gravitational/teleport"
"github.com/gravitational/teleport/lib/client"
"github.com/gravitational/teleport/lib/defaults"
"github.com/gravitational/teleport/lib/utils"

"github.com/gravitational/trace"
Expand All @@ -22,8 +21,10 @@ func UpdateKubeconfig(tc *client.TeleportClient) error {
return trace.Wrap(err)
}
clusterName := tc.ProxyHost()
// TODO: unhardcode the port
clusterAddr := fmt.Sprintf("https://%v:%v", tc.ProxyHost(), defaults.KubeProxyListenPort)
if tc.SiteName != "" && tc.SiteName != clusterName {
clusterName = fmt.Sprintf("%v.%v", tc.SiteName, tc.ProxyHost())
}
clusterAddr := fmt.Sprintf("https://%v:%v", clusterName, tc.ProxyKubePort())

creds, err := tc.LocalAgent().GetKey()
if err != nil {
Expand Down
4 changes: 2 additions & 2 deletions lib/kube/proxy/forwarder.go
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ func (f *Forwarder) setupContext(ctx auth.AuthContext, req *http.Request, isRemo
return nil, trace.Wrap(err)
}
for _, remoteCluster := range f.Tunnel.GetSites() {
if strings.HasSuffix(req.Host, remoteCluster.GetName()+".") {
if strings.HasPrefix(req.Host, remoteCluster.GetName()+".") {
f.Debugf("Going to proxy to cluster: %v based on matching host suffix %v.", remoteCluster.GetName(), req.Host)
targetCluster = remoteCluster
isRemoteCluster = remoteCluster.GetName() != f.ClusterName
Expand Down Expand Up @@ -561,9 +561,9 @@ type clusterSession struct {
func (f *Forwarder) getOrCreateClusterSession(ctx authContext) (*clusterSession, error) {
client := f.getClusterSession(ctx)
if client != nil {
f.Debugf("Returning existing creds for %v.", ctx)
return client, nil
}
f.Debugf("Requesting new creds for %v.", ctx)
return f.newClusterSession(ctx)
}

Expand Down
8 changes: 7 additions & 1 deletion tool/tsh/help.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,11 @@ EXAMPLES:
$ tsh --proxy=host.example.com:8080,8023 login
Use port 8080 and 3023 (default) for SSH proxy:
$ tsh --proxy=host.example.com:8080 login`
$ tsh --proxy=host.example.com:8080 login
Login and select cluster "two":
$ tsh --proxy=host.example.com login two
Select cluster "two" using existing credentials and proxy:
$ tsh login two`
)
Loading

0 comments on commit e570b24

Please sign in to comment.