在前一個章節裡:
Part 7 安全與權限問題不就是一件很簡單的事情嗎 ?
直接放到/usr/share/nginx/html 下不就萬事OK了嗎 ? 但我想這個疑問也是一個剛切換到RedHat Based Linux 的疑問。我剛開始也不信邪,然而奇怪的問題接踵而至: 怎麼從其他地方移動到/html中的網頁都存取不了 ? 甚至最後搬出大絕招,資料夾擁有者改nginx,擁有者也改nginx,chmod 777 也無效。縱使突然好了,怎麼樣子都無法讓/html 中的php網頁執行寫入檔案動作。It really grinds up my nerve.
難道Fedora 可以Bloody Cutting-Edge 到連Bug 都放這麼大嗎 ?
不,這是一個從其他Linux 發行版(尤其是Debian-based的),切換到RedHat Based Linux 的鬼打牆,一個無形警察: SELinux。
開始前請注意:
請不要隨意執行setenforce 0 或 透過 /etc/sysconfig/selinux 把 SELINUX=disabled,除非您在進行測試,否則在可能的情形下,以透過更改SELinux 規則或繞道法(我們等一下會提及)來讓您的網頁或程式能在SELinux 執行的模式下提供服務。SELinux 提供了您系統良好的安全性,是做為公開伺服器十分需要的條件之一。What is SELinux ?:
SELinux用來補足Linux 在權限上管理的不足,你可以對任何目標(例如應用程式、檔案、資料夾等) 規定十分嚴謹的規則,好比nginx / apache 這類的程式,都適用預先規定的httpd_xxx 的各種SELinux規則。如果想要看SELinux 對於httpd 規定了哪些行為:
# getsebool -a | grep httpd
接著我們來觀看html 資料夾套用的SELinux限制:
# ls -lZ /usr/share/nginx | grep html
我們來看Nginx 的一些重要的預設SELinux 設定(會直接影響架站的):
- httpd_can_network_connect --> off (是否允許httpd類程式主動連線其他主機 ?)
- httpd_can_network_connect_db --> off (是否允許httpd類程式主動連線外部資料庫 ?)
- httpd_can_sendmail --> off (httpd類程式是否可以主動進行寄送電子郵件 ?)
- httpd_sys_rw_content_t --> httpd類程式能對目標項目(資料夾或檔案)做讀取、執行與寫入。
- httpd_sys_content_t --> httpd 類程式只能對目標項目(資料夾或檔案)做讀取與執行,不能寫入(我們可以看到html資料夾就是這個設定)。
我們先來解釋這幾項為什麼會直接影響到架站:
httpd_can_network_connect 和 httpd_sys_content_t:多數的網頁框架軟體(好比WordPress, Drupal, Joomla等) 上載檔案、變更設定、安裝外掛、安裝主題等等時,都會對網站資料夾內的內容作出變更。不開放寫入權限會讓這些行為失敗。而又如Wordpress中有線上更新與線上安裝外掛的功能,若系統不開放httpd類程式聯網,這類功能也無法使用。
當然您的網頁可能是靜態的,那這些行為都不需要做,不過仍請翻到更後面說明的: 資料夾SE權限重建。
httpd_can_network_connect_db:
如果您的資料庫是在其他台電腦時,這會讓您的網頁執行需要存取其他電腦,此時您必須將此項開啟。否則連線會失敗(包含存取lo(loopback)介面(127.0.0.1),localhost不會)。
httpd_can_sendmail:
(尤其是論壇類) 如果您的電腦需要寄送信件(好比註冊確認信件等),您必須要讓httpd能夠執行sendmail功能。
而怎麼變更這些設定值呢 ?
setsebool [設定項目] [啟動或關閉]
例如: setsebool httpd_can_network_connect on/off
在大部分的情況之下,架設個人部落格或小型網站,我們考慮網頁伺服器與資料庫在同一台主機上,故我們只針對httpd_sys_content_t(也就是不能寫入的html資料夾)做處理。SELinux的項目權限管理工具: semanage
由於系統預設是沒有這項工具的,所以需要安裝:
# dnf install policycoreutils-python-utils
指令語法:
semanage [fcontext (對目標項目永久變更)] [增加(-a)/移除(-d)或修改(-m)] [-t (SE權限)] “[目標(一定要是完整目錄)][(/.*)? 包含目標中所有子項目]”
一旦對於一個目標或項目做了變更,都必須要求系統更新SELinux狀態:
restorecon [-R是否要連目標中所有子項目都要變更] [v要不要顯示每一個子項目做得更改在螢幕上] [目標]
範例:
# cd /usr/share/nginx/html/
# ls -lZ
1個項目
drwxr-xr-x. 2 root root unconfined_u:object_r:httpd_sys_content_t:s0 6 3月 26 16:57 testfolder
# semanage fcontext -a -t httpd_sys_rw_content_t “/usr/share/nginx/html/testfolder(/.*)?”
# restorecon -Rv /usr/share/nginx/html/testfolder
Relabeled….
# cd testfolder
# ls -lZ
2個項目
-rw-r--r--. 1 nginx nginx unconfined_u:object_r:httpd_sys_rw_content_t:s0 10 3月 26 17:04 testfile1
-rw-r--r--. 1 nginx nginx unconfined_u:object_r:httpd_sys_rw_content_t:s0 10 3月 26 17:04 testfile2
任何一個已經被賦予SELinux權限的項目若要更換其權限可以有兩種做法:
刪除原本的權限(semanage -d) 再新增
或是使用修改(semanage -m)
系統預設的SELinux檔案權限我可以從哪裡取得 ?:
# cat /etc/selinux/targeted/contexts/files/file_contexts
# cat /etc/selinux/targeted/contexts/files/file_contexts.homedir (跟家目錄管理相關的)
除了系統預設的SELinux檔案權限之外,我要怎麼知道哪些資料夾或檔案早就被我賦予SELinux 權限呢 ?:
# cat /etc/selinux/targeted/contexts/files/file_contexts.local
然而事與願違:
# ls -lZ /usr/share/nginx/
我們可以看到html 資料夾有被賦予SELinux 權限,故我們試圖將其從httpd_sys_content_t 改為httpd_sys_rw_content_t,然而當我們試圖移除權限時:
# semanage fcontext -d -t httpd_sys_content_t “/usr/share/nginx/html(/.*)?”
ValueError: /usr/share/nginx/html(/.*)? 的檔案情境已經定義在方針中,無法刪除
因為/usr/share/nginx/html 在系統規定的預設情境中。
備註: 情境是SELinux 對其中一個Profile 的稱呼,系統可以擁有多個情境,每個情境中都有不同的SELinux規則和設定,方便使用者管理與切換。
這時後要怎麼辦呢 ?
兩個解:自行建立一個資料夾(例如/data/www/) 然後賦予 httpd_sys_rw_content_t。
在/usr/share/nginx/html/資料夾中,再建立一個資料夾並賦予httpd_sys_rw_content_t,然後把跟目錄改到那裏去。
我們以比較簡單,容易管理的方法,建立/data/www ,並賦予httpd_sys_rw_content_t來繼續:
# mkdir /data/
# mkdir /data/www/
同時寫一個php寫入小程式來測試: 如果正常則會出現空白頁面,失敗則會出現500 Internal Error
# nano /data/www/phpwrite.php
然後在寫一個Hello World 的html index
# nano /data/www/index.html
phpwrite.php:
<?php
$content = “some text”;
$fp = fopen($_SERVER[‘DOCUMENT_ROOT’], “/myText.txt”, “wb”);
fwrite($fp, $content);
fclose($fp);
?>
index.html
<html>
<title>Hello World!</title>
<body>
<p>
<h1> How are you ?</h1>
</p>
</body>
</html>
把整個目錄內的所有內容全部送給nginx(讓檔案與資料夾屬於nginx):
# chown -R nginx.nginx /data/www/
最後賦予這些檔案與目錄有httpd_sys_rw_content_t權限:
# semanage fcontext -a -t httpd_sys_rw_content_t “/data/www(/.*)?”
# restorecon -Rv /data/www/
所以了解完SELinux 現在我們得來了解Nginx 的Config File: /etc/nginx/nginx.conf
Nginx Config的大架構:
備註:
好習慣要養成,變更任何config file 前,請先做好一份備份:
# cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.backup
發生問題時才能回到上一次沒問題的狀態。講這麼多,基本上就是要把root 那行改成/data/www/ 就行了。
但請不要覺得囉嗦,這些也許在未來會成為幫助您完nginx 新把戲的必備:
# nano /etc/nginx/nginx.conf
找到 root /usr/share/nginx/html 改成 root /data/www/儲存並結束
讓nginx 先檢查您的設定檔是否有語法錯誤:
# nginx -t
重新啟動 nginx
# systemctl restart nginx
接下來開啟瀏覽器:
輸入: http://[你的IP]
如果看到這個,你已經完成了正確設定SELinux,nginx 也正常執行了
我們接著來測試php寫入功能是否正常:
輸入: http://[你的IP]/phpwrite.php
如果看到空白頁面才是正常的喔。
我們來看一下php產生的檔案:
如果能看到some text
那麼恭喜你: 你已經正式的讓Fedora 成為你的架站利器了!
留言
張貼留言