Passenger 向けに AppArmor を設定する
2013/01/06
2013年最初の『Rails雑感』のテーマは、AppArmorです。Ubuntu Server上でPassengerを利用してRailsアプリケーションを運用する場合にAppArmorをどう設定すべきかを考えてみたいと思います。
本稿が対象とするUbuntu Serverのバージョンは12.04 LTSです。すでにApacheとPassengerを使ってRailsアプリケーションを運用している、という前提でお話しします。Rubyのバージョンは1.9.3で、/usr/local/bin
にインストールされています。
本稿の内容を実際に試してみたい方は、Rails本番環境構築ガイドを参考にして環境を整えてください。
AppArmorの基礎知識
AppArmorは、Linuxカーネルのセキュリティモジュールの一種です。同様のモジュールとしてはSELinuxがあり、おそらくはこちらの方が有名です。これらのセキュリティモジュールはLinux Security Modules(LSM)と呼ばれるインターフェースを通じて、Linuxカーネルに組み込まれます。基本的には、セキュリティモジュールは1個しかLinuxカーネルに組み込めませんので、Linuxのディストリビューションごとにデフォルトのセキュリティモジュールが異なります。CentOSはSELinuxを、UbuntuはAppArmorを採用しています。
AppArmorは、SELinuxと同様に強制アクセス制御(MAC)と呼ばれる仕組みをLinuxカーネルにもたらします。所有者とグループの概念に基礎を置く伝統的なLinuxのアクセス制御(任意アクセス制御)との違いをまとめると次のようになります:
- 誰が何に対してどんな処理を行えるのかを細かく制御できる。
- セキュリティポリシーは管理者によって一元的に管理される。
- 管理者以外のユーザーは、自分が所有するファイルであってもセキュリティポリシーの範囲を超えてアクセス制限を緩和できない。
Webサイトを運営する視点では、ApacheやMySQLなどのサービスに対してアクセス制限をかけられることが重要です。任意アクセス制御のもとでは、攻撃者がこれらのサービスの乗っ取りに成功すると、事実上何でもやりたい放題だったのですが、強制アクセス制御が適用されていれば、攻撃者はセキュリティポリシーの範囲内でしか動けない、ということになります。つまり、強制アクセス制御を利用すると「サービスを閉じこめる」ことができるのです。
AppArmorでは、サービスごとにプロファイルと呼ばれる設定ファイルを作り、それをAppArmorにロードすることで対象となるサービスがAppArmorの管理下に入ります。その際、サービスごとに強制モード(Enforce mode)と学習モード(Complain mode)の2つのモードのいずれかを選択できます。サービスがセキュリティポリシーに違反するアクセスを行ったときの結果が異なります。前者では単純に拒否されます。後者ではアクセス自体は可能ですが、監査ログに記録が残ります。
AppArmorに関する情報は、http://wiki.apparmor.net が詳しいです(英語)。この記事の執筆にあたっては、特に Mod apparmor example を参照しました。
AppArmorの状態を確認する
では、AppArmorの状態を確認するところから作業を始めましょう。
Ubuntu ServerのインストールされたマシンにSSHでログインして、apparmor
サービスの status を表示します。
$ sudo service apparmor status apparmor module is loaded. 6 profiles are loaded. 6 profiles are in enforce mode. /sbin/dhclient /usr/lib/NetworkManager/nm-dhcp-client.action /usr/lib/connman/scripts/dhclient-script /usr/sbin/mysqld /usr/sbin/ntpd /usr/sbin/tcpdump 0 profiles are in complain mode. 3 processes have profiles defined. 3 processes are in enforce mode. /sbin/dhclient (874) /usr/sbin/mysqld (1093) /usr/sbin/ntpd (1363) 0 processes are in complain mode. 0 processes are unconfined but have a profile defined.
注目すべきは 3 processes are in enforce mode.
に続く3行です。ここに列挙されているプログラムが強制モードでAppArmorの管理に入っています。1個目はDHCP(動的ホスト設定プロトコル)のクライアント、2個目はMySQLサーバ、NTP(時刻同期プロトコル)サーバです。Apacheが入っていませんね。つまり、Apacheは強制アクセス制御によって閉じこめられていない、というわけです。
mod_apparmorの導入
Apacheに強制アクセス制御を導入するには、Apacheモジュールの mod_apparmor
を利用するのが簡便です。
apt-get
でパッケージ libapache2-mod-apparmor
をインストールしましょう。
$ sudo apt-get install libapache2-mod-apparmor
続いて、a2enmod
コマンドで mod_apparmor
をApacheに組み込みます。
$ sudo a2enmod apparmor
すると、/etc/apparmor.d
ディレクトリに、Apache用のプロファイル usr.lib.apache2.mpm-prefork.apache2
が生成されます。初期状態での中身は次の通りです(コメント行と余分な空行を除外してあります)。
#include <tunables/global> /usr/lib/apache2/mpm-prefork/apache2 flags=(complain) { #include <abstractions/base> #include <abstractions/nameservice> capability kill, capability net_bind_service, capability setgid, capability setuid, capability sys_tty_config, / rw, /** mrwlkix, ^DEFAULT_URI flags=(complain) { #include <abstractions/base> #include <abstractions/nameservice> / rw, /** mrwlkix, } ^HANDLING_UNTRUSTED_INPUT flags=(complain) { #include <abstractions/nameservice> / rw, /** mrwlkix, } #include <apache2.d> #include <local/usr.lib.apache2.mpm-prefork.apache2> }
Apache向けのプロファイルを修正
/etc/apparmor.d/usr.lib.apache2.mpm-prefork.apache2
をエディタで開き、capability sys_tty_config,
の直後にに以下の記述を追加します。
capability chown, capability dac_override, capability fowner, capability fsetid, capability sys_ptrace, capability sys_resource,
バーチャルホストの設定変更
次に、バーチャルホストの設定ファイルを修正します。現在の内容は次のようになっています。
<VirtualHost *:80> ServerName example.com AADefaultHatName passenger DocumentRoot /home/kuroda/example/current/public <Directory /home/kuroda/example/current/public> AllowOverride all Options -MultiViews </Directory> (省略) </VirtualHost>
ここで、AllowOverride all
の上に次の記述を挿入してください。
AAHatName passenger
Passenger向けのサブプロファイルを作成
続いて、Passenger向けのサブプロファイルを作成します。ディレクトリ /etc/apparmor.d/apache2.d
の直下に新規ファイル passenger
を作成し、以下の内容を書き込んでください。
^passenger { #include <abstractions/apache2-common> #include <abstractions/base> #include <abstractions/nameservice> /usr/local/bin/ruby rix, /usr/local/lib/ruby/**/*.so m, /usr/local/lib/ruby/** r, /usr/local/lib/ruby/gems/1.9.1/gems/passenger-*/agents/** rix, /var/log/apache2/*.log w, /var/log/apache2/*.log w, /home/kuroda/example/current/** r, /home/kuroda/example/current/public/log/*.log a, }
最後の2行は、実際のディレクトリ構成に従って変更してください。
プロファイルの有効化
aa-enforce
コマンドでプロファイルを有効にします。
$ sudo aa-enforce /etc/apparmor.d/usr.lib.apache2.mpm-prefork.apache2
Apacheを再起動します。
$ sudo service apache2 restart
ブラウザでWebサイトにアクセスして、Railsアプリケーションが正常に機能すればOKです。うまく行かない場合は、まずはプロファイルの書き間違いを疑ってください。誤りがあれば修正し、次のコマンドでプロファイルをリロードしてください。
$ sudo apparmor_parser -r /etc/apparmor.d/usr.lib.apache2.mpm-prefork.apache2
もし、プロファイルに間違いがないのにRailsアプリケーションが正常に動作しない場合は、aa-genprof
ユーティリティを用いてプロファイルを修正するのですが、これについてはまたの機会に。