圖文教程:SELinux政策實施詳解
譯文【2013年11月21日 51CTO外電頭條】今年我們已經迎來SELinux的十歲生日,回想十載發展歷程真有種如夢似幻之感。SELinux最早出現在Fedora Core 3當中,其后又登陸紅帽企業Linux 4。對于從未使用過SELinux或者希望進一步確認其基礎定義的朋友們,請接著往下看。
SElinux是一套標簽系統。每個進程都擁有自己的標簽,操作系統中的每個文件/目錄對象都擁有自己的標簽。甚至包括網絡端口、設備以及潛在主機名也被分配到了標簽。我們通過編寫規則來控制對某個進程標簽乃至對象標簽的訪問,這就是所謂管理政策。SELinux內核會強制執行這些規則,有時候我們將這種方案稱為強制訪問控制(簡稱MAC)。
對象的擁有者無權超越對象的安全屬性。標準Linux訪問控制、所有/組+權限標記(例如rwx)通常被稱為自主訪問控制(簡稱DAC)。SELinux中不存在UID或者文件所有權概念。所有事物都由標簽機制進行控制。這意味著SELinux系統可以在不涉及高權限root進程的前提下實現設置。
備注: SELinux并不會取代DAC控制。SELinux是一種并行執行模式,應用程序必須在同時符合SELinux與DAC的要求之后才能正常執行。這可能會讓管理人員們在遇到權限被拒絕的狀況時感到有些混亂。管理員權限被拒絕意味著DAC方面出了問題,但這肯定與SELinux標簽無關。
- 類型強制
讓我們進一步了解標簽機制。SELinux的主要模式或者強制手段被稱為"類型強制"。這意味著我們需要根據進程的實際類型為其定義標簽,而文件系統對象的標簽也同樣基于其類型。
比喻
讓我們假設有這樣一套系統,其中需要定義的對象類型分為貓(cat)或狗(dog)。一只貓與一條狗構成進程類型。
現在我們的一類對象希望與所謂“食物”(food)進行互動。食物也需要分為不同類型,也就是貓食與狗食。
作為政策的制定者,我打算采取這樣的處理方式:dog有權吃掉dog_chow食物,貓則有權吃掉cat_chow食物。在SELinux中,我們會把這條規則寫入政策。
- 允許貓進程吃掉cat_chow:food;
- 允許狗進程吃掉dog_chow:food;
有了這些規則,系統內核將允許貓進程吃掉擁有cat_chow標簽的食物,而狗進程則吃掉擁有dog_chow標簽的食物。
但在默認情況下,SELinux系統會阻止一切執行請求。這意味著如果狗類進程試圖吃掉cat_chow,內核會對此加以阻止。
與之類似,貓進程也不允許接觸狗進程的食物。
實際情況
我們將Apache進程標簽為httpd_t,并將Apache內容標簽為httpd_sys_content_t與httpd_sys-content_rw_t。假設我們把信用卡數據保存在一套MySQL數據庫當中,其標簽為mysqld_data_t。如果某個Apache進程并侵入,黑客就能夠獲得httpd_t進程的控制權并獲準讀取httpd_sys_content_t文件的內容、向httpd_sys_content_rw_t當中寫入數據。然而黑客仍然無法讀取信用卡數據(mysqld_data_t),即使被侵入的進程以root權限運行。在這種情況下,SELinux能夠顯著緩解由侵入活動帶來的安全威脅。
- MCS強制
比喻
在前面提到的狀況里,我們輸入了狗與貓兩種進程類型。不過如果狗進程又分為兩種:Fido與Spot,我們又不希望Fido去動Spot的dog_chow,情況又會發生怎樣的變化?
一種解決方案當然是創建大量新類型,例如Fido_dog與Fido_dog_chow。不過這種作法很快就將失去可行性,因為所有狗類進程都擁有近乎相同的權限。
為了解決這個難題,我們開發出一種新的強制形式,我們將其稱為多類別安全(簡稱MCS)。在MCS當中,我們為標簽加入另一種組成部分,并將其應用到狗進程與dog_chow food當中。現在我們把狗進程分別標記為dog:random1(代表Fido)與dog:random2(代表Spot)。
我們將狗食標記為dog_chow:random1(Fido)與dog_chow:random2(Spot)。
MCS規則的內容是:如果類型強制規則沒問題、隨機MCS標簽也確切匹配,那么訪問才會被通過;如果二者中有一項不符合要求,訪問就會被拒絕。
Fido (dog:random1)如果嘗試吃掉cat_chow:food,則會被類型強制所拒絕。
Fido (dog:random1)獲準吃掉dog_chow:random1。
Fido (dog:random1)無法吃掉Spot的(dog_chow:random2)食物。
真實情況
在計算機系統當中,我們通常會面對大量訪問相同對象的進程,但我們希望它們彼此之間能夠被區分開來。我們有時候會將此稱為多租戶環境。處理此類環境的最佳方案就是虛擬機系統。如果我擁有一臺運行著大量虛擬機的服務器,而其中一套虛擬機已經受到黑客入侵,我肯定希望阻止黑客以此為跳板進一步擾亂其它虛擬機以及虛擬機鏡像。不過在類型強制系統當中,KVM虛擬機會被標記為svirt_t,而鏡像被標記為svirt_image_t。我們的規則是允許svirt_t讀取/寫入/刪除擁有svirt_image_t標簽的內容。在虛擬機標簽機制當中,我們不僅要采用類型強制方案,同時也要通過MCS對其加以區分。當虛擬機組即將啟動一套虛擬機系統時,會為其選擇一個隨機MCS標簽,例如s0:c1,c2,而后將svirt_image_t:s0:c1,c2標簽分配給該虛擬機需要管理的所有內容。最后,虛擬機會以svirt_t:s0:c1,c2的標記啟動。這時SELinux內核能夠控制svirt_t:s0:c1,c2無法向svirt_image_t:s0:c3,c4寫入內容,而且這種控制能力在虛擬機受到黑客掌握且對方擁有root權限的情況下也同樣有效。
我們在OpenShift當中也使用類似的隔離機制。每個組件(包括用戶/應用程序進程)都以同樣的SELinux類型加以運行(openshift_t)。政策定義規則、規則決定如何控制與組件類型及獨特MCS標簽相關的訪問活動,從而確保不同組件之間無法交互。
感興趣的朋友可以點擊此處查看一段小視頻,了解如果某個Openshift組件擁有root權限將引發怎樣的狀況。
- MLS強制
這是SELinux的另一種強制形式,但使用的頻繁要低得多,這就是多級安全(簡稱MLS);它誕生于上世紀六十年代,主要被用于Trusted Solaris等受信操作系統。
其主要思路在于以數據被使用的層級為基礎進行進程控制。也就是說,secrect進程無法讀取top secret數據。
MLS與MCS非常相似,但它為強制機制添加了"支配"這一概念。MCS標簽必須在完全匹配的情況下才能通過,但一條MLS標簽可以支配另一條MLS標簽從而獲得訪問許可。
比喻
現在我們不再討論不同的狗只,而將著眼點放在不同的狗類品種。舉個例子,現在我們面對的是一只灰狗與一只吉娃娃。
我們允許灰狗吃任何一種狗食,但吉娃娃則無法吃下灰狗的狗食。
我們為灰狗設定的標簽為dog:Greyhound,它的狗食則為dog_chow:Greyhound;而吉娃娃的標簽為dog:Chihuahua,它的食物標簽為dog_chow:Chihuahua。
在MLS政策之下,我們讓MLS灰狗標簽對吉娃娃標簽擁有支配權。這意味著dog:Greyhound可以吃掉dog_chow:Greyhound與dog_chow:Chihuahua。
但dog:Chihuahua不允許吃掉dog_chow:Greyhound。
當然,dog:Greyhound與dog:Chihuahua仍然受到類型強制的影響而無法吃掉cat_chow:Siamese,即使在MLS當中灰狗類型對暹羅貓類型擁有支配權。
真實情況
假設我擁有兩臺Apache服務器:一臺以httpd_t:Topsecret標簽運行,另一臺則以httpd_t:Secret標簽運行。如果Apache進程httpd_t:Secret遭到侵入,黑客將能夠讀取httpd_sys_content_t:Secret內容,但無法讀取httpd_sys_content_t:TopSecret內容。
不過如果運行著httpd_t:TopSecret的Apache服務器遭到入侵,則httpd_sys_content_t:Secrect與httpd_sys_content_t:TopSecret的內容都將暴露在黑客面前。
我們將MLS機制用于軍事環境下,即某位用戶只獲準查看secret數據,而另一位處于同一系統下的用戶則可以查看top secret數據。
總結
SELinux是一套強大的標簽系統,通過內核對每一個單獨進程進行訪問控制。其中最主要的功能就是類型強制,其中規則的作用是根據進程與對象雙方的標簽類型來判斷某個進程是否有權讀取相應的對象。此外另有兩種控制機制,其中MCS負責對同類進程進行彼此區分,而MLS則允許一種進程擁有指向另一種進程的支配權限。
原文鏈接:http://opensource.com/business/13/11/selinux-policy-guide#.UoWMDG-jYlE.sinaweibo