Skip to content

Commit

Permalink
Add options to skip connecting to ssh-agent from tsh
Browse files Browse the repository at this point in the history
In particular, gpg-agent doesn't support SSH certificates, so writing to
it is potentially disruptive for the user: https://dev.gnupg.org/T1756

User has two options:
- pass `--no-use-local-ssh-agent` for individual calls to tsh
- set `TELEPORT_USE_LOCAL_SSH_AGENT=false` to make it permanent

Fixes #3169
  • Loading branch information
Andrew Lytvynov committed May 19, 2020
1 parent 9333667 commit 5fbbb7e
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 25 deletions.
13 changes: 9 additions & 4 deletions lib/client/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,10 @@ type Config struct {
// Browser can be used to pass the name of a browser to override the system default
// (not currently implemented), or set to 'none' to suppress browser opening entirely.
Browser string

// UseLocalSSHAgent will write user certificates to the local ssh-agent (or
// similar) socket at $SSH_AUTH_SOCK.
UseLocalSSHAgent bool
}

// CachePolicy defines cache policy for local clients
Expand All @@ -269,9 +273,10 @@ type CachePolicy struct {
// MakeDefaultConfig returns default client config
func MakeDefaultConfig() *Config {
return &Config{
Stdout: os.Stdout,
Stderr: os.Stderr,
Stdin: os.Stdin,
Stdout: os.Stdout,
Stderr: os.Stderr,
Stdin: os.Stdin,
UseLocalSSHAgent: true,
}
}

Expand Down Expand Up @@ -834,7 +839,7 @@ func NewClient(c *Config) (tc *TeleportClient, err error) {
} else {
// initialize the local agent (auth agent which uses local SSH keys signed by the CA):
webProxyHost, _ := tc.WebProxyHostPort()
tc.localAgent, err = NewLocalAgent(c.KeysDir, webProxyHost, c.Username)
tc.localAgent, err = NewLocalAgent(c.KeysDir, webProxyHost, c.Username, c.UseLocalSSHAgent)
if err != nil {
return nil, trace.Wrap(err)
}
Expand Down
9 changes: 7 additions & 2 deletions lib/client/keyagent.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ type LocalKeyAgent struct {

// NewLocalAgent reads all Teleport certificates from disk (using FSLocalKeyStore),
// creates a LocalKeyAgent, loads all certificates into it, and returns the agent.
func NewLocalAgent(keyDir string, proxyHost string, username string) (a *LocalKeyAgent, err error) {
func NewLocalAgent(keyDir, proxyHost, username string, useLocalSSHAgent bool) (a *LocalKeyAgent, err error) {
keystore, err := NewFSLocalKeyStore(keyDir)
if err != nil {
return nil, trace.Wrap(err)
Expand All @@ -80,12 +80,17 @@ func NewLocalAgent(keyDir string, proxyHost string, username string) (a *LocalKe
}),
Agent: agent.NewKeyring(),
keyStore: keystore,
sshAgent: connectToSSHAgent(),
noHosts: make(map[string]bool),
username: username,
proxyHost: proxyHost,
}

if useLocalSSHAgent {
a.sshAgent = connectToSSHAgent()
} else {
log.Debug("Skipping connection to the local ssh-agent.")
}

// unload all teleport keys from the agent first to ensure
// we don't leave stale keys in the agent
err = a.UnloadKeys()
Expand Down
10 changes: 5 additions & 5 deletions lib/client/keyagent_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ func (s *KeyAgentTestSuite) SetUpTest(c *check.C) {
// a teleport key with the teleport username.
func (s *KeyAgentTestSuite) TestAddKey(c *check.C) {
// make a new local agent
lka, err := NewLocalAgent(s.keyDir, s.hostname, s.username)
lka, err := NewLocalAgent(s.keyDir, s.hostname, s.username, true)
c.Assert(err, check.IsNil)

// add the key to the local agent, this should write the key
Expand Down Expand Up @@ -159,7 +159,7 @@ func (s *KeyAgentTestSuite) TestLoadKey(c *check.C) {
userdata := []byte("hello, world")

// make a new local agent
lka, err := NewLocalAgent(s.keyDir, s.hostname, s.username)
lka, err := NewLocalAgent(s.keyDir, s.hostname, s.username, true)
c.Assert(err, check.IsNil)

// unload any keys that might be in the agent for this user
Expand Down Expand Up @@ -217,7 +217,7 @@ func (s *KeyAgentTestSuite) TestLoadKey(c *check.C) {

func (s *KeyAgentTestSuite) TestHostCertVerification(c *check.C) {
// Make a new local agent.
lka, err := NewLocalAgent(s.keyDir, s.hostname, s.username)
lka, err := NewLocalAgent(s.keyDir, s.hostname, s.username, true)
c.Assert(err, check.IsNil)

// By default user has not refused any hosts.
Expand Down Expand Up @@ -297,7 +297,7 @@ func (s *KeyAgentTestSuite) TestHostCertVerification(c *check.C) {

func (s *KeyAgentTestSuite) TestHostKeyVerification(c *check.C) {
// make a new local agent
lka, err := NewLocalAgent(s.keyDir, s.hostname, s.username)
lka, err := NewLocalAgent(s.keyDir, s.hostname, s.username, true)
c.Assert(err, check.IsNil)

// by default user has not refused any hosts:
Expand Down Expand Up @@ -351,7 +351,7 @@ func (s *KeyAgentTestSuite) TestHostKeyVerification(c *check.C) {
func (s *KeyAgentTestSuite) TestDefaultHostPromptFunc(c *check.C) {
keygen := testauthority.New()

a, err := NewLocalAgent(s.keyDir, s.hostname, s.username)
a, err := NewLocalAgent(s.keyDir, s.hostname, s.username, true)
c.Assert(err, check.IsNil)

_, keyBytes, err := keygen.GenerateKeyPair("")
Expand Down
36 changes: 22 additions & 14 deletions tool/tsh/tsh.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,6 @@ type CLIConf struct {
NodeLogin string
// InsecureSkipVerify bypasses verification of HTTPS certificate when talking to web proxy
InsecureSkipVerify bool
// IsUnderTest is set to true for unit testing
IsUnderTest bool
// Remote SSH session to join
SessionID string
// Src:dest parameter for SCP
Expand Down Expand Up @@ -107,10 +105,6 @@ type CLIConf struct {
Namespace string
// NoCache is used to turn off client cache for nodes discovery
NoCache bool
// LoadSystemAgentOnly when set to true will cause tsh agent to load keys into the system agent and
// then exit. This is useful when calling tsh agent from a script (for example ~/.bash_profile)
// to load keys into your system agent.
LoadSystemAgentOnly bool
// BenchThreads is amount of concurrent threads to run
BenchThreads int
// BenchDuration is a duration for the benchmark
Expand Down Expand Up @@ -165,6 +159,10 @@ type CLIConf struct {
// Browser can be used to pass the name of a browser to override the system default
// (not currently implemented), or set to 'none' to suppress browser opening entirely.
Browser string

// UseLocalSSHAgent set to false will prevent this client from attempting to
// connect to the local ssh-agent (or similar) socket at $SSH_AUTH_SOCK.
UseLocalSSHAgent bool
}

func main() {
Expand All @@ -181,21 +179,21 @@ func main() {
default:
cmdLine = cmdLineOrig
}
Run(cmdLine, false)
Run(cmdLine)
}

const (
clusterEnvVar = "TELEPORT_SITE"
clusterHelp = "Specify the cluster to connect"
bindAddrEnvVar = "TELEPORT_LOGIN_BIND_ADDR"
authEnvVar = "TELEPORT_AUTH"
browserHelp = "Set to 'none' to suppress browser opening on login"
clusterEnvVar = "TELEPORT_SITE"
clusterHelp = "Specify the cluster to connect"
bindAddrEnvVar = "TELEPORT_LOGIN_BIND_ADDR"
authEnvVar = "TELEPORT_AUTH"
browserHelp = "Set to 'none' to suppress browser opening on login"
useLocalSSHAgentEnvVar = "TELEPORT_USE_LOCAL_SSH_AGENT"
)

// Run executes TSH client. same as main() but easier to test
func Run(args []string, underTest bool) {
func Run(args []string) {
var cf CLIConf
cf.IsUnderTest = underTest
utils.InitLogger(utils.LoggingForCLI, logrus.WarnLevel)

// configure CLI argument parser:
Expand All @@ -220,6 +218,10 @@ func Run(args []string, underTest bool) {
app.Flag("gops-addr", "Specify gops addr to listen on").Hidden().StringVar(&cf.GopsAddr)
app.Flag("skip-version-check", "Skip version checking between server and client.").BoolVar(&cf.SkipVersionCheck)
app.Flag("debug", "Verbose logging to stdout").Short('d').BoolVar(&cf.Debug)
app.Flag("use-local-ssh-agent", "Load generated SSH certificates into the local ssh-agent (specified via $SSH_AUTH_SOCK). You can also set TELEPORT_USE_LOCAL_SSH_AGENT environment variable. Default is true.").
Envar(useLocalSSHAgentEnvVar).
Default("true").
BoolVar(&cf.UseLocalSSHAgent)
app.HelpFlag.Short('h')
ver := app.Command("version", "Print the version")
// ssh
Expand Down Expand Up @@ -1086,6 +1088,12 @@ func makeClient(cf *CLIConf, useProfileLogin bool) (*client.TeleportClient, erro
// (not currently implemented) or set to 'none' to suppress browser opening entirely.
c.Browser = cf.Browser

// Do not write SSH certs into the local ssh-agent if user requested it.
//
// This is specifically for gpg-agent, which doesn't support SSH
// certificates (https://dev.gnupg.org/T1756)
c.UseLocalSSHAgent = cf.UseLocalSSHAgent

tc, err := client.NewClient(c)
if err != nil {
return nil, trace.Wrap(err)
Expand Down

0 comments on commit 5fbbb7e

Please sign in to comment.