Info: Version 1.8.x is available.
Last modified: $Date: 2024-03-30 20:25:00 +0900 (Sat, 30 Mar 2024) $
今回は TOMOYO Linux の強力なパラメータチェック機能を活用するための「条件付きアクセス許可」について紹介します.
TOMOYO Linux には RBAC ( Role Based Access Control )機能はありませんが,ポリシーの中でユーザIDに基づく条件を付けることができます.これにより,システムアカウントのユーザIDに基づくアクセス制御が可能です.条件はアクセス許可の後ろに「 if 条件式」という形で指定します.利用できる条件について図1に,使い方の例を図2に示します.
■図1 条件指定に使えるパラメータ
|
■図2 条件指定の例
|
例として,コンソールからログインしたユーザが, /bin/cat コマンドで自分の所有するファイルのみを閲覧できるようにする手順について説明します.説明用に, user1 と user2 というアカウントを使用します.コンソールからログインして,以降の操作を行ってください.まず,アカウントを2つ作成します(図3).
■図3 アカウントを2つ作成
# useradd -s /bin/bash user1 # useradd -s /bin/bash user2 |
パスワードを適当に設定してください(図4).
■図4 作成したアカウントのパスワードを設定
# passwd user1 # passwd user2 |
cat コマンド用のドメインを作成するために, /bin/cat コマンドを実行してください.ついでに,このコマンドが動作するドメインも表示してみます(図5).
■図5 cat コマンドが動作するドメインを表示
# cat /proc/ccs/self_domain <kernel> /sbin/mingetty /bin/login /bin/bash /bin/cat |
このドメインに学習用プロファイルを割り当ててください.この連載では学習用プロファイルの番号は1ですので,図6のようになります.
■図6 cat コマンド用ドメインに学習用プロファイルを割り当て
# /usr/sbin/ccs-setprofile 1 '<kernel> /sbin/mingetty /bin/login /bin/bash /bin/cat' |
ログアウトして, user1 としてログインし直します.そして,図7の操作を行ってください.
■図7 user1 でログインし, /tmp/testfile1 を作成
$ echo "This file was created by user1" > /tmp/testfile1 $ cat /tmp/testfile1 This file was created by user1 |
ログアウトして, user2 としてログインし直します. user1 と同様に操作を行ってください(図8).
■図8 user2 でログインし, /tmp/testfile2 を作成
$ echo "This file was created by user2" > /tmp/testfile2 $ cat /tmp/testfile2 This file was created by user2 |
ログアウトして, root としてログインし直します. ccs-editpolicy を起動して,「 <kernel> /sbin/mingetty /bin/login /bin/bash /bin/cat 」ドメインのアクセス許可を確認してください.図9のようなエントリが含まれているはずです.
■図9 <kernel> /sbin/mingetty /bin/login /bin/bash /bin/cat ドメインのアクセス許可
allow_read /tmp/testfile1 allow_read /tmp/testfile2 |
このままではどちらのファイルもDAC(任意アクセス制御)のパーミッションにより許可されれば誰でも読むことができてしまいます.ここで,キーボードの「 A 」を押して,図10のように入力してください.
|
■図10 アクセス許可を追加 (※これらをまとめて, allow_read /tmp/testfile\+ if task.uid=path1.uid のように入力してもかまいません.) allow_read /tmp/testfile1 if task.uid=path1.uid allow_read /tmp/testfile2 if task.uid=path1.uid |
それから,図11の内容をキーボードの「 D 」を押して削除します.
■図11 削除する内容
allow_read /tmp/testfile1 allow_read /tmp/testfile2 |
キーボードの「 Q 」を押して, ccs-editpolicy を終了します.そして, /bin/cat コマンド用のドメインに強制用プロファイルを割り当ててください.この連載では強制用プロファイルの番号は3ですので図12のようになります.
■図12 cat コマンド用ドメインに強制用プロファイルを割り当て
# /usr/sbin/ccs-setprofile 3 '<kernel> /sbin/mingetty /bin/login /bin/bash /bin/cat' |
ログアウトして, user1 としてログインし直します.そして, /tmp/testfile1 と /tmp/testfile2 を /bin/cat コマンドで表示してみてください. /tmp/testfile2 へのアクセスが禁止されていることを確認できます(図13).
■図13 /tmp/testfile2 へのアクセスが禁止されている
$ cat /tmp/testfile1 This file was created by user1 $ cat /tmp/testfile2 cat: /tmp/testfile2: Operation not permitted |
ログアウトして, user2 としてログインし直します. user1 と同様に操作を行ってください. /tmp/testfile1 へのアクセスが禁止されていることを確認できます.変数の代わりにユーザIDを直接指定することもできます.たとえば,ユーザ認証を行ってログインシェルを起動するための「 <kernel> /sbin/mingetty /bin/login 」ドメインに対して,図14のように変更してやると, root ユーザのログインを禁止することができます.
■図14 root ユーザのログインを禁止する設定
[修正前] allow_execute /bin/bash [修正後] allow_execute /bin/bash if task.uid!=0 |
また,図15のように変更してやると,ユーザIDが 500 以上 1000 以下のユーザだけがログインできるようにすることができます.SSH経由でのログインを制限したい場合に使うことができます.
■図15 ユーザID 500 以上 1000 以下のユーザのみログインできる設定
[修正前] allow_execute /bin/bash [修正後] allow_execute /bin/bash if task.uid=500-1000 |
以上で条件付きアクセス許可の説明は終わりです.この説明のために作成したアカウントを削除します(図16).
■図16 図3で作成したアカウントを削除
# userdel user1 # userdel user2 |
ちょっと横道に逸れますが,ここでアクセス制御を行う場合に注意すべき点として,プログラムの起動方法による振る舞いの変化について触れておきたいと思います.システム( TOMOYO Linux カーネルで動作しているシステムである必要はありません)にログインして,図17のプログラムを /tmp/argv0.c という名前で保存してください.
■図17 起動方法を表示するCプログラム
#include <stdio.h>
int main(int argc, char *argv[])
{
printf("I am running as %s\n", argv[0]);
return 0;
}
|
その後,図18のようにコンパイルしておよびシンボリックリンク(またはハードリンク)を作成してください.
■図18 コンパイルしてシンボリックリンクを作成する
# gcc -o /tmp/argv0 /tmp/argv0.c # ln -s /tmp/argv0 /tmp/cat # ln -s /tmp/argv0 /tmp/passwd |
そして,そのシンボリックリンク(またはハードリンク)を実行してください.すると,シンボリックリンクの名前が表示されます(図19).
■図19 シンボリックリンク経由で起動する
# /tmp/cat I am running as /tmp/cat # /tmp/passwd I am running as /tmp/passwd |
一部のコマンドは,そのコマンドが起動されたときの「名前( argv[0] と呼ばれているものです) 」によって振る舞いを変えるように作られています.たとえば, CentOS 5 において, /sbin/pidof は /sbin/killall5 へのシンボリックリンクであり, pidof という名前で起動された場合には指定されたプログラムのプロセスIDを表示し, killall5 という名前で起動された場合には自分のセッション以外のすべてのプロセスにシグナルを送信します.
TOMOYO Linux では /tmp/cat を実行すれば /tmp/cat のドメインで動作し, /tmp/passwd を実行すれば /tmp/passwd のドメインで動作します.では,図20のように /tmp/cat という名前で /tmp/passwd を実行した場合には,どのようになるでしょうか?(結果を予想してみてください)
■図20 passwd コマンドを cat という名前で実行する
# sh -c 'exec -a /tmp/cat /tmp/passwd' |
図20の実行結果は図21となります.このことから,図20を認めることは図22を認めることと同じです.ただし,図22は /tmp/cat ドメインで /tmp/cat として動作するのを認めているのに対して,図20は /tmp/passwd ドメインで /tmp/cat として動作することを認めているという点に注意してください.
■図21 cat コマンドとして動作する
I am running as /tmp/cat |
■図22 図20がもたらす結果
# sh -c 'exec /tmp/cat' |
/usr/bin/passwd コマンドと /bin/cat コマンドが /sbin/busybox のハードリンクまたはシンボリックリンクとして提供されていると仮定します.この場合, TOMOYO Linux では /bin/cat を実行すれば /bin/cat のドメインで動作し, /usr/bin/passwd を実行すれば /usr/bin/passwd のドメインで動作します.パスワードを変更するための /usr/bin/passwd ドメインには /etc/shadow へのアクセスを認める必要がありますが,ファイルの内容を表示するための /bin/cat ドメインには /etc/shadow へのアクセスを認めたくありません.では,図23のように /bin/cat という名前で /usr/bin/passwd を実行した場合には,どのようになるでしょうか?
■図23 passwd コマンドを cat という名前で実行する
# sh -c 'exec -a /bin/cat /usr/bin/passwd /etc/shadow' |
図23を実行すると, /usr/bin/passwd は /usr/bin/passwd ドメインで動作します.しかし,起動時の名前が /bin/cat であったため,その振る舞いは /bin/cat となります.結果として図24のような振る舞いを許可してしまったことになります.
■図24 パスワードファイルを閲覧できる
# sh -c 'exec /bin/cat /etc/shadow' |
このような脅威を防ぐために, TOMOYO Linux ではプログラムのパス名と argv[0] の組み合わせをチェックする機能を備えており,プログラムの実行許可に対しては自動的に exec.realpath および exec.argv[0] という形でシンボリックリンクを解決したパス名と argv[0] も一緒にチェックするようになっています.図23のような脅威も /usr/bin/passwd コマンドを /bin/cat という名前で起動することを禁止することで防ぐことができるようになります.
学習モードで生成されるポリシーに含まれているアクセス許可には exec.realpath と exec.argv[0] と symlink.target だけしか含まれていませんが,アクセスログには図1で示した全ての変数が含まれています.そのため,アクセスログからポリシーを生成してやれば,最も厳格な条件付きアクセス許可を定義することができます.
学習モードでは,一度ポリシー違反が発生すると,そのポリシー違反を起こさないようにするために必要なアクセス許可が自動的に追加されてしまいます.しかし,自動的に追加されるアクセス許可には図1で示した全ての情報が含まれているわけではありません.そのため,プロファイルを図25のように編集して自動的に追加されないようにします.
■図25 /etc/ccs/profile.conf の変更箇所
[修正前]
PREFERENCE::learning={ verbose=no }
[修正後]
PREFERENCE::learning={ verbose=no max_entry=0 }
|
保存したら,図26のコマンドを実行して変更を反映してください.
■図26 変更を反映する
# /usr/sbin/ccs-loadpolicy p |
この状態でプログラムを動作させます.ポリシー違反は全てアクセスログとして保存されていきます.
図25で max_entry=0 という指定をしたため,図27のようなメッセージが大量に表示されますが無視してください.
■図27 学習する件数の上限に達したことを示すメッセージ
WARNING: Domain 'ドメイン名' has so many ACLs to hold. Stopped learning mode. |
grep を用いて mode=learning を含むログを抽出します(図28).前後に空白を含めていることに注意してください.空白を入れ忘れると,ファイル名などと一致してしまう可能性があります.
■図28 学習モードのアクセスログだけを抽出する
# grep -F -A 2 " mode=learning " /var/log/tomoyo/reject_log.conf > /var/log/tomoyo/learning_log.txt |
抽出したら,条件付きのアクセス許可に変換します(図29).
■図29 条件付きのアクセス許可に変換する
# /usr/lib/ccs/convert-audit-log < /var/log/tomoyo/learning_log.txt > /var/log/tomoyo/policy.tmp |
変換したら,ドメイン単位でソートすることにより圧縮します(図30).
■図30 ドメイン単位でソートする
# /usr/sbin/ccs-sortpolicy < /var/log/tomoyo/policy.tmp > /var/log/tomoyo/policy.txt |
/var/log/tomoyo/policy.txt はそのままドメインポリシーとして /etc/ccs/domain_policy.conf に追加することが可能ですが,図31のように条件が厳密すぎて使い物にならない(例えばプロセスIDやiノード番号などは毎回変わるため、指定しない方が良い)ので,テキストエディタを用いて条件を緩めて(不要と思われる条件部分を除去して)から追加してください.
■図31 厳密すぎるアクセス許可
allow_execute /usr/bin/id if task.pid=4641 task.ppid=4637 task.uid=48 task.gid=48 task.euid=48 task.egid=48 task.suid=48 task.sgid=48 task.fsuid=48 task.fsgid=48 task.state[0]=0 task.state[1]=0 task.state[2]=0 task.type!=execute_handler path1.uid=0 path1.gid=0 path1.ino=603159 path1.major=8 path1.minor=1 path1.perm=0755 path1.type=file path1.parent.uid=0 path1.parent.gid=0 path1.parent.ino=589834 path1.parent.perm=0755 exec.realpath="/usr/bin/id" exec.argc=1 exec.envc=7 exec.argv[0]="id" exec.envp["TERM"]="linux" exec.envp["PATH"]="/sbin:/usr/sbin:/bin:/usr/bin" exec.envp["PWD"]="/usr/share/horde/admin" exec.envp["LANG"]="en_US.UTF-8" exec.envp["SHLVL"]="3" exec.envp["LANGUAGE"]="en_US.UTF-8" exec.envp["_"]="/usr/bin/id" |
今回は条件付きアクセス許可について紹介しました.次回は, TOMOYO Linux の特徴である階層化されたドメイン遷移を利用して,近年急増しているSSHブルートフォース攻撃への対策と管理者権限の分割方法について紹介します.どうぞお楽しみに.