Skip to content

Commit 46e60ae

Browse files
committed
feat: add ssh-agent forwarding support
Signed-off-by: Raulian-Ionut Chiorescu <raulian-ionut.chiorescu@cern.ch>
1 parent f3b78af commit 46e60ae

1 file changed

Lines changed: 71 additions & 3 deletions

File tree

forwardServer.go

Lines changed: 71 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
proto "go.containerssh.io/libcontainerssh/agentprotocol"
1313
config "go.containerssh.io/libcontainerssh/config"
1414
log "go.containerssh.io/libcontainerssh/log"
15+
message "go.containerssh.io/libcontainerssh/message"
1516
)
1617

1718
const (
@@ -155,12 +156,12 @@ func externalDial(log log.Logger, forwardCtx *proto.ForwardCtx, connChan chan *p
155156
switch details.Protocol {
156157
case proto.PROTOCOL_TCP:
157158
protocol = "tcp"
158-
case "unix":
159+
case proto.PROTOCOL_UNIX:
159160
protocol = "unix"
160161
default:
161162
panic(fmt.Errorf("unknown protocol %s", details.Protocol))
162163
}
163-
log.Warning(fmt.Sprintf("Dialing %s %s:%d", setup.Protocol, details.ConnectedAddress, details.ConnectedPort))
164+
log.Debug(message.NewMessage(message.MAgentDialing, "Dialing %s %s:%d", protocol, details.ConnectedAddress, details.ConnectedPort))
164165

165166
dialAddr := parsePort(protocol, details.ConnectedAddress, details.ConnectedPort)
166167

@@ -182,6 +183,71 @@ func externalDial(log log.Logger, forwardCtx *proto.ForwardCtx, connChan chan *p
182183
forwardCtx.WaitFinish()
183184
}
184185

186+
func sshAgentForward(log log.Logger, forwardCtx *proto.ForwardCtx, connChan chan *proto.Connection, setup proto.SetupPacket) {
187+
socketPath := setup.BindHost
188+
if socketPath == "" {
189+
socketPath = "/tmp/ssh-agent.sock"
190+
}
191+
192+
log.Debug(message.NewMessage(message.MAgentSocketSetup, "Setting up SSH agent socket at: %s", socketPath))
193+
194+
_ = os.Remove(socketPath)
195+
196+
sock, err := net.Listen("unix", socketPath)
197+
if err != nil {
198+
log.Error("Failed to create SSH agent socket", err)
199+
return
200+
}
201+
defer sock.Close()
202+
defer os.Remove(socketPath)
203+
204+
err = os.Chmod(socketPath, 0600)
205+
if err != nil {
206+
log.Warning("Failed to set socket permissions", err)
207+
}
208+
209+
log.Debug(message.NewMessage(message.MAgentSocketListening, "SSH agent socket listening on: %s", socketPath))
210+
211+
go func() {
212+
for {
213+
conn, ok := <-connChan
214+
if !ok {
215+
log.Debug(message.NewMessage(message.MAgentChannelClosed, "SSH agent connection channel closed, stopping listener"))
216+
sock.Close()
217+
break
218+
}
219+
_ = conn.Reject()
220+
}
221+
}()
222+
223+
for {
224+
conn, err := sock.Accept()
225+
if err != nil {
226+
log.Debug(message.NewMessage(message.EAgentSocketAcceptFailed, "SSH agent socket accept failed (likely shutdown): %v", err))
227+
break
228+
}
229+
230+
log.Debug(message.NewMessage(message.MAgentConnectionAccepted, "Accepted SSH agent connection from container process"))
231+
232+
agentCon, err := forwardCtx.NewConnectionUnix(
233+
socketPath,
234+
func() error {
235+
return conn.Close()
236+
},
237+
)
238+
if err != nil {
239+
log.Warning("Failed to create SSH agent connection to host", err)
240+
conn.Close()
241+
continue
242+
}
243+
244+
go serveConnection(log, conn, agentCon)
245+
go serveConnection(log, agentCon, conn)
246+
}
247+
248+
forwardCtx.WaitFinish()
249+
}
250+
185251
func forwardServer(stdin io.Reader, stdout io.Writer, stderr io.Writer, exit exitFunc) {
186252
logConfig := config.LogConfig{
187253
Level: config.LogLevelDebug,
@@ -195,7 +261,7 @@ func forwardServer(stdin io.Reader, stdout io.Writer, stderr io.Writer, exit exi
195261
panic(err)
196262
}
197263

198-
log.Debug("Starting agent")
264+
log.Debug(message.NewMessage(message.MAgentStarting, "Starting agent"))
199265
forwardCtx := proto.NewForwardCtx(stdin, stdout, log)
200266

201267
conType, setup, connChan, err := forwardCtx.StartClient()
@@ -215,5 +281,7 @@ func forwardServer(stdin io.Reader, stdout io.Writer, stderr io.Writer, exit exi
215281
fallthrough
216282
case proto.CONNECTION_TYPE_PORT_DIAL:
217283
externalDial(log, forwardCtx, connChan, setup)
284+
case proto.CONNECTION_TYPE_SSH_AGENT:
285+
sshAgentForward(log, forwardCtx, connChan, setup)
218286
}
219287
}

0 commit comments

Comments
 (0)