sepgsql
は、SELinuxのセキュリティポリシーに基づいた、ラベルベースの強制アクセス制御(MAC; Mandatory Access Control)機能を提供するモジュールです。
現在の実装にはいくつかの重要な制限事項があり、そのため、全ての操作に対して強制アクセス制御を適用するわけではありません。 詳細は F.40.7 をご覧ください。
このモジュールは、PostgreSQLが標準で提供しているものに加えて、SELinuxと統合されたアクセス制御のレイヤーを追加します。 SELinuxの視点からは、このモジュールがPostgreSQLをユーザ空間オブジェクトマネージャとして機能することを可能にします。 すなわち、DMLクエリによる個々のテーブルや関数へのアクセスは、オペレーティングシステムのセキュリティポリシーによってチェックされます。 このチェックは、PostgreSQLによる通常のSQLパーミッションチェックに対して追加的に実施されます。
SELinuxにおけるアクセス制御の意思決定は、system_u:object_r:sepgsql_table_t:s0
のような書式を持ったセキュリティラベルと呼ばれる文字列を用いて行われます。
個々のアクセス制御の意思決定には、2種類のラベルが利用されます。
すなわち、ある操作を行おうとする主体(サブジェクト)のラベルと、その操作の対象となるオブジェクトのラベルです。
これらのラベルはあらゆる種類のオブジェクトに対して適用されるため、(このモジュールを用いる事で)データベースに格納されたオブジェクトに対するアクセス制御は、他の一般的なオブジェクト、例えばファイルに対するものと同一の基準に従って意思決定される事になります。
このデザインは、情報資産を格納する方法とは独立に、一元管理されたセキュリティポリシーによって情報資産を保護することを意図しています。
SECURITY LABEL
を用いてデータベースオブジェクトにセキュリティラベルを設定することができます。
sepgsql
はSELinuxが有効なLinuxカーネル 2.6.28 以上で動作します。
その他のプラットフォーム上では利用する事はできません。
加えて、(ディストリビューションによっては、必要なルールを古いバージョンのポリシーにバックポートしている可能性がありますが)libselinux 2.1.10以上、selinux-policy 3.9.13以上が必要です。
sestatus
コマンドを用いてSELinuxの状態を確認することができます。典型的な出力例は以下の通りです。
$ sestatus SELinux status: enabled SELinuxfs mount: /selinux Current mode: enforcing Mode from config file: enforcing Policy version: 24 Policy from config file: targeted
SELinuxが無効化されている、あるいはインストールされていない場合、このモジュールのインストールの前に、SELinuxのセットアップを行わねばなりません。
このモジュールをビルドするには、PostgreSQLのconfigure
コマンドに--with-selinux
オプションを追加してください。
これは、ビルド時にlibselinux-devel
パッケージがインストールされている事を確認します。
このモジュールを利用するには、postgresql.conf
のshared_preload_librariesパラメータに sepgsql
を含める必要があります。これ以外の方法でロードされた場合、このモジュールは正しく機能しません。
このモジュールのロード後、各データベースに対してsepgsql.sql
を実行し、セキュリティラベル管理のための関数のインストールや、初期セキュリティラベルの設定を行うべきです。
以下にsepgsql
関数およびセキュリティラベルと共にデータベースクラスタを初期化する手順を示します。
インストール先に応じて、適宜パス名を読み替えるようにしてください。
$ export PGDATA=/path/to/data/directory $ initdb $ vi $PGDATA/postgresql.conf この行を #shared_preload_libraries = '' # (change requires restart) 以下に変更 shared_preload_libraries = 'sepgsql' # (change requires restart) $ for DBNAME in template0 template1 postgres; do postgres --single -F -c exit_on_error=true $DBNAME \ </usr/local/pgsql/share/contrib/sepgsql.sql >/dev/null done
libselinuxとselinux-policyのバージョンによっては以下のようなメッセージが出力される事があります。
/etc/selinux/targeted/contexts/sepgsql_contexts: line 33 has invalid object type db_blobs /etc/selinux/targeted/contexts/sepgsql_contexts: line 36 has invalid object type db_language /etc/selinux/targeted/contexts/sepgsql_contexts: line 37 has invalid object type db_language /etc/selinux/targeted/contexts/sepgsql_contexts: line 38 has invalid object type db_language /etc/selinux/targeted/contexts/sepgsql_contexts: line 39 has invalid object type db_language /etc/selinux/targeted/contexts/sepgsql_contexts: line 40 has invalid object type db_language
これらのメッセージは無害ですので無視してください。
インストール手順が正常に終了したら、通常通り、サーバを起動することができます。
SELinuxの性質上、sepgsql
のリグレッションテストを実行するには、いくつかの追加的な設定が必要で、そのうちの幾つかはroot
で実行する必要があります。
リグレッションテストは通常のmake check
やmake installcheck
コマンドで実行する事はできません。
必要な設定を行い、テスト用スクリプトを手動で実行する必要があります。
このテストはPostgreSQLビルドツリーのcontrib/sepgsql
ディレクトリで実行する必要があります。
しかしビルドツリーを必要とする一方、このテストはインストールされたサーバに対して実行する必要があります。
これは、make check
ではなく、make installcheck
によく似ています。
最初に、F.40.2に従ってsepgsql
をデータベースにセットアップします。
使用するOS上のユーザは、認証無しでデータベース特権ユーザとして接続できる必要があることに留意してください。
次に、リグレッションテスト用のポリシーパッケージのビルドとインストールを行ってください。
sepgsql-regtest
ポリシーはリグレッションテストの実行に必要な一連のルールを含む特別な目的のポリシーパッケージです。
ポリシーのソースファイルであるsepgsql-regtest.te
から、SELinuxの提供するMakefileを用いてmake
コマンドでビルドする事ができます。
この時、インストール先システムにおいて、適切なMakefile
の位置を指定する必要があります。以下の例で示されているパスは一例です。
(このMakefileは通常selinux-policy-devel
やselinux-policy
パッケージで提供されています。)
ビルドが完了したら、semodule
を用いてこのポリシーパッケージをインストールする事ができます。このコマンドは、指定されたポリシーパッケージをリンクし、カーネル空間にロードする役割を果たします。
インストールが正常終了したら、
により有効なパッケージの一覧としてsemodule
-lsepgsql-regtest
が表示されるはずです。
$ cd .../contrib/sepgsql $ make -f /usr/share/selinux/devel/Makefile $ sudo semodule -u sepgsql-regtest.pp $ sudo semodule -l | grep sepgsql sepgsql-regtest 1.07
次に、sepgsql_regression_test_mode
を有効化してください。
安全のため、デフォルトではsepgsql-regtest
に含まれる全てのルールが有効化されている訳ではありません。
sepgsql_regression_test_mode
パラメータはリグレッションテストを起動するために必要となる幾つかのルールを有効にします。
setsebool
コマンドによって有効化する事ができます。
$ sudo setsebool sepgsql_regression_test_mode on $ getsebool sepgsql_regression_test_mode sepgsql_regression_test_mode --> on
次に、シェルがunconfined_t
ドメインで動作している事を確認して下さい。
$ id -Z unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
利用者の動作ドメインを設定する方法について、必要であれば、詳細はF.40.8をご覧ください。
最後に、リグレッションテストのスクリプトを実行します。
$ ./test_sepgsql
このスクリプトは全ての設定ステップが正常に行われていることを確認し、その後、sepgsql
モジュールに対するリグレッションテストを実行します。
テストの実行後はsepgsql_regression_test_mode
パラメータを無効化する事をお勧めします。
$ sudo setsebool sepgsql_regression_test_mode off
sepgsql-regtest
ポリシーをアンロードする際は、以下のコマンドを実行してください。
$ sudo semodule -r sepgsql-regtest
sepgsql.permissive
(boolean
)
このパラメータにより、オペレーティングシステムの設定に関わらず、sepgsql
をパーミッシブモードで動作させる事ができます。
デフォルトの設定値はoffです。
postgresql.conf
内、およびサーバ起動時のコマンドラインでのみ、このパラメータを設定する事ができます。
このパラメータがonの場合、たとえSELinuxがエンフォーシングモードで動作していたとしても、sepgsql
関数はパーミッシブモードで動作します。
このパラメータは主としてテストの目的に有用です。
sepgsql.debug_audit
(boolean
)
このパラメータにより、セキュリティポリシーの設定とは無関係に監査ログを出力する事が可能になります。 デフォルト値はoff(セキュリティポリシーの設定に従う)です。
SELinuxのセキュリティポリシーには、特定のアクセスを監査ログに記録するか否かを制御するルールも存在します。 デフォルトでは、ポリシーに違反したアクセスを記録し、それ以外はログに記録されません。
システムのポリシーとは無関係に、このパラメータは全ての監査ログの出力を強制します。
SELinuxのセキュリティモデルでは、全てのアクセス制御ルールは動作主体(サブジェクト; 典型的にはデータベースクライアント)と対象オブジェクト間の関係として記述し、これらはセキュリティラベルによって識別されます。
ラベル付けされていないオブジェクトに対するアクセスが発生した場合、そのオブジェクトはあたかもunlabeled_t
タイプが割り当てられているかのように振舞います。
現在のsepgsql
では、スキーマ、テーブル、カラム、シーケンス、ビューおよび関数に対するラベル付けがサポートされています。
sepgsql
の利用時には、これらのデータベースオブジェクトに対して、その生成時に自動的にセキュリティラベルが割り当てられます。
このラベルはデフォルトセキュリティラベルと呼ばれ、作成者のラベル、親関係にあたるオブジェクトのラベル、そして場合によっては作成されたオブジェクトの名前に基づいて、システムのセキュリティポリシーが決定します。
新しいデータベースオブジェクトのラベルは、タイプ遷移と呼ばれる異なったラベルを設定するための特別なルールがセキュリティポリシーに設定されている場合を除き、親関係にあるオブジェクトのラベルを引き継ぎます。 スキーマの親オブジェクトはデータベースであり、テーブル、シーケンス、ビュー、および関数はその属するスキーマが、カラムはその属するテーブルが親オブジェクトという事になります。
テーブルに対しては、構文の種類に応じてdb_table:select
、db_table:insert
、db_table:update
あるいはdb_table:delete
権限が全ての被参照テーブルに対してチェックされます。
加えて、WHERE
句やRETURNING
句で参照されるカラム、又はUPDATE
の際のデータ元として利用されるカラムの属するテーブルに対してdb_table:select
権限もチェックされます。
参照された全てのカラムに対して列レベルの権限チェックが行われます。
SELECT
構文で読み出されるカラムに対してだけでなく、他のDML構文で参照されているカラムに対してもdb_column:select
権限がチェックされます。
また、UPDATE
やINSERT
によって操作の対象となっているカラムに対しても、db_column:update
やdb_column:insert
権限がそれぞれチェックされます。
以下の例を見てください
UPDATE t1 SET x = 2, y = func1(y) WHERE z = 100;
ここでは、更新されるt1.x
に対してdb_column:update
権限が、更新と同時に参照されるt1.y
に対してはdb_column:{select update}
権限が、そして参照されるだけのt1.z
にはdb_column:select
権限がチェックされます。
また、テーブルレベルではdb_table:{select update}
権限がチェックされます。
SELECT
構文を用いてシーケンスを参照する場合、db_sequence:get_value
がチェックされます。
しかし、現在のところlastval()
など関連する関数の実行時にはパーミッションチェックを行わない事に留意してください。
ビューに対してはdb_view:expand
権限がチェックされ、次いで、ビューから展開されたオブジェクトに対するパーミッションが個別にチェックされます。
利用者がクエリの一部として、あるいは近道インタフェースを用いた呼び出しによって関数を実行しようとするとき、db_procedure:{execute}
権限がチェックされます。
関数がトラステッドプロシージャである場合、関数がトラステッドプロシージャのエントリーポイントとして振る舞う事ができるかどうかを検査するためにdb_procedure:{entrypoint}
権限がチェックされます。
あらゆるスキーマオブジェクトにアクセスするためには、それらを含むスキーマに対するdb_schema:search
権限が必要です。
あるスキーマオブジェクトがスキーマ修飾無しに参照された場合、この権限を与えられていないスキーマは探索されません(あたかも利用者がスキーマに対するUSAGE
権限を有していないかのように振る舞います)。
明示的なスキーマ修飾があり、このスキーマに対して利用者が要求された権限を有していない場合、エラーが発生します。
クライアントは全ての被参照テーブル・カラムに対して参照の権限を有している必要があります。それらがビューに由来し、展開されたものであっても同様です。これにより、テーブルの内容がどのような方法によって参照されるかに関係なく、一貫したアクセス制御ルールを適用する事ができます。
データベーススーパーユーザに対して、標準のデータベース権限システムはDMLを用いたシステムカタログの更新と、TOASTテーブルの参照および更新を許していますが、sepgsql
が有効なとき、これらの操作は禁止されます。
オブジェクトの作成、変更、削除やセキュリティラベルの変更など、SELinuxは各オブジェクトに共通の操作を制御するためのパーミッションを何個か定義しています。 また、特定のスキーマに対する名前の追加や削除など、いくつかのオブジェクトにはそれ固有の操作を制御するための特別なパーミッションも定義されています。
新しいデータベースオブジェクトの作成にはcreate
権限が必要です。
SELinuxは利用者のセキュリティラベルと新しいオブジェクトに付与される事になるセキュリティラベルの対に基づいて、この権限を許可、あるいは拒否します。
いくつかの場合では、追加的な権限チェックが行われます。
CREATE DATABASE
は、複製元またはテンプレートのデータベースに対するgetattr
権限を要求します。
スキーマオブジェクトの作成は、それを含むスキーマに対してadd_name
権限を要求します。
テーブルの作成は同時に、それがあたかも独立したオブジェクトであるかのように、個々のテーブル列を作成する権限を要求します。
LEAKPROOF
属性を持った関数の作成はinstall
権限を要求します。(これはまた、既存の関数にLEAKPROOF
属性を設定する時にも要求されます)
DROP
構文の実行時、削除されるオブジェクトに対してdrop
権限がチェックされます。
CASCADE
により間接的に削除されるオブジェクトに対してもチェックは行われます。
特定のスキーマに含まれるオブジェクト(テーブル、ビュー、シーケンスや関数)の削除に際しては、スキーマに対するremove_name
権限も併せてチェックされます。
ALTER
構文の実行時、テーブルに対するインデックスやトリガなど別オブジェクトに従属するもの(これらは代わりに親オブジェクトに対する権限がチェックされる)を除き、setattr
がチェックされます。
いくつかの場合では、追加的な権限チェックが行われます。
オブジェクトを新しいスキーマに移動させるには、古いスキーマに対してremove_name
権限が、新しいスキーマに対してadd_name
権限が必要です。
関数に対するLEAKPROOF
属性の設定はinstall
権限を要求します。
SECURITY LABEL
コマンドの実行時、ラベル付けされるオブジェクトの古いラベルに対してsetattr
権限とrelabelfrom
権限が、入力された新しいラベルに対してrelabelto
権限がチェックされます。
(複数のラベルプロバイダがインストールされており、利用者がSELinuxの管理下にないラベルを設定しようとした場合、setattr
権限だけがチェックされるべきです。しかし実装上の制約により、現在はこれをチェックしていません。)
トラステッドプロシージャはSECURITY DEFINER関数やSet-UIDコマンドに似ています。 通常、機密データに対する高度にコントロールされたアクセス手段(例えば行を削除したり、保存された値の精度をさげたりします)を提供する目的で、SELinuxは利用者のものとは異なるセキュリティラベルで信頼済みのコードを実行するための機能を持っています。 関数がトラステッドプロシージャとして振舞うかどうかは、関数のセキュリティラベルおよびオペレーティングシステムのセキュリティポリシーに従って決まります。 例えば:
postgres=# CREATE TABLE customer ( cid int primary key, cname text, credit text ); CREATE TABLE postgres=# SECURITY LABEL ON COLUMN customer.credit IS 'system_u:object_r:sepgsql_secret_table_t:s0'; SECURITY LABEL postgres=# CREATE FUNCTION show_credit(int) RETURNS text AS 'SELECT regexp_replace(credit, ''-[0-9]+$'', ''-xxxx'', ''g'') FROM customer WHERE cid = $1' LANGUAGE sql; CREATE FUNCTION postgres=# SECURITY LABEL ON FUNCTION show_credit(int) IS 'system_u:object_r:sepgsql_trusted_proc_exec_t:s0'; SECURITY LABEL
これらの操作は管理権限を持つ利用者で行ってください。
postgres=# SELECT * FROM customer; ERROR: SELinux: security policy violation postgres=# SELECT cid, cname, show_credit(cid) FROM customer; cid | cname | show_credit -----+--------+--------------------- 1 | taro | 1111-2222-3333-xxxx 2 | hanako | 5555-6666-7777-xxxx (2 rows)
この場合、一般の利用者はcustomer.credit
を直接参照することはできませんが、トラステッドプロシージャであるshow_credit
を用いる事で、一部の桁がマスクされた顧客のクレジットカード番号をプリントする事が可能になります。
セキュリティポリシーによって許可されている場合、SELinuxの動的ドメイン遷移機能を用いて、利用者のラベルを新しいものに切り替える事ができます。
利用者のドメインはsetcurrent
権限および、古いドメインから新しいドメインに遷移するためのdyntransition
権限を有している必要があります。
利用者に自身のラベル、すなわち権限を切り替える事を可能にする動的ドメイン遷移は、システムによる自動切り替え(トラステッドプロシージャの場合)に比べて慎重に取り扱う必要があります。
dyntransition
権限は元々のドメインよりも小さな権限セットを持つドメインに切り替える場合にのみ安全であると考えられます。
例えば、
regression=# select sepgsql_getcon(); sepgsql_getcon ------------------------------------------------------- unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 (1 row) regression=# SELECT sepgsql_setcon('unconfined_u:unconfined_r:unconfined_t:s0-s0:c1.c4'); sepgsql_setcon ---------------- t (1 row) regression=# SELECT sepgsql_setcon('unconfined_u:unconfined_r:unconfined_t:s0-s0:c1.c1023'); ERROR: SELinux: security policy violation
上記の例では、広いMCSレンジc1.c1023
から狭いMCSレンジc1.c4
への遷移は許可されているものの、その逆は禁止されています。
動的ドメイン遷移とトラステッドプロシージャの組み合わせは、典型的なコネクションプーラのライフサイクルに適合する興味深い利用法を提供します。
たとえコネクションプーリングソフトウェアが大半のSQLの実行を許可されていない場合でも、トラステッドプロシージャの内側からsepgsql_setcon()
関数を用いて利用者のセキュリティラベルを切り替える事ができます。(トラステッドプロシージャは利用者のセキュリティラベルを切り替えるための認証情報を要求すべきです。)
この後、現在のセッションはコネクションプーラの権限ではなく、対象となる利用者の権限で動作する事になります。
また、sepgsql_setcon()
にNULL
引数を与えて(適切な権限チェックを行う)トラステッドプロシージャから再び呼び出す事で、コネクションプーラは後でセキュリティラベルを元に戻す事ができます。
ここでのポイントは、トラステッドプロシージャだけが実際に有効なセキュリティラベルを変更する権限を持っており、正しい認証情報が与えられた場合にのみそれを実行するという事です。
言うまでもなく、安全な操作のためには、権限のないアクセスから認証情報を保持するテーブルや関数定義などを保護しなければなりません。
ロードされたモジュールは、セキュリティポリシーの適用を容易にバイパスできるため、LOAD
コマンドの実行は全面的に禁止されています。
表 F.29に利用可能な関数を示します。
表F.29 sepgsql関数
関数 説明 |
---|
利用者のドメイン、つまり、現在の利用者ラベルを返却します。 |
セキュリティポリシーで許可されている場合、現在のセッションの利用者ドメインを新しいドメインへと切り替えます。
|
mcstransデーモンが動作している場合、入力されたMLS/MCSレンジを修飾フォーマットから直接フォーマットに変換します。 |
mcstransデーモンが動作している場合、入力されたMLS/MCSレンジを直接フォーマットから修飾フォーマットに変換します。 |
現在のデータベース内のすべてのオブジェクトに対して初期セキュリティラベルを割り当てます。
引数は |
実装上の制約により、いくつかのDDL操作はパーミッションをチェックしません。
実装上の制約により、DCL操作はパーミッションをチェックしません。
PostgreSQLは行レベルアクセス制御をサポートしていますが、sepgsql
はサポートしていません。
たとえ利用者が参照を許可されていないオブジェクトであっても、sepgsql
はその存在を隠すことを意図していません。
例えば、我々があるオブジェクトの内容を参照する事ができなくても、主キーの競合や外部キー違反、その他の方法によって不可視なオブジェクトが存在する事を推測できます。
"最高機密"テーブルの存在を隠すことは不可能であり、その内容を秘匿することだけを意図しています。
このwikiページでは、概要、セキュリティ・デザイン、アーキテクチャ、管理、および将来の機能について紹介しています。
このドキュメントはSELinuxシステム管理に対する広範な知識を提供しています。 主としてRed Hatオペレーティングシステムを対象としていますが、それに限ったものではありません。
このドキュメントはSELinuxに関するよくある質問と回答(FAQ)です。 主としてFedoraを対象としていますが、それに限ったものではありません。
KaiGai Kohei <kaigai@ak.jp.nec.com>