Skip to content

Commit 2e8d01c

Browse files
committed
feature: Internal key usage on ssh tunnels
1 parent ef0af81 commit 2e8d01c

File tree

2 files changed

+65
-9
lines changed

2 files changed

+65
-9
lines changed

app/handlers/tunnel.go

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import (
88

99
// OpenTunnel opens ssh tunnel on unix sockets or ports
1010
func OpenTunnel(c *fiber.Ctx) error {
11-
params := []string{"remote_host", "remote_port", "username", "password"}
11+
params := []string{"remote_host", "remote_port"}
1212

1313
for _, param := range params {
1414
if len(c.FormValue(param)) < 1 {
@@ -21,13 +21,26 @@ func OpenTunnel(c *fiber.Ctx) error {
2121
sshPort = "22"
2222
}
2323

24-
port := bridge.CreateTunnel(
24+
if len(c.FormValue("username")) < 1 {
25+
port, err := bridge.CreateTunnelInternalKey(c)
26+
if err != nil {
27+
return logger.FiberError(fiber.StatusInternalServerError, err.Error())
28+
}
29+
30+
return c.JSON(port)
31+
}
32+
33+
port, err := bridge.CreateTunnel(
2534
c.FormValue("remote_host"),
2635
c.FormValue("remote_port"),
2736
c.FormValue("username"),
2837
c.FormValue("password"),
2938
sshPort,
39+
"ssh",
3040
)
41+
if err != nil {
42+
return logger.FiberError(fiber.StatusInternalServerError, err.Error())
43+
}
3144

3245
return c.JSON(port)
3346
}

internal/bridge/ssh_tunnel.go

Lines changed: 50 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package bridge
22

33
import (
44
"context"
5+
"errors"
56
"fmt"
67
"io"
78
"net"
@@ -11,6 +12,9 @@ import (
1112
"time"
1213

1314
"github.com/avast/retry-go"
15+
"github.com/gofiber/fiber/v2"
16+
"github.com/limanmys/render-engine/app/models"
17+
"github.com/limanmys/render-engine/internal/liman"
1418
"github.com/limanmys/render-engine/pkg/logger"
1519
"github.com/phayes/freeport"
1620
"golang.org/x/crypto/ssh"
@@ -301,8 +305,30 @@ func (t *Tunnel) String() string {
301305
return fmt.Sprintf("%s@%s | %s %s %s", t.user, t.hostAddr, left, mode, right)
302306
}
303307

308+
func CreateTunnelInternalKey(c *fiber.Ctx) (int, error) {
309+
credentials, err := liman.GetCredentials(&models.User{
310+
ID: c.Locals("user_id").(string),
311+
}, &models.Server{
312+
ID: c.FormValue("server_id"),
313+
})
314+
if err != nil {
315+
return 0, err
316+
}
317+
318+
port, err := CreateTunnel(
319+
c.FormValue("remote_host"),
320+
c.FormValue("remote_port"),
321+
credentials.Username,
322+
credentials.Key,
323+
credentials.Port,
324+
credentials.Type,
325+
)
326+
327+
return port, err
328+
}
329+
304330
// CreateTunnel starts a new tunnel instance and sets it into TunnelPool
305-
func CreateTunnel(remoteHost, remotePort, username, password, sshPort string) int {
331+
func CreateTunnel(remoteHost, remotePort, username, password, sshPort, connType string) (int, error) {
306332
// Creating a tunnel cannot exceed 25 seconds
307333
ch := make(chan int)
308334
time.AfterFunc(25*time.Second, func() {
@@ -315,7 +341,7 @@ func CreateTunnel(remoteHost, remotePort, username, password, sshPort string) in
315341
// Check if existing tunnel started, if not wait until starts (max: 25sec)
316342
if err == nil {
317343
if t.password != password {
318-
return 0
344+
return 0, errors.New("password mismatch")
319345
}
320346

321347
startedLoop:
@@ -336,14 +362,14 @@ func CreateTunnel(remoteHost, remotePort, username, password, sshPort string) in
336362
}
337363

338364
t.LastConnection = time.Now()
339-
return t.Port
365+
return t.Port, nil
340366
}
341367

342368
// This part from now creates a new tunnel
343369
port, err := freeport.GetFreePort()
344370
if err != nil {
345371
logger.Sugar().Errorw(err.Error())
346-
return 0
372+
return 0, errors.New("couldnt find a free port")
347373
}
348374

349375
dial := net.JoinHostPort("127.0.0.1", remotePort)
@@ -355,8 +381,8 @@ func CreateTunnel(remoteHost, remotePort, username, password, sshPort string) in
355381
}
356382

357383
ctx, cancel := context.WithCancel(context.Background())
384+
358385
sshTunnel := &Tunnel{
359-
auth: []ssh.AuthMethod{ssh.RetryableAuthMethod(ssh.Password(password), 3)},
360386
hostKeys: ssh.InsecureIgnoreHostKey(),
361387
user: username,
362388
mode: '>',
@@ -376,6 +402,23 @@ func CreateTunnel(remoteHost, remotePort, username, password, sshPort string) in
376402
cancel: cancel,
377403
}
378404

405+
if connType == "ssh" {
406+
sshTunnel.auth = []ssh.AuthMethod{
407+
ssh.RetryableAuthMethod(ssh.Password(password), 3),
408+
}
409+
}
410+
411+
if connType == "ssh_certificate" {
412+
key, err := ssh.ParsePrivateKey([]byte(password))
413+
if err != nil {
414+
return 0, errors.New("an error occured while parsing ssh key")
415+
}
416+
417+
sshTunnel.auth = []ssh.AuthMethod{
418+
ssh.RetryableAuthMethod(ssh.PublicKeys(key), 3),
419+
}
420+
}
421+
379422
Tunnels.Set(remoteHost, remotePort, username, sshTunnel)
380423
go sshTunnel.Start()
381424

@@ -398,8 +441,8 @@ loop:
398441

399442
if !sshTunnel.Started {
400443
cancel()
401-
return 0
444+
return 0, errors.New("cannot start tunnel")
402445
}
403446

404-
return sshTunnel.Port
447+
return sshTunnel.Port, nil
405448
}

0 commit comments

Comments
 (0)