Skip to content

Commit

Permalink
improved ssh service connector
Browse files Browse the repository at this point in the history
  • Loading branch information
doodlesbykumbi committed Oct 22, 2019
1 parent 932e51b commit 7493c14
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 224 deletions.
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,5 @@ require (
k8s.io/client-go v0.0.0-20180806134042-1f13a808da65
k8s.io/kube-openapi v0.0.0-20180731170545-e3762e86a74c // indirect
)

replace golang.org/x/crypto => github.com/doodlesbykumbi/sshr.crypto v0.0.0-20191016154246-b1c2b8ffdb9c
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ github.com/cyberark/summon v0.7.0/go.mod h1:S7grcxHeUxfL1vRTQUyq9jGK8yG6V/tSlLPQ
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/doodlesbykumbi/sshr.crypto v0.0.0-20191016132516-629195587fad h1:dqregO1InniAGdH6O8tVPGPYGlL9kj2Tvkie9UYmlUs=
github.com/doodlesbykumbi/sshr.crypto v0.0.0-20191016132516-629195587fad/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
github.com/doodlesbykumbi/sshr.crypto v0.0.0-20191016154246-b1c2b8ffdb9c h1:dTPA7kSjboC+CYBH0z7cwFKX2GwOb78yyLSqbVRb4qQ=
github.com/doodlesbykumbi/sshr.crypto v0.0.0-20191016154246-b1c2b8ffdb9c/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
Expand Down
146 changes: 112 additions & 34 deletions internal/plugin/connectors/ssh/proxy_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"io/ioutil"
"net"
"os"
"strings"

validation "github.com/go-ozzo/ozzo-validation"
"golang.org/x/crypto/ssh"
Expand Down Expand Up @@ -59,21 +60,6 @@ func NewProxyService(
}, nil
}

func (proxy *proxyService) handleConnections(channels <-chan ssh.NewChannel) error {
var connector = ServiceConnector{
channels: channels,
logger: proxy.logger,
}

backendCredentials, err := proxy.retrieveCredentials()
defer internal.ZeroizeCredentials(backendCredentials)
if err != nil {
return fmt.Errorf("failed on retrieve credentials: %s", err)
}

return connector.Connect(backendCredentials)
}

// Start initiates the net.Listener to listen for incoming connections
// Listen accepts SSH connections and MITMs them using a ServiceConnector.
func (proxy *proxyService) Start() error {
Expand Down Expand Up @@ -128,32 +114,72 @@ func (proxy *proxyService) Start() error {
return
}

// https://godoc.org/golang.org/x/crypto/ssh#NewServerConn
conn, chans, reqs, err := ssh.NewServerConn(nConn, serverConfig)
if err != nil {
logger.Debugf("Failed to handshake: %s", err)
continue
}
logger.Debugf(
"New connection accepted for user %s from %s",
conn.User(),
conn.RemoteAddr(),
)
tcpConn := nConn.(*net.TCPConn)
logger.Debugf("SSH Client connected. ClientIP=%v", tcpConn.RemoteAddr())


// The incoming Request channel must be serviced.
go func() {
for req := range reqs {
logger.Debugf("Global SSH request : %v", req)
backendCredentials, err := proxy.retrieveCredentials()
defer internal.ZeroizeCredentials(backendCredentials)
if err != nil {
logger.Errorf("Failed on retrieve credentials: %s", err)
return
}
}()

go func() {
if err := proxy.handleConnections(chans); err != nil {
logger.Errorf("Failed on handle connection: %s", err)
clientConfig := &ssh.ClientConfig{}
var address string
if addressBytes, ok := backendCredentials["address"]; ok {
address = string(addressBytes)
if !strings.Contains(address, ":") {
address = address + ":22"
}
}

if user, ok := backendCredentials["user"]; ok {
clientConfig.User = string(user)
}

logger.Debugf("Trying to connect with user: %s", clientConfig.User)

if hostKeyStr, ok := backendCredentials["hostKey"]; ok {
var hostKey ssh.PublicKey
if hostKey, err = ssh.ParsePublicKey([]byte(hostKeyStr)); err != nil {
logger.Errorf("Unable to parse public key: %v", err)
return
}
clientConfig.HostKeyCallback = ssh.FixedHostKey(hostKey)
} else {
clientConfig.HostKeyCallback = ssh.InsecureIgnoreHostKey()
}

if password, ok := backendCredentials["password"]; ok {
clientConfig.Auth = append(clientConfig.Auth, ssh.Password(string(password)))
}

if privateKeyBytes, ok := backendCredentials["privateKey"]; ok {
var signer ssh.Signer
if signer, err = ssh.ParsePrivateKey([]byte(privateKeyBytes)); err != nil {
logger.Debugf("Unable to parse private key: %v", err)
return
}

clientConfig.Auth = append(clientConfig.Auth, ssh.PublicKeys(signer))
}

p, err := newSSHProxyConn(
tcpConn,
serverConfig,
clientConfig,
address,
)
if err != nil {
logger.Errorln("Connection from %v closed. %v", tcpConn.RemoteAddr(), err)
return
}
logger.Infof("Establish a proxy connection between %v and %v", tcpConn.RemoteAddr(), p.DestinationHost)

logger.Infof("Connection closed on %v", conn.LocalAddr())
err = p.Wait()
logger.Debugf("Connection from %v closed. %v", tcpConn.RemoteAddr(), err)
}()
}
}()
Expand All @@ -167,3 +193,55 @@ func (proxy *proxyService) Stop() error {
proxy.done = true
return proxy.listener.Close()
}

func newSSHProxyConn(
conn net.Conn,
serverConfig *ssh.ServerConfig,
clientConfig *ssh.ClientConfig,
upstreamHostAndPort string,
) (proxyConn *ssh.ProxyConn, err error) {
d, err := ssh.NewDownstreamConn(conn, serverConfig)
if err != nil {
return nil, err
}
defer func() {
if proxyConn == nil {
d.Close()
}
}()

authRequestMsg, err := d.GetAuthRequestMsg()
if err != nil {
return nil, err
}

// use client provided user if client config is empty
if clientConfig.User == "" {
clientConfig.User = authRequestMsg.User
}

upConn, err := net.Dial("tcp", upstreamHostAndPort)
if err != nil {
return nil, err
}

u, err := ssh.NewUpstreamConn(upConn, clientConfig)
if err != nil {
return nil, err
}
defer func() {
if proxyConn == nil {
u.Close()
}
}()
p := &ssh.ProxyConn{
Upstream: u,
Downstream: d,
}

if err = p.AuthenticateProxyConn(clientConfig); err != nil {
return nil, err
}

return p, nil
}
190 changes: 0 additions & 190 deletions internal/plugin/connectors/ssh/service_connector.go

This file was deleted.

0 comments on commit 7493c14

Please sign in to comment.