Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement support for the PROXY protocol #108

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions config/ssh.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ type SSHConfig struct {
// See https://tools.ietf.org/html/rfc4253#page-4 section 4.2. Protocol Version Exchange
// The trailing CR and LF characters should NOT be added to this string.
ServerVersion SSHServerVersion `json:"serverVersion" yaml:"serverVersion" default:"SSH-2.0-ContainerSSH"`
// AllowedProxies is a list of IP addresses or CIDR ranges that are allowed to use the
// PROXY protocol to override the connection originator IP address.
AllowedProxies []string `json:"allowedProxies" yaml:"allowedProxies"`
// Ciphers are the ciphers offered to the client.
Ciphers SSHCipherList `json:"ciphers" yaml:"ciphers" default:"[\"[email protected]\",\"[email protected]\",\"[email protected]\",\"aes256-ctr\",\"aes192-ctr\",\"aes128-ctr\"]" comment:"SSHCipher suites to use"`
// KexAlgorithms are the key exchange algorithms offered to the client.
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ require (
github.com/mitchellh/mapstructure v1.4.3
github.com/opencontainers/image-spec v1.0.2
github.com/oschwald/geoip2-golang v1.5.0
github.com/pires/go-proxyproto v0.6.1
github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494
github.com/stretchr/testify v1.7.0
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -628,6 +628,8 @@ github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/9
github.com/pelletier/go-toml v1.8.1 h1:1Nf83orprkJyknT6h7zbuEGUEjcyVlCxSUGTENmNCRM=
github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/pires/go-proxyproto v0.6.1 h1:EBupykFmo22SDjv4fQVQd2J9NOoLPmyZA/15ldOGkPw=
github.com/pires/go-proxyproto v0.6.1/go.mod h1:Odh9VFOZJCf9G8cLW5o435Xf1J95Jw9Gw5rnCjcwzAY=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
Expand Down
22 changes: 19 additions & 3 deletions internal/sshserver/serverImpl.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
messageCodes "github.com/containerssh/libcontainerssh/message"
"github.com/containerssh/libcontainerssh/service"
"golang.org/x/crypto/ssh"
"github.com/pires/go-proxyproto"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a third party library and should be abstracted away with its own package, including tests so it can be replaced if need be.

)

type serverImpl struct {
Expand Down Expand Up @@ -54,11 +55,20 @@ func (s *serverImpl) RunWithLifecycle(lifecycle service.Lifecycle) error {
Control: s.socketControl,
}

useProxy := len(s.cfg.AllowedProxies) > 0

netListener, err := listenConfig.Listen(lifecycle.Context(), "tcp", s.cfg.Listen)
if err != nil {
s.lock.Unlock()
return messageCodes.Wrap(err, messageCodes.ESSHStartFailed, "failed to start SSH server on %s", s.cfg.Listen)
}
if useProxy {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems to me that PROXY is a wrapper protocol like many others (e.g. websocket). We should consider creating a generic abstraction for wrapper protocols.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't foresee having any other wrapping protocols in-front of the ssh server since, we can consider that if it's necessary further down the line.

policy := proxyproto.MustStrictWhiteListPolicy(s.cfg.AllowedProxies)
netListener = &proxyproto.Listener{
Listener: netListener,
Policy: policy,
}
}
s.listenSocket = netListener
s.lock.Unlock()
if err := s.handler.OnReady(); err != nil {
Expand All @@ -84,7 +94,13 @@ func (s *serverImpl) RunWithLifecycle(lifecycle service.Lifecycle) error {
break
}
s.wg.Add(1)
go s.handleConnection(tcpConn)
logger := s.logger
if useProxy {
proxyConn := tcpConn.(*proxyproto.Conn)
proxyIp := proxyConn.Raw().RemoteAddr()
logger = logger.WithLabel("fromProxy", proxyIp.(*net.TCPAddr).IP.String())
This conversation was marked as resolved.
Show resolved Hide resolved
}
go s.handleConnection(logger, tcpConn)
}
lifecycle.Stopping()
s.shuttingDown = true
Expand Down Expand Up @@ -501,10 +517,10 @@ func (s *serverImpl) createPasswordCallback(
return passwordCallback
}

func (s *serverImpl) handleConnection(conn net.Conn) {
func (s *serverImpl) handleConnection(logger log.Logger, conn net.Conn) {
addr := conn.RemoteAddr().(*net.TCPAddr)
connectionID := GenerateConnectionID()
logger := s.logger.
logger = logger.
WithLabel("remoteAddr", addr.IP.String()).
WithLabel("connectionId", connectionID)
handlerNetworkConnection, err := s.handler.OnNetworkConnection(*addr, connectionID)
Expand Down