PHP SSH2 and Amazon EC2 .pem's - php

I've been looking for a way to use PHP's SSH2 to create a sort of terminal. To connect to Amazon in a normal terminal, you would use something like ssh -i path_to/key.pem ec2.ip-555-xxx.com. In PHP on the other hand, SSH2 has a function ssh2_auth_pubkey_file . But have run into a bit of a wall here, as Amazon only provides me with 1 private key (.pem) file, and the function has arguments for both private and public keys. Ultimately I'd like to have a client upload a .pem file to the server and be able to connect to a local or remote SSH server with PHP SSH2 on Amazon using that .pem file.

.pem is the server certificate for the apache web server, it has nothing to do with ssh. See: https://serverfault.com/questions/9708/what-is-a-pem-file-and-how-does-it-differ-from-other-openssl-generated-key-file-f
Seems it might also be a combo file with public and private keys in it. In any case it will not work for ssh directly, you will need to convert it to normal files.
You have it backward anyway - amazon will not give you the private key, quite the opposite - you give amazon the public key. You generate the private/public key pair locally, then upload the public key into the .ssh/authorize_keys files.

Personally, I'd recommend phpseclib, a pure PHP SSH2 implementation be used:
<?php
include('Net/SSH2.php');
$key = new Crypt_RSA();
//$key->setPassword('whatever');
$key->loadKey(file_get_contents('privatekey'));
$ssh = new Net_SSH2('www.domain.tld');
if (!$ssh->login('username', $key)) {
exit('Login Failed');
}
echo $ssh->exec('ls -la');
?>

This is how you get the private and public keys from .pem within php
$eKey = file_get_contents('/pathto/key.pem');
$key_private = openssl_get_privatekey($eKey);
$keyDet=openssl_pkey_get_details($key_private);
$key_public = openssl_pkey_get_public(array($keyDet['key'],""));
$keyPDet=openssl_pkey_get_details($key_public);

Related

use ppk file to connect to sftp in PHP

I am having trouble connecting to an SFTP server using a .ppk file that are provided.
I have tried this ppk file in Filezilla and it works.
According to one of the comments in another question it is better to use phpseclib but i didnt find any instructions on how to download files from SFTP using a ppk file. Any directions or suggestions?
Here is the code I'm not sure if that will help or not.
include('Net/SSH2.php');
include('Crypt/RSA.php');
include('Net/SFTP.php');
DEFINE('SERVER','sample.sftp.com');
DEFINE('USER','sampleUserName');
DEFINE('KEY','sample_key_22733_priv.ppk');
$sftp = new Net_SFTP(SERVER);
//I guess this password is useless here
//and i will have to use my ppk file here but i don't know how
if (!$sftp->login(USER, 'password')) {
exit('Login Failed');
}
var_dump($sftp->nlist());
phpseclib works perfectly fine with PPK files, assuming they're RSA keys and not DSA keys. Just initialize a Crypt_RSA object and then call loadKey(file_get_contents('path/to/key.ppk')) on that object.
To download files do $sftp->get('/path/to/filename.ext').
Here's your orig code modified to include all this:
<?php
include('Net/SSH2.php');
include('Crypt/RSA.php');
include('Net/SFTP.php');
DEFINE('SERVER','sample.sftp.com');
DEFINE('USER','sampleUserName');
DEFINE('KEY','sample_key_22733_priv.ppk');
$rsa = new Crypt_RSA();
$rsa->loadKey(file_get_contents(KEY));
$sftp = new Net_SFTP(SERVER);
//I guess this password is useless here
//and i will have to use my ppk file here but i don't know how
if (!$sftp->login(USER, $rsa)) {
exit('Login Failed');
}
echo $sftp->get('/path/to/filename.ext');
Update:
As #neubert confirmed, PPK files are supported but you do need to make sure they are RSA as I explained, but you do not need them in OpenSSH format
Convert your PPK to an OpenSSH RSA key. You can convert this using the PuTTYgen executable: http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html
Once you have it in an RSA key, you can use this with phpseclib: http://phpseclib.sourceforge.net/ssh/auth.html#rsakey

Uploading files using SCP using phpseclib

I need to create 2 functions: one to upload files using SFTP and another using SCP. I'm using phpseclib and the put method; I believe I have the SFTP function done.
Now, I'm trying to do the SCP function. Per http://adomas.eu/phpseclib-for-ssh-and-scp-connections-with-php-for-managing-remote-server-and-data-exchange/, it seems like the following are the things I need to do:
In case of SCP:
1. Including the needed file: include('/path/to/needed/file/Net/SFTP.php');
2. Creating object and making connection:
$sftp = new Net_SFTP('host');
if (!$sftp->login('user', 'password')) { exit('Login Failed'); }
3. Reading contents of a file: $contents=$sftp->get('/file/on/remote/host.txt');
4. Copying file over sftp with php from remote to local host: $sftp->get('/file/on/remote/host.txt', '/file/on/local/host.txt');
5. Copying file over sftp with php from local to remote host: $sftp->put('/file/on/remote/host.txt', '/file/on/local/host.txt');
6. Writing contents to remote file: $sftp->get('/file/on/remote/host.txt', 'contents to write');
I need to do #5, but it looks like what I did for SFTP. SFTP and SCP aren't the same, right? Is the same code correct? If not, how do I do SCP?
As noted by neubert, phpseclib has SCP support now through the Net_SCP class.
You instantiate an Net_SCP object by passing it a Net_SSH2 or Net_SSH1 object in the constructor, and can then use the get() and put() methods to download or upload files via SCP.
Here's a simple example script showing me SCPing a file from my local machine to a remote AWS instance.
<?php
set_include_path(get_include_path() .
PATH_SEPARATOR .
'/home/mark/phpseclib');
require_once('Crypt/RSA.php');
require_once('Net/SSH2.php');
require_once('Net/SCP.php');
$key = new Crypt_RSA();
if (!$key->loadKey(file_get_contents('my_aws_key.pem')))
{
throw new Exception("Failed to load key");
}
$ssh = new Net_SSH2('54.72.223.123');
if (!$ssh->login('ubuntu', $key))
{
throw new Exception("Failed to login");
}
$scp = new Net_SCP($ssh);
if (!$scp->put('my_remote_file_name',
'my_local_file_name',
NET_SCP_LOCAL_FILE))
{
throw new Exception("Failed to send file");
}
?>
phpseclib recently added SCP support:
https://github.com/phpseclib/phpseclib/blob/master/phpseclib/Net/SCP.php
Yes, the SCP is completely different protocol to the SFTP.
The phpseclib now supports the SCP in recent versions (since version 0.3.5, released in June 2013).
Alternatively, use the PHP PECL SSH2 functions for SCP upload/download:
https://www.php.net/manual/en/ref.ssh2.php

phpseclib or ssh2 pecl extension

My post from yesterday: https://stackoverflow.com/questions/14296006/phpseclib-sftp-port-number
Ok, so yesterday I started learning about SSH / SFTP with php. I searched a bunch of forum posts and surmised that i needed to download the phpseclib.
Being relatively new to php thus starting on php5 i was not aware of previous php4's non-use of the __constructor, hence the above question/post.
The responses were conflicting, and a little off topic to the original Q however has delivered me to a question that I feel needs answering before i continue:
Which is better to use, ssh2 pecl extension OR phpseclib?
This question: phpseclib vs libssh2 is the same but I feel a little outdated now as asked on Nov 5 '10 at 17:37
I say phpseclib. Personally, I think you get better support with phpseclib and that the API is better but there are less subjective reasons too:
More portable.
I tried to install libssh2-php on Ubuntu 12.04 and "sudo apt-get install libssh2-php" didn't work for me. And even if it did it likely wouldn't get the latest version. So I had to compile libssh2 and the PECL extension myself which is always a hassle and not something a lot of admins are going to be willing to do.
And even if you are willing to compile stuff let's say your hard drive fails and you have to rebuild the server. If you're willing to compile libssh2 you'll have probably compiled other stuff too. Which means you can't just fire up another box - you have to remember all the changes you made on your old box and reapply them. And what if you don't remember them? Or what if one of them hasn't been updated to work with the latest version of another?
phpseclib, in contrast, doesn't require much of anything other than PHP. It'll use mcrypt, gmp, bcmath or openssl if they're available but if they're not, that's okay, too. And it doesn't even require PHP5, although it certainly supports it.
Better public key support.
How you do it with libssh2:
<?php
$ssh = ssh2_connect('domain.tld');
ssh2_auth_pubkey_file($ssh, 'username', '/home/ubuntu/pubkey', '/home/ubuntu/privkey'/*, 'password'*/);
$stream = ssh2_exec($ssh, 'ls -la');
echo stream_get_contents($stream);
Both have to be of the right format too. If you didn't use ssh-keygen to generate your keys good luck in converting them.
With phpseclib:
<?php
include('Net/SSH2.php');
include('Crypt/RSA.php');
$rsa = new Crypt_RSA();
$rsa->loadKey('...');
$ssh = new Net_SSH2('domain.tld');
$ssh->login('username', $rsa);
//$ssh->setPassword('password');
echo $ssh->exec('ls -la');
Ignoring the API for the time being there are a few clear ways phpseclib comes out on top here:
phpseclib takes in strings - not file paths. If you want to do a file you can do file_get_contents.
phpseclib doesn't require a public key. Most private key formats have the public key embedded within them. And if they don't... phpseclib supports that too.
phpseclib can take in pretty much any standardized format, from PKCS#1 formatted keys, to PuTTY keys, to XML Signature keys
Interactive shell.
Let's try to do sudo on the remote system.
With phpseclib:
http://phpseclib.sourceforge.net/ssh/examples.html#password,sudo,
With libssh2? I have no clue. My best guess (doesn't work):
<?php
$ssh = ssh2_connect('domain.tld');
ssh2_auth_password($ssh, 'username', 'password');
$shell = ssh2_shell($ssh);
echo fread($shell, 1024*1024);
fwrite($shell, "sudo ls -la\n");
$output = fread($shell, 1024*1024);
echo $output;
if (preg_match('#[pP]assword[^:]*:#', $output)) {
fwrite($shell, "password\n");
}
echo fread($shell, 1024*1024);
I can't get top to work with libssh2 either but it works fine with phpseclib:
http://phpseclib.sourceforge.net/ssh/examples.html#password,top,
Diagnosing problems
Why didn't top or sudo work? On phpseclib you can get logs:
http://phpseclib.sourceforge.net/ssh/examples.html#password,oneoff,logging,
They look like this:
http://phpseclib.sourceforge.net/ssh/log.txt
You can also do print_r($ssh->getErrors()) or echo $ssh->getLastError().
Changing Directories
I don't see any cd or chdir functions at http://php.net/ssh2 . phpseclib, however, has it - Net_SFTP::chdir(...)
Speed
libssh2:
<?php
$ssh = ssh2_connect('domain.tld');
ssh2_auth_password($ssh, 'username', 'password');
$start = microtime(true);
$sftp = ssh2_sftp($ssh);
$fp = fopen('ssh2.sftp://'.$sftp.'/home/username/1mb', 'w');
fwrite($fp, str_repeat('a', 1024 * 1024));
$elapsed = microtime(true) - $start;
echo "took $elapsed seconds";
25.71 seconds.
phpseclib:
<?php
include('Net/SFTP.php');
$sftp = new Net_SFTP('domain.tld');
$sftp->login('username', 'password');
$start = microtime(true);
$sftp->put('1mb', str_repeat('a', 1024*1024));
$elapsed = microtime(true) - $start;
echo "took $elapsed seconds";
11.70 seconds.
So phpseclib is more than twice as fast.

PHP Exec SCP does not copy the file to the remote server

I need a file from a server to another server (I own both) using PHP. I have the following script:
<?php
exec('scp /home/pat/file1.tst pat#myserver.com:/home/pat/file1.txt');
I get this error:
Disallowed system call: SYS_pipe
What is that error? and how can I fix it?
PHP environment does not allow exec on your server.
This is kinda late, I know, but you might have better luck with phpseclib's pure PHP SCP implementation:
https://raw.github.com/phpseclib/phpseclib/master/phpseclib/Net/SCP.php
Example of how to use it:
<?php
include('Net/SCP.php');
include('Net/SSH2.php');
$ssh = new Net_SSH2('www.domain.tld');
if (!$ssh->login('username', 'password')) {
exit('bad login');
}
$scp = new Net_SCP($ssh);
$scp->put('abcd', str_repeat('x', 1024*1024));
?>

Deploy a PHP project from Git to a server that does not have Git installed

I need to find a method of deploying a PHP project stored in a git repo to a staging and production server that do not have git installed. Scripts I've found so far (ie Capistrano) require Git on the target server.
Unfortunately, my host does not allow this, and the only way so far is via standard FTP, with which I keep missing files. This makes for an unprofessional look.
I would like to be able to deploy from my local git repo, which will check the .git folder on the target to see which version is on there, then cause the target server to backup the current version and then overwrite it with only the changed files being pushed.
Preferably something in PHP with a web interface.
Not asking much am I ;)
Anyone out there got/seen anything like this?
There are three git-ftp scripts which allow you to "push" a git repository to a FTP server.
git-ftp (bash)
git-ftp (python)
PHPloy (php)
You might be able to use something like Fuse to "mount" the production server as a local drive, and then as far as your copy of git is concerned it's a local operation. Alternatively, rsync.
There's a tool call Dandelion that also does this. From what I can see, it's quite similar to git-ftp, BUT it also supports sftp and Amazon S3, which is handy if you don't want to change deploy tool just because you change server. It comes as a ruby gem, so really easy to install and get going.
I have done something like that using ssh2 and php.
first you need to clone the repo on the server. Once cloned, you can do git pull, checkout, etc from php using ssh2. the most practical way I found was doing.
git fetch;
git reset --hard commit_hash;
in order to get set the commit to the one expected.
To execute a php - ssh2 command (supposing you have ssh2 installed), you can use this method.
public static function SSHCommmand($command,$user,$ip) {
$port = 22;
if (!function_exists("ssh2_connect"))
die("function ssh2_connect doesn't exist.");
$result['debug'] .= " -Connect- 1";
if (!($con = ssh2_connect($ip, $port, array('hostkey' => 'ssh-rsa')) )) {
die("unable to establish connection.");
} else {
// try to authenticate with username root, password secretpassword
if (!(ssh2_auth_pubkey_file($con, $user, '/home/' . $user . '/.ssh/deploy_rsa.pub', '/home/' . $user . '/.ssh/deploy_rsa'/* , 'secret' */))) {
dir("fail: unable to authenticate.");
} else {
// allright, we're in!
// execute a command
if (!($stream = ssh2_exec($con, $command))) {
die("fail: unable to execute command.");
} else {
// collect returning data from command
stream_set_blocking($stream, true);
$data = '';
while ($buf = fread($stream, 4096)) {
$data .= $buf;
}
fclose($stream);
return $data;
}
}
}
}
I'm using ssh-rsa key, the auth method might change. I'm aslo supposing that the keys are in '/home/' . $user . '/.ssh/deploy_rsa.pub' and '/home/' . $user . '/.ssh/deploy_rsa.
The other thing you might take into account is that to execute remote a remote git command, the command should be like:
_GIT_PATH.' --git-dir='.$path.'/.git --work-tree='.$path.' '.$command;
where $path is the toplevel of the working tree.
By using this and the Amazon Api, I've been able to deploy new code to several servers automatically and simultaneously.
I use Beanstalkapp.com, which is great. You can deploy via FTP or SFTP.

Categories