Skip to content

Commit

Permalink
tsh: create an in-memory agent when using identity file
Browse files Browse the repository at this point in the history
The agent might be needed for forwarding, when cluster is in proxy
recording mode. In proxy recording mode agent forwarding is mandatory.
  • Loading branch information
Andrew Lytvynov committed Aug 11, 2020
1 parent b839da9 commit 5e81a33
Show file tree
Hide file tree
Showing 5 changed files with 35 additions and 8 deletions.
6 changes: 6 additions & 0 deletions lib/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -587,6 +587,9 @@ func (proxy *ProxyClient) ConnectToNode(ctx context.Context, nodeAddress NodeAdd
// creates a new context which holds the agent. if ForwardToAgent returns an error
// "already have handler for" we ignore it.
if recordingProxy {
if proxy.teleportClient.localAgent == nil {
return nil, trace.BadParameter("cluster is in proxy recording mode and requires agent forwarding for connections, but no agent was initialized")
}
err = agent.ForwardToAgent(proxy.Client, proxy.teleportClient.localAgent.Agent)
if err != nil && !strings.Contains(err.Error(), "agent: already have handler for") {
return nil, trace.Wrap(err)
Expand Down Expand Up @@ -672,6 +675,9 @@ func (proxy *ProxyClient) PortForwardToNode(ctx context.Context, nodeAddress Nod
// creates a new context which holds the agent. if ForwardToAgent returns an error
// "already have handler for" we ignore it.
if recordingProxy {
if proxy.teleportClient.localAgent == nil {
return nil, trace.BadParameter("cluster is in proxy recording mode and requires agent forwarding for connections, but no agent was initialized")
}
err = agent.ForwardToAgent(proxy.Client, proxy.teleportClient.localAgent.Agent)
if err != nil && !strings.Contains(err.Error(), "agent: already have handler for") {
return nil, trace.Wrap(err)
Expand Down
12 changes: 6 additions & 6 deletions lib/client/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ func (k *Key) CertPrincipals() ([]string, error) {

// AsAgentKeys converts client.Key struct to a []*agent.AddedKey. All elements
// of the []*agent.AddedKey slice need to be loaded into the agent!
func (k *Key) AsAgentKeys() ([]*agent.AddedKey, error) {
func (k *Key) AsAgentKeys() ([]agent.AddedKey, error) {
// unmarshal certificate bytes into a ssh.PublicKey
publicKey, _, _, _, err := ssh.ParseAuthorizedKey(k.Cert)
if err != nil {
Expand All @@ -157,8 +157,8 @@ func (k *Key) AsAgentKeys() ([]*agent.AddedKey, error) {

// On Windows, return the certificate with the private key embedded.
if runtime.GOOS == teleport.WindowsOS {
return []*agent.AddedKey{
&agent.AddedKey{
return []agent.AddedKey{
{
PrivateKey: privateKey,
Certificate: publicKey.(*ssh.Certificate),
Comment: comment,
Expand All @@ -180,15 +180,15 @@ func (k *Key) AsAgentKeys() ([]*agent.AddedKey, error) {
//
// For more details see the following: https://bugzilla.mindrot.org/show_bug.cgi?id=2550
// WARNING: callers expect the returned slice to be __exactly as it is__
return []*agent.AddedKey{
&agent.AddedKey{
return []agent.AddedKey{
{
PrivateKey: privateKey,
Certificate: publicKey.(*ssh.Certificate),
Comment: comment,
LifetimeSecs: 0,
ConfirmBeforeUse: false,
},
&agent.AddedKey{
{
PrivateKey: privateKey,
Certificate: nil,
Comment: comment,
Expand Down
4 changes: 2 additions & 2 deletions lib/client/keyagent.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ func (a *LocalKeyAgent) LoadKey(key Key) (*agent.AddedKey, error) {
// iterate over all teleport and system agent and load key
for _, agent := range agents {
for _, agentKey := range agentKeys {
err = agent.Add(*agentKey)
err = agent.Add(agentKey)
if err != nil {
a.log.Warnf("Unable to communicate with agent and add key: %v", err)
}
Expand All @@ -155,7 +155,7 @@ func (a *LocalKeyAgent) LoadKey(key Key) (*agent.AddedKey, error) {

// return the first key because it has the embedded private key in it.
// see docs for AsAgentKeys for more details.
return agentKeys[0], nil
return &agentKeys[0], nil
}

// UnloadKey will unload key for user from the teleport ssh agent as well as
Expand Down
15 changes: 15 additions & 0 deletions tool/tsh/tsh.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import (
"time"

"golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/agent"

"github.com/gravitational/teleport"
"github.com/gravitational/teleport/lib/asciitable"
Expand Down Expand Up @@ -1042,6 +1043,20 @@ func makeClient(cf *CLIConf, useProfileLogin bool) (*client.TeleportClient, erro
}
c.AuthMethods = []ssh.AuthMethod{identityAuth}

// Also create an in-memory agent to hold the key. If cluster is in
// proxy recording mode, agent forwarding will be required for
// sessions.
c.Agent = agent.NewKeyring()
agentKeys, err := key.AsAgentKeys()
if err != nil {
return nil, trace.Wrap(err)
}
for _, k := range agentKeys {
if err := c.Agent.Add(k); err != nil {
return nil, trace.Wrap(err)
}
}

if len(key.TLSCert) > 0 {
c.TLS, err = key.ClientTLSConfig()
if err != nil {
Expand Down
6 changes: 6 additions & 0 deletions tool/tsh/tsh_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,12 @@ func (s *MainTestSuite) TestMakeClient(c *check.C) {
c.Assert(tc, check.NotNil)
c.Assert(tc.Config.WebProxyAddr, check.Equals, proxyWebAddr.String())
c.Assert(tc.Config.SSHProxyAddr, check.Equals, proxyPublicSSHAddr.String())
c.Assert(tc.LocalAgent().Agent, check.NotNil)
// Client should have an in-memory agent with keys loaded, in case agent
// forwarding is required for proxy recording mode.
agentKeys, err := tc.LocalAgent().Agent.List()
c.Assert(err, check.IsNil)
c.Assert(len(agentKeys), check.Not(check.Equals), 0)
}

func (s *MainTestSuite) TestIdentityRead(c *check.C) {
Expand Down

0 comments on commit 5e81a33

Please sign in to comment.