Skip to content

Commit

Permalink
implement rfd 18
Browse files Browse the repository at this point in the history
  • Loading branch information
xacrimon committed Mar 5, 2021
1 parent 6d8f778 commit 201f01d
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 21 deletions.
13 changes: 8 additions & 5 deletions lib/client/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -271,9 +271,12 @@ type Config struct {
// (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
// AddKeysToAgent specifies how the client handles keys.
// auto - will attempt to add keys to agent if the agent supports it
// only - attempt to load keys into agent but don't write them to disk
// on - attempt to load keys into agent
// off - do not attempt to load keys into agent
AddKeysToAgent string

// EnableEscapeSequences will scan Stdin for SSH escape sequences during
// command/shell execution. This also requires Stdin to be an interactive
Expand All @@ -298,7 +301,7 @@ func MakeDefaultConfig() *Config {
Stdout: os.Stdout,
Stderr: os.Stderr,
Stdin: os.Stdin,
UseLocalSSHAgent: true,
AddKeysToAgent: "auto",
EnableEscapeSequences: true,
}
}
Expand Down Expand Up @@ -945,7 +948,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, c.UseLocalSSHAgent)
tc.localAgent, err = NewLocalAgent(c.KeysDir, webProxyHost, c.Username, c.AddKeysToAgent)
if err != nil {
return nil, trace.Wrap(err)
}
Expand Down
23 changes: 17 additions & 6 deletions lib/client/keyagent.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ type LocalKeyAgent struct {

// proxyHost is the proxy for the cluster that his key agent holds keys for.
proxyHost string

// saveKeys dictates whether the agent will save added keys to disk or not.
saveKeys bool
}

// NewKeyStoreCertChecker returns a new certificate checker
Expand Down Expand Up @@ -100,9 +103,14 @@ func NewKeyStoreCertChecker(keyStore LocalKeyStore) ssh.HostKeyCallback {
}
}

func agentSupportsSSHCertificates() bool {
agent := os.Getenv(teleport.SSHAuthSock)
return !strings.Contains(agent, "gpg-agent")
}

// NewLocalAgent reads all Teleport certificates from disk (using FSLocalKeyStore),
// creates a LocalKeyAgent, loads all certificates into it, and returns the agent.
func NewLocalAgent(keyDir, proxyHost, username string, useLocalSSHAgent bool) (a *LocalKeyAgent, err error) {
func NewLocalAgent(keyDir, proxyHost, username string, addKeysToAgent string) (a *LocalKeyAgent, err error) {
keystore, err := NewFSLocalKeyStore(keyDir)
if err != nil {
return nil, trace.Wrap(err)
Expand All @@ -117,9 +125,10 @@ func NewLocalAgent(keyDir, proxyHost, username string, useLocalSSHAgent bool) (a
noHosts: make(map[string]bool),
username: username,
proxyHost: proxyHost,
saveKeys: addKeysToAgent != "only",
}

if useLocalSSHAgent {
if (addKeysToAgent == "auto" || agentSupportsSSHCertificates()) || addKeysToAgent == "only" || addKeysToAgent == "yes" {
a.sshAgent = connectToSSHAgent()
} else {
log.Debug("Skipping connection to the local ssh-agent.")
Expand Down Expand Up @@ -403,10 +412,12 @@ func (a *LocalKeyAgent) defaultHostPromptFunc(host string, key ssh.PublicKey, wr
// AddKey activates a new signed session key by adding it into the keystore and also
// by loading it into the SSH agent
func (a *LocalKeyAgent) AddKey(key *Key) (*agent.AddedKey, error) {
// save it to disk (usually into ~/.tsh)
err := a.keyStore.AddKey(a.proxyHost, a.username, key)
if err != nil {
return nil, trace.Wrap(err)
if a.saveKeys {
// save it to disk (usually into ~/.tsh)
err := a.keyStore.AddKey(a.proxyHost, a.username, key)
if err != nil {
return nil, trace.Wrap(err)
}
}

// load key into the teleport agent and system agent
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 @@ -96,7 +96,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, true)
lka, err := NewLocalAgent(s.keyDir, s.hostname, s.username, "auto")
c.Assert(err, check.IsNil)

// add the key to the local agent, this should write the key
Expand Down Expand Up @@ -155,7 +155,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, true)
lka, err := NewLocalAgent(s.keyDir, s.hostname, s.username, "auto")
c.Assert(err, check.IsNil)

// unload any keys that might be in the agent for this user
Expand Down Expand Up @@ -213,7 +213,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, true)
lka, err := NewLocalAgent(s.keyDir, s.hostname, s.username, "auto")
c.Assert(err, check.IsNil)

// By default user has not refused any hosts.
Expand Down Expand Up @@ -294,7 +294,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, true)
lka, err := NewLocalAgent(s.keyDir, s.hostname, s.username, "auto")
c.Assert(err, check.IsNil)

// by default user has not refused any hosts:
Expand Down Expand Up @@ -348,7 +348,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, true)
a, err := NewLocalAgent(s.keyDir, s.hostname, s.username, "auto")
c.Assert(err, check.IsNil)

_, keyBytes, err := keygen.GenerateKeyPair("")
Expand Down
29 changes: 24 additions & 5 deletions tool/tsh/tsh.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,9 @@ type CLIConf struct {
// connect to the local ssh-agent (or similar) socket at $SSH_AUTH_SOCK.
UseLocalSSHAgent bool

// AddKeysToAgent specifies the behaviour of how certs are handled.
AddKeysToAgent string

// EnableEscapeSequences will scan stdin for SSH escape sequences during
// command/shell execution. This also requires stdin to be an interactive
// terminal.
Expand Down Expand Up @@ -243,6 +246,7 @@ const (
// cluster. All new code should use TELEPORT_CLUSTER instead.
siteEnvVar = "TELEPORT_SITE"
userEnvVar = "TELEPORT_USER"
addKeysToAgentEnvVar = "TELEPORT_ADD_KEYS_TO_AGENT"
useLocalSSHAgentEnvVar = "TELEPORT_USE_LOCAL_SSH_AGENT"

clusterHelp = "Specify the cluster to connect"
Expand Down Expand Up @@ -279,7 +283,9 @@ func Run(args []string, opts ...cliOption) error {
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("add-keys-to-agent", "Controls how keys are handled. Valid values are yes, no, auto or only").Short('k').Envar(addKeysToAgentEnvVar).Default("auto").StringVar(&cf.AddKeysToAgent)
app.Flag("use-local-ssh-agent", fmt.Sprintf("Load generated SSH certificates into the local ssh-agent (specified via $SSH_AUTH_SOCK). You can also set %v environment variable. Default is true.", useLocalSSHAgentEnvVar)).
Hidden().
Envar(useLocalSSHAgentEnvVar).
Default("true").
BoolVar(&cf.UseLocalSSHAgent)
Expand Down Expand Up @@ -460,6 +466,20 @@ func Run(args []string, opts ...cliOption) error {
return trace.Wrap(err)
}

// parameter must be yes, no, auto or only
switch cf.AddKeysToAgent {
case "yes":
break
case "no":
break
case "auto":
break
case "only":
break
default:
return trace.BadParameter("valid values for parameter add-keys-to-agent are yes, no, auto or only, got %s", cf.AddKeysToAgent)
}

// Read in cluster flag from CLI or environment.
readClusterFlag(&cf, os.Getenv)

Expand Down Expand Up @@ -1634,11 +1654,10 @@ 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
c.AddKeysToAgent = cf.AddKeysToAgent
if cf.UseLocalSSHAgent == false {
c.AddKeysToAgent = "off"
}

c.EnableEscapeSequences = cf.EnableEscapeSequences

Expand Down

0 comments on commit 201f01d

Please sign in to comment.