PHPを使ってバッチスクリプトなどを作る際、ファイル転送といえば今まではftp経由が主流(?)かと思いますが、昨今のセキュリティに対する意識向上から何らかの暗号化を施したい場合があります。2005年の初めにPECLにssh2拡張モジュールが登録されマニュアルもそれなりにこなれてきましたので、今更ながら試してみました。
今回のゴールは、PHP4.3.11で公開鍵認証を使ってリモートコマンドの実行とファイル転送を行う、というものです。
インストール
まずはインストールした環境ですが、PHPは以下のようなconfigureオプションを付けたPHP4.3.11です。
●PHP4.3.11のconfigureオプション
--with-apxs2=/usr/local/apache2/bin/apxs \
--prefix=/usr/local/lib/php4 \
--with-pear=/usr/local/lib/php4/pear \
--with-config-file-path=/usr/local/lib/php4/ini/4.3.11 \
--with-config-file-scan-dir=/usr/local/lib/php4/ini.d \
--enable-zend-multibyte \
--enable-mbstring \
--enable-mbregex \
--with-dom \
--with-gd=shared \
--with-jpeg-dir \
--with-png-dir \
--with-zlib-dir \
--with-ttf \
--with-freetype-dir \
--enable-gd-jis-conv \
--with-java=shared,/usr/local/jdk \
--enable-xslt \
--with-xslt-sablot \
--with-expat-dir=/usr \
--with-oci8=shared,/u01/app/oracle/product/10.1.0 \
--without-mysql \
--with-pgsql=shared \
--enable-debug
「--prefix」オプションを付けているため、phpコマンドのパスがデフォルトとは変わっていますが適宜読み替えてください。
さて、ssh2拡張モジュールのインストールですが、PHPマニュアルにもあるとおり先にopenssl、libssh2をインストールしておく必要があります。なお、最近のLinuxディストリビューションであれば、openssl-develパッケージなど用意されていると思いますので、aptなりup2dateなりyumなりでインストールした方が簡単です。今回の環境ではlibssh2のパッケージは用意されていませんでしたので、ソースから入れることにしました。
libssh2のアーカイブをダウンロード・解凍した後のインストール手順はざっと以下の通りです。今回は2006/01/18現在最新のibssh2-0.12を使用しました。
●libssh2のインストール$ tar zxf libssh2-0.12.tar.gz
$ cd /usr/local/src/libssh2-0.12/
$ ./configure
$ make
$ su
# make install
#
続いて、pearコマンドでssh2拡張モジュールをインストールします。
●ssh2拡張モジュールのインストール# /usr/local/lib/php4/bin/pear install ssh2
downloading ssh2-0.10.tgz ...
Starting to download ssh2-0.10.tgz (22,187 bytes)
........done: 22,187 bytes
5 source files, building
running: phpize
Configuring for:
PHP Api Version: 20020918
Zend Module Api No: 20020429
Zend Extension Api No: 20021010
:
install ok: ssh2 0.10
#
インストールが終わったら、ssh2拡張モジュールをロードするようphp.iniに追記します。
●php.iniの編集 :
extension=ssh2.so
:
最後にApacheを再起動し、phpinfoの画面で正しくロードされている事を確認します。
接続のサンプル
まずは、SSHでの接続サンプルです。。。といっても、PHPマニュアルに掲載されているものと変わりありません(^-^; 手順としては、ssh2_connect関数を使用してSSHサーバに接続し、認証用の関数を使用して認証を行います。認証方法にはパスワード認証と公開鍵認証が利用できます。
まず、パスワード認証の場合、ssh2_auth_password関数を使用します。
●パスワード認証の例
<?php
$connection = ssh2_connect('ofnir', 22);
if (!ssh2_auth_password($connection, 'username', 'password')) {
die('Authentication Failed...');
}
echo "Authentication Successful!\n";
?>
公開鍵認証の場合、事前にRSA秘密鍵・公開鍵のペアを作成しておく必要が(当然)あります。また、Apacheと組み合わせる場合はUserディレクティブで指定したユーザー、バッチの場合はバッチを実行するユーザーでの読み込み権限が必要です。今回は、/home/httpd/.sshディレクトリを作成し、所有者をApacheのUserディレクティブでしていたnobodyユーザーにしました。使用する関数は、ssh2_auth_pubkey_fileです。
以下ざっとした手順です。targethostの/etc/ssh/sshd_configの編集が必要になる場合もありますので、適宜Googleで検索してみてください。
●鍵ペアの作成$ ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/home/somebody/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/somebody/.ssh/id_rsa.
Your public key has been saved in /home/somebody/.ssh/id_rsa.pub.
The key fingerprint is:
XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX somebody@server
$
●PHP用鍵の設置ディレクトリ作成$ su
# mkdir -p /home/httpd/.ssh
# cp -p ~somebody/.ssh/id_rsa* /home/httpd/.ssh/
# chown -R nobody /home/httpd/
# chmod go-rwx /home/httpd/.ssh/
#
●公開鍵を対象サーバにコピーしauthorized_keys2を作成$ scp /home/somebody/.ssh/id_rsa.pub targethost:./
somebody@targethost's password:
$ ssh targethost
somebody@targethost's password:
$ mkdir .ssh
$ chmod 700 .ssh/
$ mv id_rsa.pub .ssh/authorized_keys2
$
●公開鍵認証の例
<?php
$connection = ssh2_connect('targethost', 22, array('hostkey'=>'ssh-rsa'));
if (!ssh2_auth_pubkey_file($connection, 'somebody',
'/home/httpd/.ssh/id_rsa.pub',
'/home/httpd/.ssh/id_rsa',
'passphrase')) {
die('Public Key Authentication Failed');
}
echo "Public Key Authentication Successful\n";
?>
リモートコマンドの実行
コマンド実行はssh2_exec関数で行いますが、結果出力を取得する場合、ssh2_exec関数から返されるストリームのブロックモードを有効にしておく必要があるようです。
<?php
:
$stream = ssh2_exec($connection, 'df -h ');
stream_set_blocking($stream, true);
var_dump(fread($stream, 4096));
?>
ここで返されるストリームはstdoutになります。このため、エラーメッセージなどを取得する場合は、コマンドの後に「2>&1」を付けてstderrと共にstdoutに出力をするか、以下のように一度stderrサブストリームを取得して、結果を取得するようになります。
<?php
:
$stdio_stream = ssh2_exec($connection, 'non-exist-command ');
$stderr_stream = ssh2_fetch_stream($stdio_stream, SSH2_STREAM_STDERR);
stream_set_blocking($stdio_stream, true);
var_dump(fread($stdio_stream, 4096));
var_dump(fread($stderr_stream, 4096));
?>
ファイルの転送
これはPHPマニュアルどおり、コマンド一発で行えます。
<?php
:
if (ssh2_scp_send($connection,
'/home/httpd/test.log',
'/home/shimooka/test.log', 0644)) {
echo '転送成功';
}
else {
echo '転送失敗';
}
?>
まとめ
前から知っていたのですが、試してみるのが今頃になってしまいました。今夏炒めしてみて公開鍵認証が問題なく行えると分かりました。これは使いどころによってはかなり強力ではないかと思います。
通常、バッチスクリプトならshスクリプトで済ませてしまうことが多いのですが、ちょっと凝ったことをするバッチなどに良いかも知れません。
|