背景
Youki (Rustでruncを再実装するOSS)にcontributeする中で、本家のruncで実装されているSELinuxに関する機能が、Youkiでは実装されていないことがわかった。
そこで、SELinuxに関する機能をYoukiに導入することになったのだが、Rustで利用できるSELinuxのcrateが無かった。そこで、SELinux crateをRustで再実装することになり、そのプロジェクトにアサインしてもらった。
しかし、その時点で僕はSELinuxについて何も知らなかったので、SELiuxについて色々と調べたことをまとめた。
SELinuxとは何か?
security-enhanced Linuxの略称。MAC制御を行うことができる。通常のセキュリティに加えてSELinuxを設定することで、システムセキュリティを更に強化できる。
Labelとpolicyを組み合わせたセキュリティ制御が特徴である。process・file・networkなどのobject、process・userなどのsubjectのそれぞれに、labelが付与される。label同士のルールをsecurity policyに定義することで、subject・object間のアクセスをコントロールする。
メリット
- SELinuxのルールはlabelで決定するので、ルート権限などの概念は考慮する必要が無い。
- 権限昇格攻撃による被害を軽減することができる。process・fileなどはdomainで互いに分離されているので、あるprocessが乗っ取られても、被害を最小限に抑えることができる。
- 管理者がアクセス制御を行うため、一般ユーザーに変更される心配がない。
- ウイルス対策ソフトウェアなどと独立した機能として、OSの安全性を高めることができる。
DAC, MAC
- DAC: 任意アクセス制御。一般ユーザー自身がシステム上のアクセス制御を行う。
- MAC: 強制アクセス制御。管理者がアクセス制限を行う。
Subject, Object
- Subject: process、userなどを指す。
- Object: file、directoryなどを指す。
SELinuxの動作モード
OSは、SELinuxの動作モードを選択する。config file(etc/selinux/config)を書き換えると、動作モードを変更できる。/sys/fs/selinux/enforceにも動作モードの設定がある。前者のファイルを書き換える場合は再起動が必要だが、後者の場合は、再起動せずに変更することができる。
- Enforcing: SELinux有効。ルール外の動作は全て止める。
- Permissive: SELinux有効。ただしルール外の動作はログに記録するだけ。
- Disable: SELinux無効。
Mount
SELinuxがenableされると、SELinuxファイルシステムが特定のディレクトリ以下でマウントされる。マウントされたSELinuxディレクトリ内で、ポリシー、状態管理が行われる。
label (SELinux context)
SELinuxが有効の場合、subject・objectは、通常のfile permission (例: 777)のほかに、label(SELinux context)を持つ。labelは4つのpartから構成される。subject, objectのどちらにも、以下の形式で付与される。
User:Role:Type:level
- User: Userごとに付与されるラベル。例:
system_u
- Role: Userに対して紐づいたRole名。RBACとして機能する。例:
object_r
- Type: subjectのdomain, およびobjectのtypeを定義する。末尾に
_t
が付与される。例:etc_t
。etc内のファイルにetc_t
が付与される、のようにルールが適用される。 - Level: MLS, MCSに利用される属性。例:
s0
例:system_u:object_r:bin_t:s0:c1,c2
Type enforcement (domain)
あるdomainを持つobjectには、policy ruleが許可されたsubjectしかアクセス出来ない。例えば、httpd_t
というドメインで実行されているプロセスは、httpd_sys_content_t
を持つファイルにアクセスできるが、mysql_db_t
というドメインを持つファイルにはアクセスできない。
あるsubject・objectをdomainで制約したくない場合、unconfined
というdomainを設定することができる。このdomainを使えば、特定のdomainに制約されることなく、多くの操作を行うことができる。
xattr
標準のファイル属性に加えて、追加のメタデータをファイルに格納する仕組み。SELinuxは、xattrを利用してファイルにlabelを設定する。security.selinux
という拡張属性(キー)を利用している。xattrは、ファイルのindex node (inode)に書き加えられる。inodeにはファイルのパーミッション・所有者・更新日時などの情報が保存されている。
procfs
Process filesystemのことで、processに関する情報が蓄えられている。processのlabelは、xattrではなくprocfsのファイルに書き込む。
MLS enforcement
Multi level securityの略称。同じTypeに属するが別の挙動をさせたいsystemに、levelを設定することができる。例えば、A, Bは同じType httpd_t
に属するが、Aだけにアクセスさせたいファイルがある場合、Aには強いlevelを設定することで、A・Bのアクセス権を区別できる。s0
からs15
までの16段階のlevelがあり、s15
が最も機密レベルが高い。
security Policy
SELinuxに関するルールを定義する。あるdomainは、あるtypeにアクセスできる、などを定める。以下の形式でルールを設定する。classは、どのリソースに対するルールなのかを表す。file, directory, simbolic link, device, ports, cursorなどのリソースがclassの種類として存在する。
以下の形式で書かれる。
allow <domain> <type>:<class> { <permissions> };
以下はルール例。
ftp_home_dir (off , off) Allow ftp to home dir
smartmon_3ware (off , off) Allow smartmon to 3ware
mpd_enable_homedirs (off , off) Allow mpd to enable homedirs
xdm_sysadm_login (off , off) Allow xdm to sysadm login
xen_use_nfs (off , off) Allow xen to use nfs
mozilla_read_content (off , off) Allow mozilla to read content
ssh_chroot_rw_homedirs (off , off) Allow ssh to chroot rw homedirs
mount_anyfile (on , on) Allow mount to anyfile
Domain transition
domain transitionは、あるprocessのlabelを変えられる。例えば、あるprocessがあるコードを実行して新しくprocessが生成される時に、別のlabelとして実行させることができる。dyntransitionとも記載される。
Dockerなどのcontainerで、SELinuxがどのように使われるのか?
Host, containerを互いに保護するために利用される。
DockerはSELinuxの機能のうち、主に、type enforcement, MCS(Multi-category security)分離、という2つの機能を利用している。type enforcementは、Host・container間の保護に利用される。MCSはcontainer同士の保護に利用される。
Dockerでは、SELinuxがdefaultで有効化されているわけでは無いので、有効化したい場合は設定を変更する必要がある。
Type enforcement
subject, object間でのアクセス制御に使われる。label同士のやり取りをpolicyで設定する。
コンテナのdefault typeは、svirt_lxc_net_t
である。このtypeは、usr, etc以下のほぼ全てのファイルをread, execできるが、var, home, rootなど、他ファイルへのアクセスは制限される。ネットワーク使用は許可されている。コンテナ内の全てのファイルはsvirt_sandbox_file_t
ラベルが付与される。svirt_lxc_net_t
はsvirt_sandbox_file_t
およびdocker_var_lib_t
とラベルされたファイルにはアクセスできる。docker_var_lib_t
はdocker volumeの使用に関連する。
MCS(multi category security)分離
この機能は、Docker, OpenShiftなどのコンテナ権限管理に利用されることが多い。
MCS分離はsvirt
とも呼ばれる。コンテナごとにuniqueな値(Docker起動時のPID)が、SELinux labelのlevel fieldに付与される。つまり、コンテナは、そのprocessがコンテナであることを表すlabelと、「どのコンテナなのか」を表すlabelが付く。
processのMCS labelは、開きたいファイルのMCS labelに対応している必要がある。例えば、s0:c1,c2
のlabelを持つprocessはs0, s0:c1, s0:c2, s0:c1,c2
にアクセスできる。s0:c1,c3
にはアクセスできない。
labelは複数のカテゴリを推奨される。そのため、s0:c1
, s0:c2
は好ましく無い。
go-selinuxでカバーしている機能
containerd organization内にあるレポジトリ。
subject・objectのlabel操作を行う関数・動作モードを変更する関数などをサポートしている。
あくまで、containerd関連のプロジェクトがSELinux機能を使うサポート用のOSSである。そのため、SELinuxが持つ、label・policyを元にアクセス制御するシステム自体を実装しているわけでは無い。
このレポジトリを絶賛Rustに移植している。
参考にしたリンク