mod_mrubyでモジュール型PHPもsuEXEC

mod_mrubyでsuEXECのようなアクセス制御を実装できるようにしました。

しかも、CGIだけでなくモジュール型のPHPやmod_perl等、所謂DSOも簡単にsuEXECのようにサーバプロセスと権限を分離して実行することができます。

以下に、実装例を紹介します。

mod_mrubyで実装してみる

mod_mrubyのビルドで、組み込んでおいた方が良いmrbgemを自動で組み込んでビルドしてくれるbuildスクリプトを作りました。mod_mrubyを簡単に試したいという方は是非使ってみてください。

[program lang=’bash’ escaped=’true’]

git clone git://github.com/matsumoto-r/mod_mruby.git
cd mod_mruby
sh build.sh

[/program]

上記コマンド一発で、便利なmrbgemを組み込んだmod_mrubyモジュールがビルドされます。

その後、httpd.confに以下のように設定します。

[program lang=’apache’ escaped=’true’]

mrubyPostConfigLast            /etc/httpd/hooks/capset.rb
mrubyFixupsLast               /etc/httpd/hooks/suexec.rb

[/program]

続いて、capset.rbに以下のように実装します。

[program lang=’ruby’ escaped=’true’]

c = Capability.new
Apache.errlogger 4, "prepare cap"

[/program]

これによって、親サーバプロセスは80ポートをbindするためにrootで起動しますが、その時にLinuxのCapabilityを一般ユーザである子サーバプロセスが引き継ぐ事ができます。このpost_configというフックは、Apacheの親サーバプロセスの初期化処理(root)のタイミングだと思ってください。

さらに、suexec.rbを以下のように記述します。

[program lang=’ruby’ escaped=’true’]

uid = 501

pid = Process.fork {
  c = Capability.new
  r = Apache::Request.new
  c.get_proc
  cap = [Capability::CAP_SETUID, Capability::CAP_SETGID]
  c.set Capability::CAP_PERMITTED, cap
  c.set Capability::CAP_EFFECTIVE, cap
  c.setuid(uid)
  c.clear Capability::CAP_EFFECTIVE, cap
  c.clear Capability::CAP_PERMITTED, cap
  r.run_handler
  Apache.errlogger 4, "suexec for #{r.filename}. set to uid #{uid}."
}

Process.waitpid pid

[/program]

このように、リクエスト処理を行う直前のフェイズであるFixupsで、子サーバプロセスがさらに親から見た孫プロセスをforkし、さらにそのプロセスにsetuidとsetgidが可能な権限を付与しておきます。そして、CAP_PERMITTEDとCAP_EFFECTIVEを孫プロセスにセットし、孫プロセス自身を任意のuid(サンプルでは501)に変更します。

そして、Webアプリから権限昇格をさせないように、Webアプリ実行前にきちんとCAP_EFFECTIVEとCAP_PERMITTEDをclearしておいてから、r.run_handlerにてコンテンツを処理します。

これによって、例えばsleepするだけのphpスクリプトをmod_phpで動作させると、以下のようなプロセスの状態になります。

[program lang=’text’ escaped=’true’]

apache   29935  0.0  0.1 316740  7576 ?        S    11:39   0:00  ¥_ /usr/sbin/httpd -DFOREGROUND
501      29976  0.0  0.1 316740  7128 ?        S    11:39   0:00  ¦   ¥_ /usr/sbin/httpd -DFOREGROUND
apache   29937  0.0  0.1 316740  7004 ?        S    11:39   0:00  ¥_ /usr/sbin/httpd -DFOREGROUND
apache   29938  0.0  0.1 316740  7004 ?        S    11:39   0:00  ¥_ /usr/sbin/httpd -DFOREGROUND

[/program]

きちんと501でPHPを実行できていますね。

DSOでの権限分離は色々と厄介なのですが、mod_mrubyを使えばこのように柔軟に実装することが可能になります。

まとめ

このように、mod_mrubyを使えば、suEXECやsuPHP、および、DSOに対応したmod_suid2やmod_ruid2のような、サーバプロセスとアプリの権限を分離して実行する処理が簡単に実装できました。

まだまだmod_mrubyはApacheをコントロールできるように改良中ですので、アイデア次第で自分のApacheを簡単かつ強力にカスタマイズすることができるしょう。

mod_mrubyでこんなの作った!とか、こんなの作りたい!とかを教えていただければ、随時対応したいと思っています。

「mod_mrubyでモジュール型PHPもsuEXEC」への1件のフィードバック

  1. ピンバック: Daily Digest for 2013/02/18

コメントは受け付けていません。