GithubHelp home page GithubHelp logo

stocard / node-ssh-forward Goto Github PK

View Code? Open in Web Editor NEW
61.0 13.0 40.0 170 KB

Another easy node ssh forwarding lib (with port forwarding and jump host support)

License: Apache License 2.0

TypeScript 84.86% Dockerfile 10.72% Shell 4.42%

node-ssh-forward's Introduction

node-ssh-Forward

Another easy simple ssh lib for forwarding ports, command execution and interactive shell support.

Has in-built support for bastion hosts (also known as jump hosts).

$ npm install node-ssh-forward

or

$ yarn add node-ssh-forward

Setting up the initial ssh connection (using a bastion host)

import { SSHConnection } from 'node-ssh-forward'

const sshConnection = new SSHConnection({
  endHost: 'example.com',
  bastionHost: 'my-bastion-host.com'
})

Port forwarding

$ ssh -L 9000:imgur.com:80 example.com
const sshConnection = new SSHConnection({
  endHost: 'example.com',
})
await sshConnection.forward({
  fromPort: 9000,
  toPort: 80,
  toHost: 'imgur.com'
})

Port forwarding and using a bastion/jump host

$ ssh -L 9000:localhost:80 -J your-jump-host.com example.com
const sshConnection = new SSHConnection({
  endHost: 'example.com',
  bastionHost: 'your-jump-host.com'
})
await sshConnection.forward({
  fromPort: 9000,
  toPort: 80,
})

Executing a command on the remote server

const sshConnection = new SSHConnection({
  endHost: 'example.com',
  bastionHost: 'your-jump-host.com'
})
await sshConnection.executeCommand('uptime')

new SSHConnection(options)

Options are an object with following properties:

  • username (optional): The username used for your ssh connection (equivalent to -l option). If not set, it first looks for an SSH_USERNAME environment variable. If that is not set, it fallbacks to USER environment variable.
  • password (optional): Provide a password to authenticate with username and password, not private key. Also see skipAutoPrivateKey.
  • privateKey (optional): Can be a string or Buffer that contains a private key. If not set, it fallbacks to ~/.ssh/id_rsa
  • skipAutoPrivateKey (optional): Don't try and read ~/.ssh/id_rsa if no private key is provided
  • agentForward (optional): Is a boolean which uses the ssh-agent for connection (defaults to false). If set defaults to the value of env.SSH_AUTH_SOCK (all platforms), then pageant on Windows if no SSH_AUTH_SOCK is present.
  • agentSocket (optional): Provide your own path to the SSH Agent Socket you want to use. Useful if your app doesn't have access to ENV directly.
  • endHost (required): The host you want to end up on (connect to)
  • endPort (optional): Port number of the server. Needed in case the server runs on a custom port (defaults to 22)
  • bastionHost (optional): You can specify a bastion host if you want
  • passphrase (optional): You can specify the passphrase when you have an encrypted private key. If you don't specify the passphrase and you use an encrypted private key, you get prompted in the command line.
  • noReadline (optional): Don't prompt for private key passphrases using readline (eg if this is not run in an interactive session)

connection.executeCommand(command: string): Promise<void>

Executes a command on the server. Promise will resolve after the command has been executed.

connection.tty(): Promise<void>

Starts an interactive shell session. Will resolve when then client has logged out from the server.

connection.forward(forwardOptions: Object)

Established port-forwarding. Promise resolves after the forwarding has been established. Forwarding can be stopped by calling connection.shutdown()

Possible options for forwardOptions:

  • fromPort (required): Specifies the port on your local computer
  • toPort (required): The port on endHost (specified in the SSHConnection options).
  • toHost (optional): You can specify an additional toHost when you want to forward a port from a different server than your endHost.

connection.shutdown()

Closes all connections.

Developing

  • Add your wanted feature to the implementation in ./src
  • Add test in ./test/test.ts
  • Run the test with ./test/test.sh

Limitations/Todos

  • host based authentication
  • Better documentation
  • Debug logging
  • Ability to pass an additional string to the forward that specifies when the promise is resolved and the forwarding is stopped

node-ssh-forward's People

Contributors

dependabot[bot] avatar faulik avatar junkern avatar r3dsm0k3 avatar rathboma avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

node-ssh-forward's Issues

Host key verification / MITM

It appears this library is not performing verification of the remote ssh host key (~/.ssh/known_hosts) and blindly accepts any connection, potentially compromising the login & all subsequent traffic if a MITM attack is in place.

This comes from the underlying ssh2 lib, where it is only an optional option:

hostVerifier - (...) Default: (auto-accept if hostVerifier is not set)
https://github.com/mscdex/ssh2/blob/70f90f52ff2e8535a0b96834d8655db16bc6d6fd/README.md?plain=1#L927

I think there should at least be a way to opt-in to that (easiest: statically pass the hostkey) and a clear warning to make users aware of the risk.

Cannot forward or connect to the server

var SSHConnection=require('node-ssh-forward').SSHConnection;
 
const sshConnection = new SSHConnection({
  endHost: 'ubuntu@publicIP,
  privateKey: 'keyPath'
})
await sshConnection.forward({
  fromPort: 5000,
  toPort: 5000,
  toHost: 'localhost'
})

I got this following error message

await sshConnection.forward({
^^^^^

SyntaxError: await is only valid in async function
    at createScript (vm.js:80:10)
    at Object.runInThisContext (vm.js:139:10)
    at Module._compile (module.js:616:28)
    at Object.Module._extensions..js (module.js:663:10)
    at Module.load (module.js:565:32)
    at tryModuleLoad (module.js:505:12)
    at Function.Module._load (module.js:497:3)
    at Function.Module.runMain (module.js:693:10)
    at startup (bootstrap_node.js:188:16)
    at bootstrap_node.js:609:3

Error: connect ECONNREFUSED 127.0.0.1:9000

I really don't know why, buy I always receive:

Error: connect ECONNREFUSED 127.0.0.1:9000
    at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1141:16) {
  errno: 'ECONNREFUSED',
  code: 'ECONNREFUSED',
  syscall: 'connect',
  address: '127.0.0.1',
  port: 9000
}

Even though I set the fromPort and toHost in forward function

Is it possible to connect to remote mongo with port forwarding

This is more like a "how-to" question. A bit of unusual scenario, I am trying to connect to remote mongo, which is behind a bastion. I wanted to use port forwarding, so my local port 27017 would be connected to 127.0.0.1:27017 on the end host (that runs mongo).
When I run this command in terminal (removed sensitive data):

ssh -L 27017:localhost:27017 -J [email protected] [email protected]

I then can connect to mongodb on localhost:27017. I use private key to authenticate, which is in default .ssh folder.
I seem to use same settings for node-ssh-forward, but connection gets stuck. Code in index.js:

const { SSHConnection } = require('node-ssh-forward')

;(async () => {
  const sshConnection = new SSHConnection({
    username: 'user',
    endHost: 'mongo.private',
    bastionHost: 'bastion.com'
  })
  await sshConnection.forward({
    fromPort: 27017,
    toPort: 27017
  })

  console.log(12345) // This never gets logged
})()

What am I missing? Is this even possible in theory that after await sshConnection.forward I should be able to connect to mongo on localhost:27017?

Missing support for returning shell stdout?

I may be missing how this is accomplished, but it seems like you should be able to return the stdout result from the executeCommand.

Example:
...
let result=await ssh.executeCommand('uptime')
console.log(result)

16:04:14 up 1079 days, 18:31, 1 user, load average: 0.00, 0.00, 0.00

Timeout option

Can we add support for passing timeout parameter to ssh2?
I can submit PR

Ability to Respond To Keyboard-Interactive Events

Hi There,

Would you be open to a PR to allow interactive keyboard prompts coming back from the SSH server?

I've got a use case where I'd like to be able to create a tunnel and use a private key as well as multi-factor authentication, in order to create the tunnel and use it. See this article for how MFA can be setup with Amazon Linux:
https://www.middlewareinventory.com/blog/aws-mfa-ssh-ec2-setup/
This can be done with other Linux variants as well.

This is easy to accomplish with "ssh2" which you're already using. If you look at the docs for "ssh2" you'll see that there is a "tryKeyboard" option that you can set which will allow keyboard interactivity. If you set it to try, you need to provide an implementation for the "keyboard-interactive" event.

My plan is to add a single option to the SSHConnection option in "node-ssh-forward" called "tryKeyboard". I'll also provide an implementation for "keyboard-interactive" that'll simply display the interactive prompts from the server if thee are any, and allow the user to submit their response to those prompts.

This will require no additional libraries and will create no bloat. Would you be game?

Modules not found

Hi i am fairly new with this but i am facing the following problems while running this app. Any insights as to what is happening
Screenshot from 2022-07-08 13-15-02
?

Need to set endPort

I tried to use it but there was problem that we didn't connect our server by using default port.
I think ssh2 can set custom port to connect server.
So, it's gonna work well with my request if you change a little thing.

SSH2 Critical Vulnerability

Hello node-ssh-forward team.

There seems to be a critical vulnerability with one of the packages you are using being
"ssh2": "^0.8.9"

More details at
GHSA-652h-xwhf-q4h6

Would someone be able to update the used package to 1.4.0? Thanks!

I see that dependabot has made a pr #38 to bump it but it failed :(

Catch error when connection lost

I try to catch the error of connection to automatically try to reconnect if something happen on the network.

Once connected and if I disconnect from the network, an error is thrown like this after a few seconds:

node_modules\ssh2\lib\client.js:999
    throw new Error('Not connected');
    ^

Error: Not connected
    at Client.forwardOut (node_modules\ssh2\lib\client.js:999:11)
    at Server.<anonymous> (node_modules\node-ssh-forward\dist\Connection.js:185:28)
    at Server.emit (events.js:315:20)
    at TCP.onconnection (net.js:1555:8)

However it is not detected by the try,catch block around the connection.

export async function main() {
    try {
        let sshConnection = new SSHConnection(options);
        let res = await sshConnection.forward({
          fromPort: fp,
          toPort: tp,
        });
        console.log('connected',res);
    } catch(err){
        console.log('got an error, trying to restart connection',err);
        main();
    }
}

How could I detect this properly without stopping the process?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.