Merge pull request #493 from gravitational/ev/491

Adds the ability to specify non-standard HTTPS proxy port
This commit is contained in:
Ev Kontsevoy 2016-08-05 15:48:08 -07:00 committed by GitHub
commit df05b9e6d2
4 changed files with 59 additions and 15 deletions

View file

@ -134,7 +134,7 @@ Run shell or execute a command on a remote SSH node.
Flags:
--user SSH proxy user [ekontsevoy]
--proxy SSH proxy host or IP address
--proxy SSH proxy host or IP address, for example --proxy=host:ssh_port,https_port
--ttl Minutes to live for a SSH session
--insecure Do not verify server certificate and host name. Use only in test environments
-d, --debug Verbose logging to stdout
@ -158,6 +158,20 @@ using familiar SSH syntax:
> ssh -p 6122 root@host ls
```
### Note about Proxies
A Teleport proxy uses two ports: `3080` for HTTPS and `3023` for proxying SSH connections.
The HTTPS port is used to serve Web UI and also to implement 2nd factor auth for `tsh` client.
If your Teleport proxy is configured to listen on other ports, you should specify
them via `--proxy` flag as shown:
```
tsh --proxy=host:5000,5001
```
This means "connect to the port `5000` for SSH and to `5001` for HTTPS".
### Port Forwarding
`tsh ssh` supports OpenSSH `-L` flag which allows to forward incoming connections from localhost

View file

@ -81,7 +81,8 @@ type Config struct {
// HostPort is a remote host port to connect to
HostPort int
// ProxyHost is a host or IP of the proxy (with optional ":port")
// ProxyHost is a host or IP of the proxy (with optional ":ssh_port,https_port"). This parameter
// is taken from the --proxy flag and can look like --proxy=host:5025,5080
ProxyHost string
// KeyTTL is a time to live for the temporary SSH keypair to remain valid:
@ -130,13 +131,32 @@ type Config struct {
Env map[string]string
}
// ProxyHostPort returns a full host:port address of the proxy or an empty string if no
// proxy is given. If 'forWeb' flag is set, returns HTTPS port, otherwise
// ProxyHostPort returns a full host:port address of the SSH proxy
// Otherwise, returns an empty string if no proxy is given.
//
// If 'forWeb' flag is set, returns HTTPS port, otherwise
// returns SSH port (proxy servers listen on both)
func (c *Config) ProxyHostPort(defaultPort int) string {
func (c *Config) ProxyHostPort(forWeb bool) string {
var defaultPort int
if c.ProxySpecified() {
if forWeb {
defaultPort = defaults.HTTPListenPort
} else {
defaultPort = defaults.SSHProxyListenPort
}
host, port, err := net.SplitHostPort(c.ProxyHost)
if err == nil && len(port) > 0 {
ports := strings.Split(port, ",")
if forWeb {
if len(ports) > 1 {
port = ports[1]
} else {
port = strconv.Itoa(defaultPort)
}
} else {
port = ports[0]
}
// c.ProxyHost was already specified as "host:port"
return net.JoinHostPort(host, port)
}
@ -586,11 +606,13 @@ func (tc *TeleportClient) ListNodes() ([]services.Server, error) {
return nil, trace.Wrap(err)
}
}
// connect to the proxy and ask it to return a full list of servers
proxyClient, err := tc.ConnectToProxy()
if err != nil {
return nil, trace.Wrap(err)
}
defer proxyClient.Close()
return proxyClient.FindServersByLabels(tc.Labels)
}
@ -784,7 +806,7 @@ func (tc *TeleportClient) GetKeys() ([]agent.AddedKey, error) {
// ConnectToProxy dials the proxy server and returns ProxyClient if successful
func (tc *TeleportClient) ConnectToProxy() (*ProxyClient, error) {
proxyAddr := tc.Config.ProxyHostPort(defaults.SSHProxyListenPort)
proxyAddr := tc.Config.ProxyHostPort(false)
sshConfig := &ssh.ClientConfig{
User: tc.getProxyLogin(),
HostKeyCallback: tc.HostKeyCallback,
@ -924,7 +946,7 @@ func (tc *TeleportClient) AddKey(host string, key *Key) error {
// directLogin asks for a password + HOTP token, makes a request to CA via proxy
func (tc *TeleportClient) directLogin(pub []byte) (*web.SSHLoginResponse, error) {
httpsProxyHostPort := tc.Config.ProxyHostPort(defaults.HTTPListenPort)
httpsProxyHostPort := tc.Config.ProxyHostPort(true)
certPool := loopbackPool(httpsProxyHostPort)
// ping the HTTPs endpoint first:
@ -954,8 +976,9 @@ func (tc *TeleportClient) directLogin(pub []byte) (*web.SSHLoginResponse, error)
func (tc *TeleportClient) oidcLogin(connectorID string, pub []byte) (*web.SSHLoginResponse, error) {
log.Infof("oidcLogin start")
// ask the CA (via proxy) to sign our public key:
response, err := web.SSHAgentOIDCLogin(tc.Config.ProxyHostPort(defaults.HTTPListenPort),
connectorID, pub, tc.KeyTTL, tc.InsecureSkipVerify, loopbackPool(tc.Config.ProxyHostPort(defaults.HTTPListenPort)))
webProxyAddr := tc.Config.ProxyHostPort(true)
response, err := web.SSHAgentOIDCLogin(webProxyAddr,
connectorID, pub, tc.KeyTTL, tc.InsecureSkipVerify, loopbackPool(webProxyAddr))
return response, trace.Wrap(err)
}

View file

@ -40,11 +40,20 @@ func (s *APITestSuite) TestConfig(c *check.C) {
c.Assert(conf.ProxySpecified(), check.Equals, false)
conf.ProxyHost = "example.org"
c.Assert(conf.ProxySpecified(), check.Equals, true)
c.Assert(conf.ProxyHostPort(12), check.Equals, "example.org:12")
c.Assert(conf.ProxyHostPort(false), check.Equals, "example.org:3023")
c.Assert(conf.ProxyHostPort(true), check.Equals, "example.org:3080")
conf.ProxyHost = "example.org:100"
c.Assert(conf.ProxySpecified(), check.Equals, true)
c.Assert(conf.ProxyHostPort(12), check.Equals, "example.org:100")
c.Assert(conf.ProxyHostPort(false), check.Equals, "example.org:100")
c.Assert(conf.ProxyHostPort(true), check.Equals, "example.org:3080")
conf.ProxyHost = "example.org:100,200"
c.Assert(conf.ProxyHostPort(false), check.Equals, "example.org:100")
c.Assert(conf.ProxyHostPort(true), check.Equals, "example.org:200")
conf.ProxyHost = "example.org:,200"
c.Assert(conf.ProxyHostPort(true), check.Equals, "example.org:200")
}
func (s *APITestSuite) TestNew(c *check.C) {
@ -63,10 +72,7 @@ func (s *APITestSuite) TestNew(c *check.C) {
la := tc.LocalAgent()
c.Assert(la, check.NotNil)
c.Assert(tc.NodeHostPort(), check.Equals, "localhost:22")
c.Assert(tc.ProxySpecified(), check.Equals, true)
c.Assert(tc.ProxyHostPort(12), check.Equals, "proxy:12")
}
func (s *APITestSuite) TestParseLabels(c *check.C) {

View file

@ -56,7 +56,8 @@ func (s *MainTestSuite) TestMakeClient(c *check.C) {
c.Assert(err, check.IsNil)
c.Assert(tc, check.NotNil)
c.Assert(tc.Config.NodeHostPort(), check.Equals, "localhost:3022")
c.Assert(tc.Config.ProxyHostPort(666), check.Equals, "proxy:666")
c.Assert(tc.Config.ProxyHostPort(false), check.Equals, "proxy:3023")
c.Assert(tc.Config.ProxyHostPort(true), check.Equals, "proxy:3080")
c.Assert(tc.Config.HostLogin, check.Equals, client.Username())
c.Assert(tc.Config.KeyTTL, check.Equals, defaults.CertDuration)