鳥哥私房菜

鳥哥私房菜

3.6、利用 SELinux trouble shoot 服務

基本上,透過了解 SELinux 的三種模式 (disabled, permissive, enforcing)、功能規範開放與否 (getsebool, setsebool)、

安全本文的修改 (chcon, restorecon, semanage fcontext),以及埠口規範 (semanage port) 的方法,

對於 SELinux 的管理,大概就不會差太多了!不過,有沒有更簡單的方法呢?是有的喔!

事實上,如果你的 SELinux 運作錯誤時,我們可以透過 setroubleshoot 這個軟體的功能,

它會自動分析可能的錯誤,並且將可能的解決方案直接紀錄到 /var/log/messages 裡面!

如此一來,你只要重複犯錯的動作,然後查閱 messages 檔案內容,就可以知道如何解決了!相當愉快!

確認 setroubleshoot 與 rsyslog 是有安裝的

要使用 SELinux 自動錯誤克服的功能,就得要安裝 setroubleshoot 軟體才行!而且,

初次安裝完畢時,可能得要重新開機才會有作用。另外,RockyLinux 8 預設似乎沒有啟動 rsyslog,不過,RockyLinux 9 倒是預設安裝的。

如果你無法確認 rsyslog 有沒有啟動以及 setroubleshoot 有沒有安裝,沒關係,就讓我們來手動測試看看即可。

[root@localhost ~]# yum -y install setroubleshoot*

[root@localhost ~]# rpm -qa | grep setrouble

setroubleshoot-plugins-3.3.14-4.el9.noarch

setroubleshoot-server-3.3.31-2.el9_2.x86_64

setroubleshoot-3.3.31-2.el9_2.x86_64

[root@localhost ~]# systemctl status rsyslog

● rsyslog.service - System Logging Service

Loaded: loaded (/usr/lib/systemd/system/rsyslog.service; enabled; preset: enabled)

Active: active (running) since Fri 2023-08-04 16:02:11 CST; 6h ago

Docs: man:rsyslogd(8)

https://www.rsyslog.com/doc/

Main PID: 609 (rsyslogd)

Tasks: 3 (limit: 12243)

Memory: 3.0M

CPU: 521ms

CGroup: /system.slice/rsyslog.service

└─609 /usr/sbin/rsyslogd -n

你可能會覺得很怪異,上面安裝的軟體名稱當中有 setroubleshoot-server 這個關鍵字,但是,使用 systemctl

去檢查相關的服務時,卻找不到任何 setrouble 相關的服務名稱!這是因為 setrouble 已經整合到稽核模組 auditd 服務中!

因此, setroubleshoot 的運作方式是這樣的:

先由 auditd 去呼叫 audispd 服務

然後 audispd 服務去啟動 sedispatch 程式

sedispatch 再將原本的 auditd 訊息轉成 setroubleshootd 的訊息,進一步儲存下來的

總之,鳥哥這種老人家,還是比較習慣查詢 /var/log/messages 內的資料,而不是讓日誌直接寫入 systemd-journald 當中!

因為只寫入 systemd-journald 時,當系統重新開機,日誌可能是會遺失的呢!

1. 模擬狀況,當 port 出問題時:讓 httpd 開啟在非正規埠口

基本上,http, https 的埠口分別是 port 80, port 443 的 tcp 埠口。那麼當我將這個埠口開啟到非正規的 377 埠口呢?

很可能會無法啟動喔!先來測試看看。我們依序可以這樣做:

1. 網頁伺服器的軟體所需名稱為 httpd,請安裝好這個軟體

2. 軟體主設定檔為 /etc/httpd/conf/httpd.conf ,內部的 Listen 設定,請改為 377

3. 啟動名為 httpd 的服務,並且查看有沒有出問題?

4. 若出問題,將 SELinux 模式由 enforcing 改為 permissive 測試一下

5. 再次重新啟動 httpd 服務,是否能正常啟動?若可以,代表就是 SELinux 的問題。

6. 前往 /var/log/messages 查詢是否有 setrouble 的關鍵字?若有,取出查閱

7. 根據 sealert 的解釋,將問題克服

我們就實際在虛擬機上面惡搞一下囉!

# 1. 先安裝軟體

[root@localhost ~]# yum -y install httpd

# 2. 修改設定檔,大約在 47 行處,修改埠口號碼

[root@localhost ~]# vim /etc/httpd/conf/httpd.conf

Listen 377

# 3. 嘗試啟動 httpd 服務

[root@localhost ~]# systemctl start httpd

Job for httpd.service failed because the control process exited with error code.

See "systemctl status httpd.service" and "journalctl -xeu httpd.service" for details.

# 如上所示,系統會提示出現錯誤了!

# 4. 嘗試將 SELinux 模式改為 permissive

[root@localhost ~]# getenforce

Enforcing

[root@localhost ~]# setenforce 0

[root@localhost ~]# getenforce

Permissive

# 5. 確認一下能不能順利啟動?用來判斷問題是否出在 SELinux 的情況

[root@localhost ~]# systemctl start httpd

[root@localhost ~]# netstat -tlunp | grep httpd

tcp6 0 0 :::377 :::* LISTEN 8324/httpd

# 出現 LISTEN 關鍵字!代表服務有正常啟動了!所以,問題一定是 SELinux 造成的!

# 6. 確認 /var/log/messages 有沒有因為啟動 httpd 而記載錯誤解決方案

[root@localhost ~]# grep setrouble /var/log/messages | grep sealert

Aug 4 22:13:38 localhost setroubleshoot[3553]: SELinux is preventing /usr/sbin/httpd

from name_bind access on the tcp_socket port 377. For complete SELinux messages

run: sealert -l 525fe157-a16b-47c4-ad8d-11bad86c9e9a

# 重點是找到 sealert 這個關鍵字!後續的指令直接執行就是答案!

# 7. 將找到的 sealert 指令執行,並依據提示處理問題

[root@localhost ~]# sealert -l 525fe157-a16b-47c4-ad8d-11bad86c9e9a

SELinux is preventing /usr/sbin/httpd from name_bind access on the tcp_socket port 377.

***** Plugin bind_ports (99.5 confidence) suggests ************************

If you want to allow /usr/sbin/httpd to bind to network port 377

Then you need to modify the port type.

Do

# semanage port -a -t PORT_TYPE -p tcp 377

where PORT_TYPE is one of the following: http_cache_port_t, http_port_t, ...

***** Plugin catchall (1.49 confidence) suggests **************************

....

其實解決問題的方案不止一種,因此,上述的 sealert 提供的方式中,會有好幾個解決方案,不過,解決方案總是有輕重緩急!

所以,最好選擇信賴度最高的方案來解決較佳!所以,當然是選上面 99.5% 信賴度的啊!然後,又看到底下的指令,

就是『 semanage port -a -t PORT_TYPE -p tcp 377 』這一段,你應該會覺得很開心!因為剛剛才學過啊!

只是, PORT_TYPE 必須要選擇正確的項目才行!因為我們是在處理 http 的埠口,當然最終選擇 http_port_t!

所以,整個解決方案的處理會是這樣:

[root@localhost ~]# semanage port -a -t http_port_t -p tcp 377

[root@localhost ~]# setenforce 1

[root@localhost ~]# getenforce

Enforcing

[root@localhost ~]# systemctl restart httpd

# 最終,在 Enforcing 的模式中,再次重新啟動服務!可正常啟動才會是正確的!

範例的思考也是很重要的!上面的範例中,原本鳥哥屬意的埠口是 538 (台語諧音:有三八),

但是,這個埠口竟然已經被 semanage port 所管理了!因此無法順利找到正確的解決方案!差點崩潰!

所以,未來想要找某個非正規埠口來練習時,還是得要先用底下的方法確認,不要使用已記載的埠口為佳!

『semanage port -l | grep 538』(結果沒出現任何訊息,該埠口才好應用!)

最後,讓我們使用文字型瀏覽器來看看我們的本機 (http://localhost) 有沒有順利提供服務呢?

[root@localhost ~]# curl http://localhost:377 2> /dev/null | head

HTTP Server Test Page powered by: Rocky Linux