diff --git a/Makefile b/Makefile index 33259679e5e..b142ae7749e 100644 --- a/Makefile +++ b/Makefile @@ -20,12 +20,6 @@ BINARIES=$(BUILDDIR)/tsh $(BUILDDIR)/teleport $(BUILDDIR)/tctl VERSRC = version.go gitref.go LIBS = $(shell find lib -type f -name '*.go') *.go -# TODO: REMOVE ME -.PHONY: mac -mac: - BUILDDIR=darwin $(MAKE) all - - # # Default target: builds all 3 executables and plaaces them in a current directory # diff --git a/integration/helpers.go b/integration/helpers.go index 232591cc239..22a00e9adff 100644 --- a/integration/helpers.go +++ b/integration/helpers.go @@ -354,7 +354,8 @@ func (i *TeleInstance) Start() (err error) { return err } -// NewClient returns a fully configured client (with server CAs and user keys) +// NewClient returns a fully configured and pre-authenticated client +// (pre-authenticated with server CAs and signed session key) func (i *TeleInstance) NewClient(login string, site string, host string, port int) (tc *client.TeleportClient, err error) { keyDir, err := ioutil.TempDir(i.Config.DataDir, "tsh") if err != nil { @@ -394,7 +395,7 @@ func (i *TeleInstance) NewClient(login string, site string, host string, port in if err != nil { return nil, err } - // tells the client to use user keys from 'secrets': + // confnigures the client authenticate using the keys from 'secrets': user, ok := i.Secrets.Users[login] if !ok { return nil, trace.Errorf("unknown login '%v'", login) @@ -402,11 +403,12 @@ func (i *TeleInstance) NewClient(login string, site string, host string, port in if user.Key == nil { return nil, trace.Errorf("user %v has no key", login) } - err = tc.AddKey(host, user.Key) + _, err = tc.AddKey(host, user.Key) if err != nil { return nil, trace.Wrap(err) } - // tell the client to trust given CAs (from secrets) + // tell the client to trust given CAs (from secrets). this is the + // equivalent of 'known hosts' in openssh cas := i.Secrets.GetCAs() for i := range cas { err = tc.AddTrustedCA(cas[i].V1()) diff --git a/integration/integration_test.go b/integration/integration_test.go index b13e3f80e5c..022de2ec90c 100644 --- a/integration/integration_test.go +++ b/integration/integration_test.go @@ -104,7 +104,6 @@ func (s *IntSuite) newTeleport(c *check.C, logins []string, enableSSH bool) *Tel for _, login := range logins { t.AddUser(login, []string{login}) } - if t.Create(nil, enableSSH, nil) != nil { c.FailNow() } diff --git a/lib/client/api.go b/lib/client/api.go index 86a99648267..0ce9fe290ce 100644 --- a/lib/client/api.go +++ b/lib/client/api.go @@ -121,7 +121,7 @@ type Config struct { // AuthMethods to use to login into cluster. If left empty, teleport will // use its own session store, - AuthMethods []*CertAuthMethod + AuthMethods []ssh.AuthMethod Stdout io.Writer Stderr io.Writer @@ -355,7 +355,6 @@ func NewClient(c *Config) (tc *TeleportClient, err error) { } return tc, nil } - tc.Config.AuthMethods = append(tc.Config.AuthMethods, tc.LocalAgent().AuthMethods()...) return tc, nil } @@ -848,6 +847,16 @@ func (tc *TeleportClient) getProxyLogin() string { return proxyLogin } +// authMethods returns a list (slice) of all SSH auth methods this client +// can use to try to authenticate +func (tc *TeleportClient) authMethods() []ssh.AuthMethod { + // return the auth methods that we were configured with + // plus our local key agent (i.e. methods we've added during runtime + // by the means of .AddKey()) + m := append([]ssh.AuthMethod(nil), tc.Config.AuthMethods...) + return append(m, tc.LocalAgent().AuthMethods()...) +} + // ConnectToProxy dials the proxy server and returns ProxyClient if successful func (tc *TeleportClient) ConnectToProxy() (*ProxyClient, error) { proxyAddr := tc.Config.ProxySSHHostPort() @@ -856,7 +865,7 @@ func (tc *TeleportClient) ConnectToProxy() (*ProxyClient, error) { HostKeyCallback: tc.HostKeyCallback, } // helper to create a ProxyClient struct - makeProxyClient := func(sshClient *ssh.Client, m *CertAuthMethod) *ProxyClient { + makeProxyClient := func(sshClient *ssh.Client, m ssh.AuthMethod) *ProxyClient { return &ProxyClient{ Client: sshClient, proxyAddress: proxyAddr, @@ -868,7 +877,7 @@ func (tc *TeleportClient) ConnectToProxy() (*ProxyClient, error) { } successMsg := fmt.Sprintf("[CLIENT] successful auth with proxy %v", proxyAddr) // try to authenticate using every non interactive auth method we have: - for i, m := range tc.Config.AuthMethods { + for i, m := range tc.authMethods() { log.Infof("[CLIENT] connecting proxy=%v login='%v' method=%d", proxyAddr, sshConfig.User, i) sshConfig.Auth = []ssh.AuthMethod{m} diff --git a/lib/client/client.go b/lib/client/client.go index 6858ad071f1..298cd7bef8c 100644 --- a/lib/client/client.go +++ b/lib/client/client.go @@ -44,7 +44,7 @@ type ProxyClient struct { hostLogin string proxyAddress string hostKeyCallback utils.HostKeyCallback - authMethod *CertAuthMethod + authMethod ssh.AuthMethod siteName string } @@ -155,8 +155,11 @@ func (proxy *ProxyClient) ConnectToSite(ctx context.Context, quiet bool) (auth.C // look at the certificate which we've received from the proxy and pick the 1st // valid principal to pass to the auth server authLogin := proxy.hostLogin - if cert, ok := proxy.authMethod.Cert.PublicKey().(*ssh.Certificate); ok && len(cert.ValidPrincipals) > 0 { - authLogin = cert.ValidPrincipals[0] + certMethod, ok := proxy.authMethod.(*CertAuthMethod) + if ok { + if cert, ok := certMethod.Cert.PublicKey().(*ssh.Certificate); ok && len(cert.ValidPrincipals) > 0 { + authLogin = cert.ValidPrincipals[0] + } } // this connects us to the node which is an auth server for this site diff --git a/lib/client/keyagent.go b/lib/client/keyagent.go index 0ced17193e4..9dd47244512 100644 --- a/lib/client/keyagent.go +++ b/lib/client/keyagent.go @@ -100,7 +100,10 @@ func (a *LocalKeyAgent) AddHostSignersToCache(hostSigners []services.CertAuthori return trace.Wrap(err) } log.Debugf("[KEY AGENT] adding CA key for %s", hostSigner.DomainName) - a.keyStore.AddKnownHostKeys(hostSigner.DomainName, publicKeys) + err = a.keyStore.AddKnownHostKeys(hostSigner.DomainName, publicKeys) + if err != nil { + return trace.Wrap(err) + } } return nil } @@ -155,7 +158,13 @@ func (a *LocalKeyAgent) CheckHostSignature(hostId string, remote net.Addr, key s return err } +// AddKey stores a new signed session key for future use. +// +// It returns an implementation of ssh.Authmethod which can be passed to ssh.Config +// to make new SSH connections authenticated by this key. +// func (a *LocalKeyAgent) AddKey(host string, username string, key *Key) (*CertAuthMethod, error) { + // save it to disk (usually into ~/.tsh) err := a.keyStore.AddKey(host, username, key) if err != nil { return nil, trace.Wrap(err) @@ -164,15 +173,18 @@ func (a *LocalKeyAgent) AddKey(host string, username string, key *Key) (*CertAut if err != nil { return nil, trace.Wrap(err) } - // add it to SSH agent as well: + // add it to the external SSH agent: if a.sshAgent != nil { if err = a.sshAgent.Add(*agentKey); err != nil { log.Warn(err) } } + // add it to our own in-memory key agent: if err = a.Agent.Add(*agentKey); err != nil { return nil, trace.Wrap(err) } + // generate SSH auth method based on the given signed key and return + // it to the caller: signer, err := ssh.NewSignerFromKey(agentKey.PrivateKey) if err != nil { return nil, trace.Wrap(err) @@ -215,7 +227,7 @@ func (a *LocalKeyAgent) DeleteKey(proxyHost string, username string) error { // It returns two: // 1. First to try is the external SSH agent // 2. Itself (disk-based local agent) -func (a *LocalKeyAgent) AuthMethods() (m []*CertAuthMethod) { +func (a *LocalKeyAgent) AuthMethods() (m []ssh.AuthMethod) { // combine our certificates with external SSH agent's: var certs []ssh.Signer if ourCerts, _ := a.Signers(); ourCerts != nil { @@ -227,7 +239,7 @@ func (a *LocalKeyAgent) AuthMethods() (m []*CertAuthMethod) { } } // for every certificate create a new "auth method" and return them - m = make([]*CertAuthMethod, len(certs)) + m = make([]ssh.AuthMethod, len(certs)) for i := range certs { m[i] = methodForCert(certs[i]) }