Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass a key file when spawning an ssh command from node.js?

This works from my local terminal:

ssh -i ~/.ec2/mykey.pem [email protected] ls

Of course it does. But when I try the same using node.js' child_process.spawn command it complains that the key does not exist / can't be accessed.

// child process
var childProcess = require('child_process').spawn;

// spawn the slave using slaveId as the key
slaves[slaveId] = childProcess('ssh', [
    '-i /mykey.pem',
    '[email protected]',
    'ls'
])  

Result:

stderr: Warning: Identity file  /mykey.pem not accessible: No such file or directory.  
stderr: Permission denied (publickey).

Things tried:

  1. Variations on the path to key:
    /actual/path/to/mykey.pem
    mykey.pem (with a copy of the file in the root of the node project)
    /mykey.pem (with a copy of the file in the root of the node project)
    ~/.ec2.mykey.pem (where it should be)

  2. Running the command without the ssh part, ie. childProcess(ls); - works.

  3. chmod 644, 600, 400 etc. mykey.pem

My only theory at this point is there is an issue with passing a file reference in and I need to do something using the fs module. (?) And yes, I know there are libraries out there for ssh access with node but they use passwords which won't cut it and anyway, my requirements don't really justify a library.

Please tell me I'm being stupid and that this is possible.

UPDATE:

OK, so I can use the exec command like this:

var childProcess = require('child_process').exec;
slaves[slaveId] = childProcess('ssh -i mykey.pem [email protected] ls',  function (error, stdout, stderr) {...}

Still, I feel like I've been downgraded from creating a true slave using fork with all it's nice messaging and handy properties (my original implementation which runs fine locally) to having a vacuum cleaner and being told to do all the work myself (now that I want to launch slaves on remote hosts).

like image 730
Oliver Lloyd Avatar asked Sep 08 '12 17:09

Oliver Lloyd


People also ask

How do you spawn in node JS?

The spawn function launches a command in a new process and we can use it to pass that command any arguments. For example, here's code to spawn a new process that will execute the pwd command. const { spawn } = require('child_process'); const child = spawn('pwd');

What is Child_process spawn?

child_process.exec() : spawns a shell and runs a command within that shell, passing the stdout and stderr to a callback function when complete.

How do I run an exec in node JS?

The exec() function in Node. js creates a new shell process and executes a command in that shell. The output of the command is kept in a buffer in memory, which you can accept via a callback function passed into exec() .


1 Answers

I seem to be jumping Brandon's comments a lot lately :-). He's right again. When you execute ssh -i ~/.ec2/mykey.pem [email protected] ls, the ssh executable, in this case, gets four arguments: -i, the name of your key file, the address of the host and the command, eg. ls -ltr /tmp. When it sees a -i it expects the next argument to be the name of the key file, not to see the name as a trailing substring of the -i.

Remember that when you spawn a program, you invoke it directly without going through the shell, so you have to pass it exactly the arguments the shell would have passed it after the shell did any expansion, quoting, etc. When you use exec, you're actually passing a command-line string to the shell, so the shell does all that stuff for you, including figuring out where one arguments ends and another begins.

like image 55
ebohlman Avatar answered Oct 11 '22 19:10

ebohlman