エンジニアの生き様をウォッチするメディア

まつもとりーのインフラ入門-第八回「高集積マルチテナントアーキテクチャのセキュリティ(3)」

みなさん、こんにちは。まつもとりーのインフラ入門第八回です。本連載では、主にインターネット基盤技術、または、インターネットのインフラ技術と呼ばれる領域に関して、Webホスティングサービスの歴史やWebサーバの設計と実装を中心に執筆していくと第一回で述べました。

第七回では、これまで述べてきた基礎概念から少し踏み込んで、マルチテナント環境において非常に重要となるセキュリティの研究動向について、第六回に引き続き様々な観点から紹介し、その課題をまとめました。

第八回では、いよいよ前回整理した課題をどのように解決するか、果たして可能なのか等を中心に、引き続きセキュリティについてより踏み込んでいきたます。

前回まとめたセキュリティと性能の課題

高集積にホストを収容するマルチテナント環境において、Webサーバプロセスは複数のホストに対するリクエストを、プロセスを使いまわしながら処理してレスポンスを返します。 その際に、Linux Capabilitiesといった特権を与えられたサーバプロセスは、root権限で実行されていなくても、setuid()およびsetgid()システムコールを実行可能となります。 その後、mod_suid2同様にApacheのサーバプロセス自体を任意のuid、gidに権限変更してから処理を実行し、再度、元のuid、gidに戻します。

この仕組みによって、mod_phpのようなDSO実行方式であっても、PHPスクリプトは権限が異なるため他ホスト領域を閲覧できません。また、実行後でも、元のサーバプロセスの権限に戻すことで、プロセスの再利用も可能にしているため、DSO実行方式の性能を維持できます。

しかし、このようなプロセスは、rootのように全ての特権を持たないものの、setuid()およびsetgid()システムコールを実行できる特権を保持していることになります。すなわち、それが意味するところはWebアプリケーションの脆弱性をつかれ悪意のある者に乗っ取られた場合、setuid()およびsetgid()システムコールによる権限変更を利用し、他ホスト領域のファイル閲覧や変更および不正プログラムの配置や配布等が可能となります。

つまり、サーバプロセス自体に権限を変更できる特権の保持を許したままレスポンスを生成することは、同時に数多くの脆弱性を許すことになります。

一方で、setuid()およびsetgid()システムコールを実行した後にCAP_SETUIDおよびCAP_SETGIDのLinux Capabilitiesを放棄し、処理後にプロセスを復帰できないように改修すれば安全になりますが、やはりそれではワーカプロセスが再利用できなくなり、mod_suid2同様性能は著しく低下することになります。

一般に、サーバプロセスにアクセス制御を設定後に再度解除するというアプローチは性能上の利点を得られますが、共有型の大規模Webホスティング基盤のセキュリティを考える上でリスクが非常に大きく、脆弱性をつかれた場合の利用者や閲覧者への被害は甚大であり、避けるべきと考えられます。

Linuxスレッド単位でDSO方式の権限分離を行う手法

DSO方式の利点は、プログラムを高速に実行できることです。そのため、DSO方式のアクセス制御アーキテクチャを設計する上では、性能劣化を十分考慮しなければなりません。例えば、これまで述べてきたようなCGI実行方式のためのアクセス制御モジュールであるsuEXECのようなプログラム実行時に新たに子プロセスを生成し、コンテンツ処理後にプロセスを破棄するアーキテクチャは、性能を大幅に低下させることにつながります。 また、mod_ruid2のように、プロセスを生成せずにサーバプロセスに権限変更の特権を与えてプロセスを再利用すれば高速に実行できるが、前回述べた通り、 脆弱性が生じます。

そこで、松本らは、Linux上で動作することを前提とし、Linuxにおけるスレッドをpthread_create()関数によって一時的に生成し、そのスレッド上で権限分離を行った後、スレッド配下でプログラムの処理を行い、最後にスレッドを破棄する手法mod_process_securityを提案しています。

https://github.com/matsumotory/mod_process_security
・Ryosuke Matsumoto, Yasuo Okabe, Access Control Architecture Separating Privilege by a Thread on a Web Server, The 12th IEEE/IPSJ International Symposium on Applications and the Internet (SAINT2012), pp.178-183, July 2012.

Linuxにおけるスレッドはプロセス内の同一メモリ空間上で実行でき、メモリ消費量等が軽減できます。また、Linux上では、下記の論文で示されているように、スレッドの生成・破棄はプロセスの生成・破棄よりも処理が軽くなります。

・Gu Y, Lee B S, Cai W, Evaluation of Java Thread Performance on Two Different Multi threaded Kernels, Operating Systems Review, Vol. 33, No. 1, pp. 34-46, 1999.

スレッドの生成・破棄を利用することにより、サーバプロセスを破棄する必要もありません。 下図にDSO実行方式にmod_process_securityを適用した場合の、処理の流れを示します。

Linux上で動作するApacheは、親サーバプロセス(Parent Server Process)から事前にfork()システムコールが実行され生成された複数の子サーバプロセス(Child Server Process)がリクエストを受け付けるために待機しています。リクエストを受け付けると、子サーバプロセス上で一時的にスレッド(Control Thread)を生成します。一時的に生成したスレッドに対し権限変更の特権であるLinux CapabilityのCAP_SETUID、CAP_SETGIDを付与します。この特権によって、スレッドは、スレッド単位で任意のuid、gidに権限変更可能となります。その後、実行対象のプログラムのuig、gid等の権限情報を動的に取得して、その権限にスレッドの権限変更を行います。スレッドの権限変更を行った後は、プログラムを実行する前にスレッドに付与された特権を破棄しておくようにします。これによって、mod_ruid2で生じたような、プログラム経由での権限変更を防止します。スレッド上で直接プログラムを実行した後は、スレッドを破棄して、スレッドが属した子サーバプロセスは再度リクエスト受け付けに再利用されます。

これによって、既存のDSO実行方式のアクセス制御アーキテクチャのように、サーバプロセスの生成破棄をすることなく、安全にアクセス制御を行えます。また、スレッドの生成、破棄の処理時間の短さから性能劣化を低減し、DSO実行方式の特徴である高い性能を維持できます。

実環境での評価

実際にCGIとsuEXECを利用している場合と、mod_phpとmod_process_securityを利用している場合のシステムコールの回数を比較すると、その差が歴然であることがわかります。 以下のコマンドでシステムコールの回数をカウントしながら、実際にphpinfo()を実行するだけのコンテンツにリクエストを送って、レスポンスを受信してみました。

strace -c -f -p PID

すると、suEXECの場合は3377回のシステムコールが発行されているのに対し、mod_process_securityの場合は155回とその差は約20倍以上でした。

また、以下のようなコマンドで実行に時間がかかっているシステムコールを調査すると、実行に時間がかかっているのは、clone()、open()、close()、execve()など、CGIとsuEXEC実行時に一からインタプリタを立ち上げてプロセスを複製している処理に必要なシステムコールがほとんどでした。

cat cgi.log | grep -v epoll_wait | grep -v futex | perl -ane ‘/<([\d\.]+)>/; print $_ if $1 > 0.00005;’

以上のことから、mod_phpにしてインタプリタをApache httpdに直接組み込んだ上で、スレッド単位で権限分離することがどれほど効率的かが理解できます。

さらに、一日のアクセス数が約1000万アクセスあるようなホスティングサーバに対して、CGIとsuEXECで権限分離していたサーバとDSOとmod_process_securityで権限分離した場合のリソース使用量の違いを比較しました。

すると以下の図のように、最近の多くのコンテンツは動的コンテンツであり、PHPなどで動作することが多いため、その実行効率を上げるだけでサーバのリソース使用量、特にCPUの使用量に関しては大きく改善していることがわかりました。

特に、システムコールの数の比較でも大きな差があったように、システムコールのオーバーヘッドが大きく改善したことから、systemのCPU使用量が大きく減少していることがわかります。

まとめ

ということで、今回は、前回まとめた高集積マルチテナント環境のセキュリティと性能要件に関する関連研究の課題に基づき、それらをうまく解決するアーキテクチャとその実装を紹介しました。この実装を利用することによって、実際のリソース使用量も大きく改善し、性能が大きく上がることも確認しました。 それでは、次回以降はこれまでのセキュリティやリソース、性能の観点を踏まえた上で、どのように効率的に運用保守していくかについて、関連研究を踏まえて紹介してきます。

リファレンス
本連載は下記の私が執筆した論文を参考に、新しい読者へ広めるために平易な形へと再編集しています。
・ 松本 亮介, 栗林 健太郎, 岡部 寿男, Webサーバの高集積マルチテナントアーキテクチャと運用技術, 電子情報通信学会論文誌B, Vol.J101-B, No.1, pp.16-30, Jan 2018.
・ copyright©2018 IEICE

(記事:松本 亮介)

京都大学博士(情報学)、さくらインターネット研究所上級研究員、ペパボ研究所客員研究員、Forkwell技術顧問、セキュリティ・キャンプ講師、情報処理学会各種委員、松本亮介事務所所長。

2008年に現場の技術を知るため修士に行かずにホスティング系企業に就職したのち、2012年に異例の修士飛ばしで京都大学大学院の博士課程に入学。インターネット基盤技術の研究に取り組み、mod_mrubyやngx_mrubyなどのOSSを始めとした多数のOSSへの貢献や学術的成果を修める。

2015年4月より2018年10月までGMOペパボ株式会社にてチーフエンジニアとしてプロダクトのアーキテクトやエンジニア組織のマネージメントに従事すると同時に、ペパボ研究所では主席研究員としてOS・Middleware・HTTPに関する研究、及び、事業で実践できるレベルまで作りこむことを目標に研究に従事。

2018年11月より現職のさくらインターネット研究所で上級研究員を務める。

第9回日本OSS奨励賞や2014年度情報処理学会山下記念研究賞など、その他受賞多数。2016年に情報処理学会IPSJ-ONEにおいて時流に乗る日本の若手トップ研究者19名に選出される。