Skip to content

Commit 5d55354

Browse files
committed
Add support for ssh-agent
Signed-off-by: yuguorui <[email protected]>
1 parent 2c4ef83 commit 5d55354

File tree

1 file changed

+37
-4
lines changed

1 file changed

+37
-4
lines changed

main.go

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ import (
4545

4646
"github.com/dsnet/golib/jsonfmt"
4747
"golang.org/x/crypto/ssh"
48+
"golang.org/x/crypto/ssh/agent"
4849
"golang.org/x/crypto/ssh/knownhosts"
4950
)
5051

@@ -56,6 +57,8 @@ type TunnelConfig struct {
5657
// If the path is empty, then the server will output to os.Stderr.
5758
LogFile string `json:",omitempty"`
5859

60+
SshAgentSocket string `json:",omitempty"`
61+
5962
// KeyFiles is a list of SSH private key files.
6063
KeyFiles []string
6164

@@ -116,6 +119,21 @@ type KeepAliveConfig struct {
116119
CountMax uint
117120
}
118121

122+
func setupSshAgent(socket string) ssh.AuthMethod {
123+
if len(socket) == 0 {
124+
return nil
125+
}
126+
127+
conn, err := net.Dial("unix", socket)
128+
if err != nil {
129+
log.Printf("Failed to open SSH_AUTH_SOCK %s: %v\n", socket, err)
130+
return nil
131+
}
132+
133+
agentClient := agent.NewClient(conn)
134+
return ssh.PublicKeysCallback(agentClient.Signers)
135+
}
136+
119137
func loadConfig(conf string) (tunns []tunnel, logger *log.Logger, closer func() error) {
120138
var logBuf bytes.Buffer
121139
logger = log.New(io.MultiWriter(os.Stderr, &logBuf), "", log.Ldate|log.Ltime|log.Lshortfile)
@@ -137,6 +155,10 @@ func loadConfig(conf string) (tunns []tunnel, logger *log.Logger, closer func()
137155
if err := json.Unmarshal(c, &config); err != nil {
138156
logger.Fatalf("unable to decode config: %v", err)
139157
}
158+
if config.SshAgentSocket == "" {
159+
// ssh-agent(1) provides a UNIX socket at $SSH_AUTH_SOCK.
160+
config.SshAgentSocket = os.Getenv("SSH_AUTH_SOCK")
161+
}
140162
for _, t := range config.Tunnels {
141163
if config.KeepAlive == nil && t.KeepAlive == nil {
142164
config.KeepAlive = &KeepAliveConfig{Interval: 30, CountMax: 2}
@@ -171,11 +193,10 @@ func loadConfig(conf string) (tunns []tunnel, logger *log.Logger, closer func()
171193
closer = f.Close
172194
}
173195

196+
var auth []ssh.AuthMethod
197+
174198
// Parse all of the private keys.
175199
var keys []ssh.Signer
176-
if len(config.KeyFiles) == 0 {
177-
logger.Fatal("no private keys specified")
178-
}
179200
for _, kf := range config.KeyFiles {
180201
b, err := ioutil.ReadFile(kf)
181202
if err != nil {
@@ -187,7 +208,19 @@ func loadConfig(conf string) (tunns []tunnel, logger *log.Logger, closer func()
187208
}
188209
keys = append(keys, k)
189210
}
190-
auth := []ssh.AuthMethod{ssh.PublicKeys(keys...)}
211+
if len(keys) > 0 {
212+
auth = append(auth, ssh.PublicKeys(keys...))
213+
}
214+
215+
// Setup ssh-agent(1)
216+
agent := setupSshAgent(config.SshAgentSocket)
217+
if agent != nil {
218+
auth = append(auth, agent)
219+
}
220+
221+
if len(auth) == 0 {
222+
logger.Panic("no private keys and ssh-agent usable")
223+
}
191224

192225
// Parse all of the host public keys.
193226
if len(config.KnownHostFiles) == 0 {

0 commit comments

Comments
 (0)