SELinux的安全上下文

乐乐0120發表於2024-12-07

一、SELinux介紹

傳統Linux,一切接檔案,由使用者,組,許可權控制訪問
在Selinux中,一切皆物件(object),由存放在inode的擴充套件屬性域的安全元素所控制其訪問。
DAC:自由訪問控制
MAC: 強制訪問控制
DAC環境下程序是無束縛的
MAC環境下策略的規則決定控制的嚴格程度
MAC環境下程序可以被限制
策略被用來定義被限制的程序能夠使用哪些資源(檔案和埠)
預設情況下,沒有被明確允許的行為將被拒絕
image

二、SELinux安全上下文檢視方法

SELinux 管理過程中,程序是否可以正確地訪問檔案資源,取決於它們的安全上下文。程序和檔案都有自己的安全上下文,SELinux 會為程序和檔案新增安全資訊標籤,比如 SELinux 使用者、角色、型別、類別等,當執行 SELinux 後,所有這些資訊都將作為訪問控制的依據。

首先,透過一個例項看看如何檢視檔案和目錄的安全上下文,執行命令如下:

[root@localhost ~]# ls -Z
#使用選項-Z檢視檔案和目錄的安全上下文
-rw-------.root root system_u:object_r:admin_home_t:s0 anaconda-ks.cfg
-rw-r--r--.root root system_u:object_r:admin_home_t:s0 install.log
-rw-r--r--.root root system_u:object_r:admin_home_t:s0 install.log.syslog

可以看到,檢視檔案的安全上下文非常簡單,就是使用“ls -Z”命令。而在此基礎上,如果想要檢視目錄的安全上下文,需要新增“-d”選項,代表檢視目錄本身,而非目錄下的子檔案。舉個例子:

[root@localhost ~]# ls -Zd /var/www/html/
drwxr-xr-x.root root system_u:object_r:httpd_sys_content_t:s0 /var/www/html/

那麼,該如何檢視程序的安全上下文呢?只需使用 ps 命令即可。命令如下:

[root@localhost ~]# service httpd start
#啟動apache服務
[root@localhost ~]# ps auxZ | grep httpd
unconfined_u:system_r:httpd_t:s0 root 25620 0.0 0.5 11188 3304 ? Ss
03:44 0:02 /usr/sbin/httpd
…省略部分輸出…

也就是說,只要程序和檔案的安全上下文匹配,該程序就可以訪問該檔案資源。在上面的命令輸出中,我們加粗的就是安全上下文。

如果一個程序的安全上下文不允許它訪問某個檔案的安全上下文,SELinux 會阻止訪問並在審計日誌(可以透過ausearch或auditd工具檢視)中記錄相關事件。

安全上下文看起來比較複雜,它使用“:”分隔為 4 個欄位,其實共有 5 個欄位,只是最後一個“類別”欄位是可選的,例如:

system_u:object_r:httpd_sys_content_t:s0:[類別]
#身份欄位:角色:型別:靈敏度:[類別]

下面對這 5 個欄位的作用進行說明。

(1).身份欄位(user)

用於標識該資料被哪個身份所擁有,相當於許可權中的使用者身份。這個欄位並沒有特別的作用,知道就好。常見的身份型別有以下 3 種:

1.- root:表示安全上下文的身份是 root。
2.- system_u:表示系統使用者身份,其中“_u”代表 user。
3.- user_u:表示與一般使用者賬號相關的身份,其中“_u”代表 user。
user 欄位只用於標識資料或程序被哪個身份所擁有,一般系統資料的 user 欄位就是 system_u,而使用者資料的 user 欄位就是 user_u。

那麼,SELinux 中到底可以識別多少使用者身份欄位呢?我們可以使用 seinfo 命令來進行查詢。SELinux 的相關命令一般都是以“se”開頭的,所以也較為好記。

seinfo 命令格式如下:

[root@localhost ~]# seinfo [選項]
選項:
-u: 列出SELinux中所有的身份(user);
-r: 列出SELinux中所有的角色(role);
-t: 列出SELinux中所有的型別(type);
-b: 列出所有的布林值(也就是策略中的具體規則名稱);
-x: 顯示更多的資訊;

seinfo 命令的功能較多,我們在這裡只想查詢 SELinux 中的身份,那麼只需執行如下命令:

[root@localhost ~]# seinfo -u
Users:9
sysadm_u
system_u
xguest_u
root
guest_u
staff_u
user_u
unconfined_u
git_shell_u

就可以看到 SELinux 中能夠識別的 user 身份共有 9 種。不過這個欄位在實際使用中並沒有太多的作用,瞭解一下即可。

(2).角色(role)

主要用來表示此資料是程序還是檔案或目錄。這個欄位在實際使用中也不需要修改,所以瞭解就好。

常見的角色有以下兩種:

1.- object_r:代表該資料是檔案或目錄,這裡的“_r”代表 role。
2.- system_r:代表該資料是程序,這裡的“_r”代表 role。
那麼,SELinux 中到底有多少種角色呢?使用 seinfo 命令也可以查詢,命令如下:

[root@localhost ~]# seinfo -r
Roles:12
guest_r
staff_r
user_r
git_shell_r
logadm_r
object_r
sysadm_r
system_r
webadm_r
xguest_r
nx_server_r
unconfined_r

(3).型別(type)

型別欄位是安全上下文中最重要的欄位,程序是否可以訪問檔案,主要就是看程序的安全上下文型別欄位是否和檔案的安全上下文型別欄位相匹配,如果匹配則可以訪問。

注意,型別欄位在檔案或目錄的安全上下文中被稱作型別(type),但是在程序的安全上下文中被稱作域(domain)。也就是說,在主體(Subject)的安全上下文中,這個欄位被稱為域;在目標(Object)的安全上下文中,這個欄位被稱為型別。域和型別需要匹配(程序的型別要和檔案的型別相匹配),才能正確訪問。

SELinux 中到底有多少型別也是透過 seinfo 命令查詢的,命令如下:

[root@localhost ~]# seinfo -t | more
Types:3488
#共有3488個型別
bluetooth_conf_t
cmirrord_exec_t
foghorn_exec_t
jacorb_port_t
sosreport_t
etc_runtime_t
…省略部分輸出…

我們知道了型別的作用,可是我們怎麼知道程序的域和檔案的型別是否匹配呢?這就要查詢具體的策略規則了,我們在後面再進行介紹。

不過,我們已知 apache 程序可以訪問 /var/www/html/(此目錄為 RPM 包安裝的 apache 的預設網頁主目錄)目錄中的網頁檔案,所以 apache 程序的域和 /var/www/html/ 目錄的型別應該是匹配的,我們查詢一下,命令如下:

[root@localhost ~]# ps auxZ | grep httpd
unconfined_u:system_r:httpd_t:s0 root 25620 0.0 0.5 11188 3304 ? Ss
03:44 0:02 /usr/sbin/httpd
#apache程序的域是httpd_t
[root@localhost ~]# ls -dZ /var/www/html/
drwxr-xr-x.root root system_u:object_r:httpd_sys_content_t:s0 /var/www/html/
#/var/www/html/目錄的型別是httpd_sys_content_t

apache 程序的域是 httpd_t,/var/www/html/ 目錄的型別是 httpd_sys_content_t,這個主體的安全上下文型別經過策略規則的比對,是和目標的安全上下文型別匹配的,所以 apache 程序可以訪問 /var/www/html/ 目錄。
我們在 SELinux 中最常遇到的問題就是程序的域和檔案的型別不匹配,所以我們一定要掌握如何修改型別欄位。

(4).靈敏度

靈敏度一般是用 s0、s1、s2 來命名的,數字代表靈敏度的分級。數值越大,代表靈敏度越高。

(5).類別

類別欄位不是必須有的,所以我們使用 ls 和 ps 命令查詢的時候並沒有看到類別欄位。但是我們可以透過 seinfo 命令來查詢,命令如下:

[root@localhost ~]# seinfo -u -x
#查詢所有的user欄位,並檢視詳細資訊
system_u
#user欄位名
default level:s0
#預設靈敏度
range:s0 - s0:c0.c1023
#靈敏度可以識別的類別
roles:
#該user能夠匹配的role(角色)
object_r
system_r
unconfined_r

三、SELinux安全上下文的修改和設定(chcon和restorecon命令)

安全上下文的修改是我們必須掌握的,其實也並不難,主要是透過兩個命令來實現的。

chcon 命令格式如下:

[root@localhost ~]# chcon [選項] 檔案或目錄

選項:

-R: 遞迴,當前目錄和目錄下的所有子檔案同時設定;
-t: 修改安全上下文的型別欄位,最常用;
-u: 修改安全上下文的身份欄位;
-r: 修改安全上下文的角色欄位;

舉個例子:

[root@localhost ~]# echo'test page!!!' >> /var/www/html/index.html
#建立一個網頁檔案,並寫入“test page!!!”

我們可以透過瀏覽器檢視這個網頁,只需在瀏覽器的 URL 中輸入“http://ip”即可。

[root@localhost ~]# ls -Z /var/www/html/index.html
-rw-r--r--. root root unconfined_u:object_r:httpd_sys_content_t:s0 /var/www/html/index.html
#這個網頁檔案的模式類別是httpd_sys_content_t
[root@localhost ~]# seinfo -t I grep var_t
#查詢SELinun中所有的型別、發現有一個型別叫var_t
[root@localhost ~]# chcon -t var_t /var/www/html/index.html
#把網頁檔案的型別修改為var_t型別
[root@localhost ~]# ls -Z /var/www/html/index.html
-rw-r--r--. toot root unconfined_u:object_r:var_t:s0 /var/www/html/index.html
#這個網頁的型別已經被修改了

我們把網頁檔案的型別修改了,這樣 apache 程序的安全上下文一定不能匹配網頁的安全上下文,就會出現拒絕訪問的情況。

這時網頁就會提示許可權拒絕,這裡我們已經知道是安全上下文不匹配惹的禍!當然,我們可以透過 chcon 命令修改回來就可以修復。不過,我們還有一個命令 restorecon,這個命令的作用就是把檔案的安全上下文恢復成預設的安全上下文。SELinux 的安全上下文設定非常完善,所以使用 restorecon 命令就可以修復安全上下文不匹配所引起的問題。

restorecon 命令格式如下:

[root@localhost ~] # restorecon [選項】 檔案或目錄

選項:

-R:遞迴.當前目錄和目錄下所有的子檔案同時恢復;
-V:把恢復過程顯示到螢幕上;

例如:

[root@1ocalhost ~]# restorecon -Rv /var/www/html/index.html
restorecon  reset   /var/www/html/index.html    context
unconfined_u:object_r:var_t:s0->unconfined_u:object_r:httpd_sys_content_t:s0
#這裡已經提示了安全上下文從var_t恢復成了httpd_sys_content_t
[root@1ocalhost ~]# ls -Z /var/www/html/index.html
-rw-r--r--. root root unconfined_u:object_r:httpd_sys_content_t:s0 /var/www/html/index.html
#檢視一下,安全上下文已經恢復正常了.網頁的訪問也已經恢復正常了

四、SELinux預設安全上下文的查詢和修改(semanage命令)

前面講到,restorecon 命令可以將檔案或目錄恢復成預設的安全上下文,這就說明每個檔案和目錄都有自己的預設安全上下文,事實也是如此,為了管理的便捷,系統給所有的系統預設檔案和目錄都定義了預設的安全上下文。

那麼,預設安全上下文該如何查詢和修改呢?這就要使用 semanage 命令了。該命令的基本格式如下:

[root@localhost ~]# semanage [login|user|port|interface|fcontext|translation] -l
[root@localhost ~]# semanage fcontext [選項] [-first]  file_spec

其中,fcontext 主要用於安全上下文方面,-l 是查詢的意思。除此之外,此命令常用的一些選項及含義,如下表所示。

選項 含義
-a 新增預設安全上下文配置
-d 刪除指定的預設安全上下文
-m 修改指定的預設安全上下文
-t 設定預設安全上下文的型別
[root@localhost ~]# semanage fcontext -l
#查詢所有的預設安全上下文
…省略部分輸出…
/var/www(/.*)? all files
system_u:object_r:httpd_sys_content_t:s0
…省略部分輸出…
#能夠看到/var/www/目錄下所有內容的預設安全上下文都是httpd_sys_content_t

所以,一旦對 /var/www/ 目錄下檔案的安全上下文進行了修改,就可以使用 restorecon 命令進行恢復,因為預設安全上下文已經明確定義了。

【例 2】修改預設安全上下文。
那麼,可以修改目錄的預設安全上下文嗎?當然可以,舉個例子:

[root@localhost ~]# mkdir /www
#新建/www/目錄,打算用這個目錄作為apache的網頁主目錄,而不再使用/var/www/html/目錄
[root@localhost ~]# ls -Zd /www/
drwxr-xr-x.root root unconfined_u:object_r:default_t:s0 /www/
#而這個目錄的安全上下文型別是default_t,那麼apache程序當然就不能訪問和使用/www/目錄了

這時我們可以直接設定 /www/ 目錄的安全上下文型別為 httpd_sys_content_t,但是為了以後管理方便,我打算修改 /www/ 目錄的預設安全上下文型別。先查詢一下 /www/ 目錄的預設安全上下文型別,命令如下:

[root@localhost ~]# semanage fcontext -l | grep "/www"
#查詢/www/目錄的預設安全上下文

查詢出了一堆結果,但是並沒有 /www/ 目錄的預設安全上下文,因為這個目錄是手工建立的,並不是系統預設目錄,所以並沒有預設安全上下文,需要我們手工設定。命令如下:

[root@localhost ~]# semanage fcontext -a -t httpd_sys_content_t "/www(/.*)?"
#這條命令會給/www/目錄及目錄下的所有內容設定預設安全上下文型別是httpd_sys_content_t
[root@localhost ~# semanage fcontext -l | grep "/www"
…省略部分輸出…
/www(/.*)? all files system_u:object_r:httpd_sys_content_t:s0
#/www/目錄的預設安全上下文出現了

這時已經設定好了 /www/ 目錄的預設安全上下文。

[root@localhost ~]# ls -Zd /www/
drwxr-xr-x.root root unconfined_u:object_r:default_t:s0 /www/
#但是查詢發現/www/目錄的安全上下文並沒有進行修改,那是因為我們只修改了預設安全上下文,而沒有修改目錄的當前安全上下文
[root@localhost ~]# restorecon -Rv /www/
restorecon reset /www context
unconfined_u:object_r:default_t:s0->unconfined_u:object_r:httpd_sys_content_t:s0
#恢復一下/www/目錄的預設安全上下文,發現型別已經被修改為httpd_sys_content_t

五、編寫自定義 SELinux 策略模組

1.環境準備

首先,需要安裝相關的開發工具。在 CentOS 或 RHEL 系統中,要安裝policycoreutils -devel包,這個包提供了編寫和編譯 SELinux 策略模組所需的工具,如checkmodule和semodule_package。

2.策略模組檔案結構和基本語法

(1).模組宣告(Module Declaration)

一個 SELinux 策略模組以module關鍵字開始,後面跟著模組名稱和版本號。例如:

module my_custom_policy 1.0;
  • 這裡my_custom_policy是模組名稱,1.0是版本號。
(2).型別宣告(Type Declarations)
  • 需要宣告主體(如程序)型別和客體(如檔案、目錄)型別。例如:
type my_process_t;
type my_file_t;
  • 上面分別宣告瞭一個代表程序的型別my_process_t和一個代表檔案的型別my_file_t。
(3).介面宣告(Interface Declarations)
  • 介面用於定義模組提供給其他模組的功能。例如:
interface(`my_policy_api',`
    gen_require(`
        type my_file_t;
    ')
)
  • 這個介面my_policy_api宣告瞭對型別my_file_t的需求。
(4).規則定義(Rule Definitions)
  • 最重要的部分是定義主體對客體的訪問規則。例如,允許my_process_t型別的程序讀取my_file_t型別的檔案:
allow my_process_t my_file_t:file read;
  • 規則格式通常是allow|deny [主體型別] [客體型別]:[客體類別] [訪問許可權];,其中allow表示允許訪問,deny表示禁止訪問,file是客體類別(可以是file、dir、socket等多種類別),read是訪問許可權(還可以有write、execute等多種許可權)。
(5).編寫一個簡單的示例策略模組

假設我們要編寫一個策略模組,允許一個自定義的程序(myapp_process_t)讀取和寫入一個自定義的配置檔案(myapp_config_t)。
策略模組檔案(myapp_policy.te)內容如下:

module myapp_policy 1.0;

type myapp_process_t;
type myapp_config_t;

interface(`myapp_policy_api',`
    gen_require(`
        type myapp_config_t;
    ')
)

allow myapp_process_t myapp_config_t:file {read, write};
(6).編譯和載入策略模組

一、編譯模組

  • 使用checkmodule -M -m -o myapp_policy.mod myapp_policy.te命令。其中checkmodule是編譯工具,-M選項表示建立一個模組,-m選項用於指定模組檔案(.te檔案),-o選項指定輸出的編譯後的模組檔案(.mod檔案)。
    二、打包模組
  • 使用semodule_package -o myapp_policy.pp -m myapp_policy.mod命令。semodule_package工具將編譯後的模組打包成一個可載入的策略包(.pp檔案)。
    三、載入模組
  • 使用semodule -i myapp_policy.pp命令來載入這個自定義策略模組。載入後,SELinux 就會按照這個模組中定義的規則來控制訪問。
(7).除錯和測試策略模組

1.檢視審計日誌(Audit Logs)

  • 當 SELinux 阻止或允許訪問操作時,相關資訊會記錄在審計日誌中。可以使用ausearch -m avc -ts recent命令來檢視最近的 SELinux 訪問向量快取(AVC)訊息。這些訊息可以幫助判斷策略模組是否按預期工作。

2.調整和最佳化策略

  • 根據審計日誌和實際應用程式的執行情況,可能需要對策略模組進行調整。例如,如果發現應用程式還需要執行檔案的許可權,就需要在策略模組中新增allow myapp_process_t myapp_config_t:file execute;這樣的規則。同時,要注意避免過度授權,以確保系統安全。

3.相關策略檔案的儲存位置

(1).SELinux 策略檔案儲存位置
  • 在大多數 Linux 系統中,SELinux 策略檔案通常儲存在/etc/selinux目錄下。這個目錄包含了 SELinux 策略相關的配置檔案。
  • 例如,對於targeted策略(這是很多系統預設的策略型別),策略檔案的二進位制表示形式可能儲存在/etc/selinux/targeted/policy目錄中。這些檔案是經過編譯後的策略模組,系統透過載入這些檔案來實施 SELinux 策略。
(2).自定義策略模組儲存位置
  • 當你編寫自定義的 SELinux 策略模組時,在編譯和打包後(通常生成.pp檔案),可以將這些檔案儲存在本地目錄用於測試。
  • 不過,如果要讓系統在啟動時自動載入自定義策略模組,一個比較合適的位置是/etc/selinux/targeted/modules/active/modules目錄(對於targeted策略而言)。你可以使用semodule -i命令將自定義策略模組(.pp檔案)安裝到這個位置,這樣系統在下次啟動時會載入這些自定義策略規則。
(3).SELinux 策略原始檔(用於開發)
  • 對於開發自定義策略,原始檔(如.te、.fc、.if等檔案)可以儲存在本地開發目錄。這些檔案包含了型別宣告、規則定義等內容,用於構建自定義策略模組。
  • 例如,你可以在自己的使用者目錄下建立一個專門用於開發 SELinux 策略的資料夾,如~/selinux_policy_dev,在這個資料夾中編寫和編輯策略原始檔,然後在需要時將其編譯、打包並安裝到系統的策略目錄中。

相關文章