Rubyで設定が書けるTrusterd HTTP/2 WebサーバのDockerイメージ公開

mrubyを組み込む事によりRubyで設定を書く事ができるTrusterd HTTP/2 Web ServerDockerイメージを作成・公開しました。

Docker環境のある方は、以下のコマンドで簡単にHTTP/2を喋るWebサーバTrusterdを動かす事ができます。

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

sudo docker run -d -p 8080:8080 matsumotory/trusterd

[/program]

その後、HTTP/2クライアントであるnghttp(これはnghttp2をビルドして準備してください)コマンドで以下のようにアクセスすると、

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

$ nghttp http://127.0.0.1:8080/index.html

Hello Trusterd HTTP/2 world on Docker.

[/program]

というように、HTTP/2によるコンテンツGETができると思います。

また、Trusterdの設定を弄りたい人は、GitHubのTrusterdレポジトリをcloneしてきて

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

trusterd/docker/conf/trusterd.conf.rb

[/program]

のファイルに設定を書き、さらにコンテンツを追加する場合は、

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

trusterd/docker/htdocs/

[/program]

以下にファイルを放りこんで、それぞれ以下のようなコマンドでDockerビルドし直してください。

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

sudo docker build -t local/trusterd .

[/program]

ではでは以上のように非常に簡単にHTTP/2なWebサーバTrusterdを動かして、設定をRubyで色々書いてみたり、ベンチマークをとるなどして遊んでみてください!

ちょっと明日から1人でLinuxの旅に行ってくる

転職エントリが多数見られる8月ですが、これは残念ながら転職エントリではありません。すみません。

前々からずっとやりたいと思っていたのですが、子供が生まれたりと色々バタバタしていて、まとまった時間がどうしても取れず実現できていなかった「Linuxの旅」に、ついに明日から行って参ります!もちろん目的は、技術・研究に対するモチベーションを高める事です!

IMG_4995

「Linuxの旅?なにそれ」

と思った方も多いでしょう。簡単に紹介します。

Linuxの旅といっても、持ち物は必要最低限でノートパソコンすら持って行きません。必要最低限の着替えと青春18切符を握りしめ、大阪からJRをひたすら乗り継いで札幌まで5、6日間かけて向かいます。

え?Linuxの旅なのにノートパソコン無いなんて大丈夫?と思われた皆さん、大丈夫です。Linuxの旅の持ち物は、以下となります。

  • 着替え
  • iPhoneのバッテリー
  • iPhone
  • 財布
  • LINUXプログラミングインタフェース 1冊

LINUXプログラミングインタフェース!!!!???

IMG_4996

そうです、LINUXプログラミングインタフェースを片手(両手)に、ひたすら電車の中で読み続ける青春18切符の旅こそが、僕が勝手に決めた「Linuxの旅」なのです。

予定としては、

  • 1日目 大阪〜金沢らへん
  • 2日目 金沢〜新潟らへん
  • 3日目 新潟〜青森らへん
  • 4日目 青森〜函館らへん
  • 5日目 函館〜札幌らへん

という、超曖昧で前後しまくりの予定を立てていますが、まぁLINUXプログラミングインターフェイスを読み尽くすことはないだろうと予想しているので、これぐらいのふわっとした予定で良いと思っています。また、結局道中はiPhoneを触って1日が終わりそうな日もありそうです。4分の1ぐらいは読みたいですねぇ。

というわけで、技術・研究のモチベーションを高めるべく、明日からLinuxの旅に行ってまいります!

(>´・Д・)> 決してIT芸人目指しているわけではございません!

共有WebホスティングでVitrualHost設定に手を入れずにシンボリックリンクのTOCTOU問題を解決するApacheモジュールを作った

共有Webホスティングを提供している業者の皆様は、シンボリックリンクのTOCTOU問題というかなりクリティカルで必ず対応すべき問題をおそらく様々な方法によって解決されていると思います。

しかし一方で、TOCTOU問題をなんとなく放置されている、あるいは、誤解されている場合もあるかもしれません。この問題は、Apacheでシンボリックリンクを使えない(シンボリックリンクにアクセスがあったら4系エラーを返す)設定にしていたとしても、シンボリックリンクファイルを作る事さえできれば、攻撃プログラムを使う事により、apache権限でアクセス可能なファイルにシンボリックリンク経由でアクセスすることが可能となります。また、Apache本体のコアに直接パッチを当てて対応されている方も多いでしょう。

その場合、

  • コアのパッチは今後Apacheのバージョンアップに伴いメンテが面倒になる
  • 幾つか公開されているモジュールは設定の変更箇所が多いので困っている
  • TOCTOU問題をあまりよくわかってない

という状況があると思います。

そこで、あまり既存の共有ホスト、例えばVirtualHostの設定等を変える事なく簡単な設定を追記するのみで共有WebホスティングのTOCTOU問題を解決するApacheモジュールmod_fileownercheckを作りました。

追記1:SetOutputFilterの設定をしなくて良いようにした

インストールは簡単で、apxsでビルドした後いつも通りモジュールをLoadModuleするだけで良いです。

モジュールをロードするだけで、シンボリックリンクのTOCTOU問題を解決できます。ホスティング業者によっては、共有ホスティングの構成が様々でこのモジュールだけでは対応出来ない場合もあると思います。ですので、一度攻撃プログラムを用いて試した上で利用するのが良いと思います。VirtualHost + suEXEC + Directoryのパーミッションのような定番の共有ホスティングの場合は、大抵このモジュールだけで解決できると思います。

仕組み的には単純で、リクエストのあったファイルがApacheによってopenされた時点で、そのopenされたファイルのownerとリクエストのあったファイルパスのownerが一致するかをチェックするものです。

追記2:.htaccessでの上書き防止処理やリクエストパスの途中にシンボリックリンクを含んでいる場合の対処を追加

さらに、.htaccessで上書きできないようモジュールで強制的にoutput filterに追加するようにしました。また、リクエストパスの途中に他のユーザのディレクトリを指すシンボリックリンクが含まれている場合も対応するために、suEXECで設定しているownerとopenしているファイルのownerチェックも行うようにしました。

もしまだApacheのバーチャルホスト等で構築した共有Webホスティングを提供しながら、このTOCTOU問題の対応をされていなかったり、コアに手を入れていたりする場合は是非このmod_fileownercheckをご活用下さい。また、問題がありそうでしたらレポジトリにissueやpull-requestをして頂けると幸いです。

apache bench(ab)コマンドをRubyで拡張できるab-mrubyのDockerイメージを公開

ab-mrubyとはapache bench(abコマンド)のパラメータ設定や、ベンチマーク結果のテストをRubyで書けるベンチマークツールです。今回はそのab-mrubyコマンドのDockerイメージを作りました。

僕みたいにabコマンドを毎日のように使うエンジニアにとっては、ab-mrubyはそれなりに有用だと思っていたのですが、mrubyをビルドしたりaprを使ってabをビルドしたりいまいち使いにくいなぁと思っていました。しかしそれがDockerの登場によって面倒な所はほとんどラッパーできるようになり、ab-mrubyのDockerイメージを作る事によって必要な部分だけを弄ってすぐにab-mrubyを使えるようにしました。

自身のクライアントPCにDockerを入れるのは気軽にできると思うので是非一度遊んでみてください。

ab-mrubyについてご存じない方は以下のエントリを御覧ください。

最新のab-mrubyはGitHubにて公開しています。

簡単な使い方

ab-mrubyに関しては、上記のエントリに書いているので、今回は簡単な使い方の説明のみにします。

まずはab-mrubyのDockerイメージをDocker Hubからpullして下さい。

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

sudo docker pull matsumotory/ab-mruby

[/program]

そして、実際に実行してみましょう。docker runコマンドに加えて最後の引数にURLを指定してやるだけでab-mrubyを試すことができます。

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

$ sudo docker run matsumotory/ab-mruby https://blog.matsumoto-r.jp/
======================================================================
This is ab-mruby using ApacheBench Version 2.3 <$Revision: 1430300 $>
Licensed to MATSUMOTO Ryosuke, https://github.com/matsumoto-r/ab-mruby

                          CONFIG PHASE

======================================================================
  Target Information  URL: https://blog.matsumoto-r.jp/
  Target Information HOST: blog.matsumoto-r.jp
  Target Information PORT: 80
  Target Information PATH: /
  Target Information  SSL: false
======================================================================
This is ab-mruby using ApacheBench Version 2.3 <$Revision: 1430300 $>
Licensed to MATSUMOTO Ryosuke, https://github.com/matsumoto-r/ab-mruby

                            TEST PHASE

======================================================================
[TEST CASE] [true] FailedRequests (0) should be 0
[TEST CASE] [true] WriteErrors (0) should be 0
[TEST CASE] [true] CompleteRequests (100) should be 100
[TEST CASE] [true] TransferRate (1179.60901260841) should be over 500
[TEST CASE] [false] RequestPerSecond (18.4716961893629) should be over 1000
[TEST CASE] [true] TimePerRequest (54.1368799999999) should be under 100
[TEST CASE] [true] TimePerConcurrentRequest (541.368799999999) should be under 3000
[TEST CASE] [true] ConnetcErrors (0) should be 0
[TEST CASE] [true] ReceiveErrors (0) should be 0
[TEST CASE] [true] LengthErrors (0) should be 0
[TEST CASE] [true] ExceptionsErrors (0) should be 0
[TEST CASE] [true] Non2xxResponses (0) should be 0

test suites: [false]

[/program]

すると、予めRubyで記述したベンチマークパラメータとテストケースによって実行されたベンチマークとテストの結果が得られます。おおおお、RequestPerSecondがテストケースの値より低く出ているのでテストが失敗していますねー、とかがわかります。

Rubyでベンチマークパラメータやテストを書いて自分専用のDockerイメージを作る

ab-mrubyのDockerイメージはab-mruby/docker/ディレクトリ以下のRubyで書かれたベンチマークパラメータとテストケースのサンプルを元に実行されています。それらを自分なりに変更したい場合は、

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

git clone https://github.com/matsumoto-r/ab-mruby.git
cd ab-mruby
vi docker/ab-mruby.conf.rb
vi docker/ab-mruby.test.rb
sudo docker build -t local/ab-mruby .
sudo docker run local/ab-mruby https://blog.matsumoto-r.jp/

[/program]

ab-mruby.conf.rbにベンチマークパラメータを、ab-mruby.test.rbにテストケースを書くと、自分なりのベンチマークパラメータやテストケースを反映した自分専用のDockerイメージを作成する事ができます。自由にGitHubからforkして頂き、そこからDocker Hubと連携してベンチマークイメージを作るのも良いと思います。

書き方は、

上記に上げたab-mrubyに関するエントリやab-mrubyのGitHubレポジトリを参考にして下さい。

ab-mrubyのDockerイメージを使って有意義なベンチマークライフを過ごしてみてはいかがでしょうか!

Apacheのシンボリックリンク検査に関するTOCTOU問題をmod_mrubyで解決してみた

共有ホスティングにおいて、各利用ユーザに対してシンボリックリンクの使用を許可していた場合に、他のユーザ領域のコンテンツを閲覧できたりする問題があるため、SymLinksIfOnwerMatchの設定によりリンクのownerとリンク先のファイルのownerが一致していない限りはリンクを辿らないようにする対処がされてきましたが、そもそもリンクの検査とファイル作成のタイミングによっては、検査をすり抜け、閲覧を可能にするTOCTOU問題がありました。

この件に関しては、「Apache HTTPD: `Options -FollowSymLinks` は不完全」に詳しく解説されているのでそちらを見て頂くとして、リンク使用は許可しつつもそのTOCTOU問題を解決するための一つの方法として、open()したコンテンツファイルのfdから情報を検査してownerに不一致があった場合はレスポンスを返さないようにする、というアプローチがあります。

実装として、Apache本体に手を入れたり、Apacheモジュールで対応したり、といくつか方法がありますが、今日はWebホスティングのセキュリテイとmod_mrubyの実装の復習がてら、単純な静的コンテンツへのリクエストにおけるこの問題をmod_mrubyで楽に解決できるようにしてみました。

具体的には、コンテンツがopen()されているアウトプットフィルターフェイズにおいてmod_mrubyで介入し、任意のuidと、open()されているコンテンツのuidが異なっていたらエラーを返す、という処理を書きました。

まずは、Apacheの設定を以下のようにして、

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

SetOutputFilter mruby
mrubyOutputFilter /path/to/solved_link_toctou.rb

[/program]

/path/to/solved_link_toctou.rbを以下のようにします。

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

uid = 1000

f = Apache::Filter.new

if f.uid != uid
  f.error_create Apache::HTTP_SERVICE_UNAVAILABLE
end

[/program]

このように実装することで、f.uidメソッドから既にopen()されたファイルのuid情報を取得できるので、TOCTOU問題を気にすることなくownerのチェックを行えます。上記の例の場合では、openしたコンテンツのuidが1000じゃなければ503エラーを返し、一致すれば何もせずにリクエストのあったコンテンツの内容をそのまま返します。後は幾つか細かい点があるのですが、それを書くと内容が広がりすぎるので一旦はこの程度の検査に留めておきます。

というわけで、mod_mrubyのリハビリがてら、SymLinksIfOnwerMatchTOCTOU問題をmod_mrubyで解決してみました。mod_mrubyだと非常に簡単に書けるので楽でした。