AUTH-2037: Adds support for ssh port forwarding
This commit is contained in:
parent
945bf76897
commit
c2a71c5a51
|
@ -73,6 +73,9 @@ const (
|
||||||
|
|
||||||
// s3URLFlag is the S3 URL of SSH log uploader (e.g. don't use AWS s3 and use google storage bucket instead)
|
// s3URLFlag is the S3 URL of SSH log uploader (e.g. don't use AWS s3 and use google storage bucket instead)
|
||||||
s3URLFlag = "s3-url-host"
|
s3URLFlag = "s3-url-host"
|
||||||
|
|
||||||
|
// disablePortForwarding disables both remote and local ssh port forwarding
|
||||||
|
enablePortForwardingFlag = "enable-port-forwarding"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -387,7 +390,7 @@ func StartServer(c *cli.Context, version string, shutdownC, graceShutdownC chan
|
||||||
}
|
}
|
||||||
|
|
||||||
sshServerAddress := "127.0.0.1:" + c.String(sshPortFlag)
|
sshServerAddress := "127.0.0.1:" + c.String(sshPortFlag)
|
||||||
server, err := sshserver.New(logManager, logger, version, sshServerAddress, shutdownC, c.Duration(sshIdleTimeoutFlag), c.Duration(sshMaxTimeoutFlag))
|
server, err := sshserver.New(logManager, logger, version, sshServerAddress, shutdownC, c.Duration(sshIdleTimeoutFlag), c.Duration(sshMaxTimeoutFlag), c.Bool(enablePortForwardingFlag))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.WithError(err).Error("Cannot create new SSH Server")
|
logger.WithError(err).Error("Cannot create new SSH Server")
|
||||||
return errors.Wrap(err, "Cannot create new SSH Server")
|
return errors.Wrap(err, "Cannot create new SSH Server")
|
||||||
|
@ -1020,5 +1023,11 @@ func tunnelFlags(shouldHide bool) []cli.Flag {
|
||||||
EnvVars: []string{"S3_URL"},
|
EnvVars: []string{"S3_URL"},
|
||||||
Hidden: true,
|
Hidden: true,
|
||||||
}),
|
}),
|
||||||
|
altsrc.NewBoolFlag(&cli.BoolFlag{
|
||||||
|
Name: enablePortForwardingFlag,
|
||||||
|
Usage: "Enables remote and local SSH port forwarding",
|
||||||
|
EnvVars: []string{"ENABLE_PORT_FORWARDING"},
|
||||||
|
Hidden: true,
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,7 +55,7 @@ type SSHServer struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new SSHServer and configures its host keys and authenication by the data provided
|
// New creates a new SSHServer and configures its host keys and authenication by the data provided
|
||||||
func New(logManager sshlog.Manager, logger *logrus.Logger, version, address string, shutdownC chan struct{}, idleTimeout, maxTimeout time.Duration) (*SSHServer, error) {
|
func New(logManager sshlog.Manager, logger *logrus.Logger, version, address string, shutdownC chan struct{}, idleTimeout, maxTimeout time.Duration, enablePortForwarding bool) (*SSHServer, error) {
|
||||||
currentUser, err := user.Current()
|
currentUser, err := user.Current()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -64,23 +64,40 @@ func New(logManager sshlog.Manager, logger *logrus.Logger, version, address stri
|
||||||
return nil, errors.New("cloudflared SSH server needs to run as root")
|
return nil, errors.New("cloudflared SSH server needs to run as root")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
forwardHandler := &ssh.ForwardedTCPHandler{}
|
||||||
sshServer := SSHServer{
|
sshServer := SSHServer{
|
||||||
Server: ssh.Server{
|
Server: ssh.Server{
|
||||||
Addr: address,
|
Addr: address,
|
||||||
MaxTimeout: maxTimeout,
|
MaxTimeout: maxTimeout,
|
||||||
IdleTimeout: idleTimeout,
|
IdleTimeout: idleTimeout,
|
||||||
Version: fmt.Sprintf("SSH-2.0-Cloudflare-Access_%s_%s", version, runtime.GOOS),
|
Version: fmt.Sprintf("SSH-2.0-Cloudflare-Access_%s_%s", version, runtime.GOOS),
|
||||||
|
// Register SSH global Request handlers to respond to tcpip forwarding
|
||||||
|
RequestHandlers: map[string]ssh.RequestHandler{
|
||||||
|
"tcpip-forward": forwardHandler.HandleSSHRequest,
|
||||||
|
"cancel-tcpip-forward": forwardHandler.HandleSSHRequest,
|
||||||
|
},
|
||||||
|
// Register SSH channel types
|
||||||
|
ChannelHandlers: map[string]ssh.ChannelHandler{
|
||||||
|
"session": ssh.DefaultSessionHandler,
|
||||||
|
"direct-tcpip": ssh.DirectTCPIPHandler,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
logger: logger,
|
logger: logger,
|
||||||
shutdownC: shutdownC,
|
shutdownC: shutdownC,
|
||||||
logManager: logManager,
|
logManager: logManager,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if enablePortForwarding {
|
||||||
|
sshServer.LocalPortForwardingCallback = allowForward
|
||||||
|
sshServer.ReversePortForwardingCallback = allowForward
|
||||||
|
}
|
||||||
|
|
||||||
if err := sshServer.configureHostKeys(); err != nil {
|
if err := sshServer.configureHostKeys(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
sshServer.configureAuthentication()
|
sshServer.configureAuthentication()
|
||||||
|
|
||||||
return &sshServer, nil
|
return &sshServer, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -285,19 +302,6 @@ func (s *SSHServer) startPtySession(cmd *exec.Cmd, winCh <-chan ssh.Window, logC
|
||||||
return tty, tty, nil
|
return tty, tty, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets PTY window size for terminal
|
|
||||||
func setWinsize(f *os.File, w, h int) syscall.Errno {
|
|
||||||
_, _, errNo := syscall.Syscall(syscall.SYS_IOCTL, f.Fd(), uintptr(syscall.TIOCSWINSZ),
|
|
||||||
uintptr(unsafe.Pointer(&struct{ h, w, x, y uint16 }{uint16(h), uint16(w), 0, 0})))
|
|
||||||
return errNo
|
|
||||||
}
|
|
||||||
|
|
||||||
func stringToUint32(str string) (uint32, error) {
|
|
||||||
uid, err := strconv.ParseUint(str, 10, 32)
|
|
||||||
return uint32(uid), err
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *SSHServer) logAuditEvent(writer io.WriteCloser, session ssh.Session, sessionID string, eventType string) {
|
func (s *SSHServer) logAuditEvent(writer io.WriteCloser, session ssh.Session, sessionID string, eventType string) {
|
||||||
username := "unknown"
|
username := "unknown"
|
||||||
sshUser, ok := session.Context().Value("sshUser").(*User)
|
sshUser, ok := session.Context().Value("sshUser").(*User)
|
||||||
|
@ -322,3 +326,19 @@ func (s *SSHServer) logAuditEvent(writer io.WriteCloser, session ssh.Session, se
|
||||||
line := string(data) + "\n"
|
line := string(data) + "\n"
|
||||||
writer.Write([]byte(line))
|
writer.Write([]byte(line))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sets PTY window size for terminal
|
||||||
|
func setWinsize(f *os.File, w, h int) syscall.Errno {
|
||||||
|
_, _, errNo := syscall.Syscall(syscall.SYS_IOCTL, f.Fd(), uintptr(syscall.TIOCSWINSZ),
|
||||||
|
uintptr(unsafe.Pointer(&struct{ h, w, x, y uint16 }{uint16(h), uint16(w), 0, 0})))
|
||||||
|
return errNo
|
||||||
|
}
|
||||||
|
|
||||||
|
func stringToUint32(str string) (uint32, error) {
|
||||||
|
uid, err := strconv.ParseUint(str, 10, 32)
|
||||||
|
return uint32(uid), err
|
||||||
|
}
|
||||||
|
|
||||||
|
func allowForward(_ ssh.Context, _ string, _ uint32) bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ import (
|
||||||
|
|
||||||
type SSHServer struct{}
|
type SSHServer struct{}
|
||||||
|
|
||||||
func New(_ sshlog.Manager, _ *logrus.Logger, _, _ string, _ chan struct{}, _, _ time.Duration) (*SSHServer, error) {
|
func New(_ sshlog.Manager, _ *logrus.Logger, _, _ string, _ chan struct{}, _, _ time.Duration, _ bool) (*SSHServer, error) {
|
||||||
return nil, errors.New("cloudflared ssh server is not supported on windows")
|
return nil, errors.New("cloudflared ssh server is not supported on windows")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue