在SELinux中基於角色的訪問控制

基於角色的訪問控制(RBAC)是常用的簡化管理的安全模式,通過給用戶指定角色,然後再給角色授權來實現,RBAC在SELinux中扮演用戶與基礎類型加強模式(TE)之間的抽象層,它提供非常細粒度的訪問控制,但是管理難度並沒有降低,研究如何將SELinux上下文的3部分(策略、內核和用戶空間)協同工作以強制使用RBAC和限制Linux用戶在TE策略中。

在SELinux下安全策略的實施是在基於角色的訪問控制(RBAC)下的類型增強(TE),(SELinux也能實現多級安全(MLS)的實施,MLS在本文範圍之外),類型增強(TE)是最常見的,但也是最不容易理解的,因爲它強制實施更細粒度的許可:當某些東西因爲異常訪問拒絕而遭到破壞時,類型增強(TE)是最可靠的,在TE中,一個進程的安全域(它的影響超過了系統)是由任務歷史和當前執行的程序決定的

RBAC的概念並不象TE一樣被經常提到,並且因爲他與TE集成的原因,總是讓人難以理解,你通常會認爲RBAC是按照用戶被分配的角色進行訪問的,從TE方面來說SELinux明確指出了基於角色的訪問,因此SELinux下RBAC的目標是允許基於角色的權限管理,然後限制一個角色的權利域,合成一個有效的安全上下文。

要知道這是如何工作的,請看一個簡單的現金帳簿會計系統是如何使用SELinux提供安全保護的,你將在兩個完全不同的環境(看這兩個環境相關的下載,附錄A)下看到一樣的解決方案:

在developerWorks網站上有一篇文章“從零開始SELinux”介紹瞭如何從零開始一個SELinux系統,這個系統顯示在內核和用戶空間裏的部分是綁定在一起的。

Fedora Core 8 系統,Fedora Core 8 系統(寫本文時的最新版本)展示了SELinux與RBAC是如何高度地集成在一起的。

與角色一起工作

假設你已經要求一個庫房部門部署一套安全登記庫存會計系統,因爲每天都進行現金帳簿,最終數量必須同時被出納和經理統計,因此我們首先定義兩個角色,出納和經理,然後我們將角色賦予了需要它的僱員,即賦予出納和經理。

在兩個系統上的策略文件或許會稍微不同,在兩個系統上都使用現金帳簿系統,數據一樣,所有數據存儲在/data目錄下,並且只能通過/bin/register.py程序進行訪問,register.py能同時被經理和出納使用,用於存儲數值,爲了保持代碼簡潔,缺少一些特點,出納每天爲他自己存儲現金帳簿值,經理能爲其他僱員存儲數值,當出納與經理爲同一個出納存儲相同的數值時,經理能夠提交這個數值。

在2007/12/12晚上9點,當出納Bob使用register.py存儲了一個數值109.95時,文件/data/cashier_r/bob/12-12-2007被創建,內容是"bob 09:00 109.95.",後來,經理Mary在9:25存儲了一個相同的數值,結果文件/data/cashier_r/bob/12-12-2007被覆蓋,內容爲"mary 09:25 109.95.",最後,Mary在晚上9:27提交了這個數值,bob使用register.py提交後創建了文件/data/final/bob/12-12-2007,內容爲"mary 09:27 bob mary 109.95."。

如果Bob和Mary對他們的數值都不同意,Mary將不能爲Bob提交數值了,他不得不去找Bob協商,除非他們兩個都同意,否則這兩個數值都必須重新計算,重新運行register.py命令用前面的數值再計算一次,新的結果將附加到先前的結果後以便倉庫管理員稍後容易閱讀,bob使用/bin/register.py命令提交時將使用最後的那個數值而不是/data/cashier_r/bob/12-12-2007和/data/mgr_r/bob/12-12-2007。

注意:在這個例子中討論的代碼都爲訪問控制需要使用了SELinux,我們的例子簡單地允許所有擁護都能完全往/data目錄下的文件和目錄中進行寫入訪問,在一個真實的部署環境中,你可能會想到使用DAC[譯者注:即傳統的linux權限控制,使用訪問控制列表ACL]許可來進行深度防禦,所有經理都希望在/data/mgr_r/bob/和/data/final/bob/目錄下創建文件,牽涉到UNIX組權限的小心使用,但是更簡單的辦法是,完全依靠SELinux來實現強制訪問控制。

首先阻止經理和出納訪問/data目錄下的任何文件,除非通過register.py程序,實際上,Bob將以cashier_t類型登陸到角色cashier_r,但是cashier_t不能讀取/data目錄下的內容,爲了能讀取,他必須進入cashier_register_t類型,進入後也只能執行/bin/register.py程序,類似地,Mary將以mgr_t登陸到角色mgr_r,但是他必須進入mgr_register_t類型後才能執行/bin/register.py程序來訪問/data目錄下的內容。

第一個訪問控制實際上發生在登陸的時候,PAM模塊認爲Bob必須登陸到cashier_r角色,當在內核中的SELinux類型增強服務器拒絕同意bob_u:cashier_r:cashier_t進入bob_u:cashier_r:cashier_register_t時也會發生,除了執行cashier_exec_t類型的文件,cashier_exec_t是管理員僅僅爲/bin/register.py指定的類型。

當register.py拒絕同意出納提交數據或爲另一個用戶存儲數據時也會發生,將來通過SELinux策略進行加強,並且內核代碼也會加強策略的控制,它不允許cashier_register_t訪問/data/mgr_r或/data/final目錄下的文件。

部署現金帳簿系統

 

部署現金帳簿會計系統的第一步建立在前面提及到的從零開始一個SELinux系統(可以在http://www.ibm.com/developerworks/linux/library/l-rbac-selinux/index.html?ca=drs-#download下載)之上,下面的步驟將展示完成一個從零開始的系統。

加載要使用的磁盤鏡像(關閉qemu鏡像):

mount -o loop,offset=32256 -t ext2 gentoo.img /mnt

http://www.ibm.com/developerworks/linux/library/l-rbac-selinux/index.html?ca=drs-#download下載code_for_fromscratch.tgz,然後在磁盤鏡像下解壓:

tar zxf selinuxregister.tgz -C /mnt
umount /mnt 

現在開始qemu鏡像:

qemu -hda gentoo.img -m 512 -vnc :3 -kernel bzImage -append "ro root=
/dev/hda1 -p"

一旦你登陸進去,你必須編譯並安裝新的策略和新的PAM模塊:

cd /usr/src
checkpolicy -c 19 -o policy.bin policy.conf
cp policy.bin /etc/
rc-update add selinuxenforce default
cp /etc/pam.d/system-auth /etc/pam.d/system-auth.orig
cp /etc/pam.d/system-auth.new /etc/pam.d/system-auth

在策略中的用戶被創建,但是你必須創建與之對應的Linux用戶:

adduser mary
passwd mary
  (passwd)
mkdir /home/mary
adduser boss
passwd boss
  (passwd)
mkdir /home/boss
adduser bob
passwd bob
  (passwd)
mkdir /home/bob

然後爲數據存儲創建目錄結構:

mkdir /data
mkdir /data/cashier_r
mkdir /data/mgr_r
mkdir /data/final
chmod 777 /data/*
最後,給文件系統做上標記:
setfiles /usr/src/filecontexts /
poweroff

現在鏡像準備好了,不加-p參數重新啓動它,SELinux策略就被加載了:

qemu -hda gentoo.img -m 512 -vnc :3 -kernel bzImage -append "ro root=
/dev/hda1"

再以root登陸並再次嘗試:
ls /data

權限被拒絕,註銷root然後用bob登陸,我們的出納,登記一個數值,例如:
register bob 25.22

然後嘗試欺騙系統:
register bob commit

不能工作,註銷bob然後用Mary登陸:
register bob commit

哦,Mary首先需要敲入她自己的數值:
register bob 27
register bob commit

數值不匹配,想知道Bob提交後的結果嗎?
cat /data/cashier_r/bob/(day)

哦,你未被允許查看它,你將不得不去找Bob進行協商,或許你要重新統計你的帳簿並查出他是對的,因此:
register bob 25.22
register bob commit

這下沒有問題了,現在你以root用戶登陸並:
cat /data/final/bob/(day)

這下將顯示所有輸入的數值了。

更進一步研究類型增強

 

不同用戶使用相同的/bin/register程序讀/寫沒有這個程序他們就不能訪問的不同文件,這就是類型增強的核心概念:用戶經過認證的上下文和正在被執行的代碼將一起決定進程的“權利域”或“TE域”。

圖1展示了我們系統中的域和類型:
 

圖1

但是是什麼阻止Bob作爲經理登陸或Mary作爲出納登陸的呢?更有趣的是,老闆是如何以這兩者進行登陸的呢?

第一點是通過新的PAM模塊實現的,簡單地說,PAM(可插拔的認證模塊)允許小塊代碼在不同認證步驟中執行,並允許模塊靈活地執行,我已經介紹過一個新的模塊,pam_ctx.so,它的代碼在/usr/src/pam_ctx下,它爲正被認證的用戶名在文件/usermap.conf中搜索,併爲這個用戶找出默認的上下問,對於Bob而言,默認的上下文是cashier_u:cashier_r:cashier_t,對於Mary而言,默認的上下文是mgr_u:mgr_r:mgr_t,對於老闆來說,默認的上下文是full_u:mgr_r:mgr_t,注意所有的上下文都由冒號分隔的3部分組成:

◆最後一部分是域,它最終決定用戶在系統上的權限
◆第二部分是角色,它限制了用戶可以進入的域
◆第一部分是SELinux用戶,與角色和域相似,它限制了進程可以進入的角色

PAM模塊通過將上下文寫入文件/proc/$$/attr/exec來設置上下文,然後再對新域執行一個有效登記類型的shell腳本,查看策略的代碼,你會看到mgr_r或許是與域mgr_t,mgr_register_t, and rolechange_t聯繫在一起,角色cashier_r或許是與域cashier_t和cashier_register_t聯繫在一起,類似地,SELinux用戶mgr_u或許是與角色mgr_r聯繫在一起,cashier_u與cashier_r聯繫在一起,用戶full_u或許是與mgr_r或cashier_r聯繫在一起。

圖2展示了所有這些是如何聯繫在一起的

圖2


最上面的一行展示了我們的SELinux用戶,中間的行列出了角色,下面的行列出了域,創建一個有效的安全上下文必須從連接在一起的條目中每一行使用一個項目,在策略裏,用戶的定義如下:
user full_u roles { mgr_r cashier_r };

 

當角色定義好後,將其與用戶建立連接:
role cashier_r types { cashier_t cashier_register_t };

定義一箇中間行的項目並將其與下面行的項目建立連接。

但是是什麼阻止Bob從"full_u:mgr_r:mgr_t"往/proc/$$/attr/exec裏寫入呢?有幾個原因,其中一個就是類型增強(TE),查看圖1,一旦你在類型cashier_t裏,你僅僅可以進入cashier_write_t,同樣,SELinux策略指出角色是可以轉變的,因此就可以:
allow mgr_r cashier_r;

指定一個基於角色mgr_r的進程切換到基於角色cashier_r的上下文:
allow cashier_r mgr_r;

因此Bob不能轉換到任何基於cashier_r的上下文。

我們也拒絕Mary進入cashier_t域的權限,查看圖1,實際上域是可以轉換自身的:
allow mgr_r cashier_r;

也允許角色進行轉換,然而,策略指出它必須首先通過/bin/role_change進入rolechange_t,這個程序將不會重寫SELinux用戶的上下文部分,因此,一旦登陸到mgr_u:mgr_r:mgr_t,如果不重新作爲經過/usermap.conf和pam_ctx.so認證的full_u用戶登陸的話將無法轉換到cashier_r角色。

在我們的策略裏有一件事情不用禁止,注意不是生來就可以控制SELinux用戶轉換,所有的控制都要依賴於SELinux用戶,角色和域,因此角色和域的轉換不允許轉換到任何有效的其他的—如果是我們要求的SELinux用戶上下文。

特別地,讓我們嘗試下面的內容,作爲root用戶登陸,並修改/bin/register.py讓它告訴我們它的上下文,我們將在一個新文件addme中增加一些行,然後插入/bin/register.py前面部分的內容。

echo 0 > /selinux/enforce
cat > /root/addme << EOF
f=open("/proc/self/attr/current", "r")
print f.readlines()
f.close()
EOF
nano /bin/register.py


現在用向下箭頭鍵引導光標到import行下,然後按Ctrl-r讀取文件,敲入/root/addme,再按Ctrl-O寫這個文件,回車確認文件名,然後按Ctrl-X退出,最後,將SELinux設置爲強制模式:

echo 1 > /selinux/enforce
logout
以bob用戶登陸,明確地要求SELinux做一個域轉換,然後運行register.py:
echo "full_u:cashier_r:cashier_register_t" > /proc/self/attr/exec
/bin/register.py bob 25

現在register.py作爲full_u:cashier_r:cashier_register_t運行!往/proc/pid/attr/exec文件寫入一個上下文引導SELinux嘗試轉換到這個上下文,下次執行就會使用這個上下文了,當然,僅當轉換有效纔會正常工作,在這個例子中,因爲我們沒有改變角色,因此轉換是有效的,並且cashier_t執行一個cashier_exec_t類型的文件是允許轉換到cashier_register_t的,如果你嘗試:
echo "full_u:mgr_r:mgr_register_t" > /proc/self/attr/exec
/bin/register.py bob 25

你將注意到權限被拒絕,最後,你可以嘗試:
echo "full_u:mgr_r:cashier_register_t" > /proc/self/attr/exec
/bin/register.py bob 25

這次權限沒有被拒絕了,但是,上下文顯示爲cashier_u:cashier_r:cashier_register_t,爲何表現不同了?因爲full_u:mgr_r:mgr_register_t是一個有效的上下文,因此下次執行實際上試圖進行域轉換時失敗了,但是,自從mgr_r與cashier_register_t建立聯繫以來,full_u:mgr_r:cashier_register_t就不再僅是一個有效的上下文了,在往/proc/self/attr/exec寫入上下文後,我們檢查了返回的數值,我們發現它失敗了。
echo "full_u:mgr_r:cashier_register_t" > /proc/self/attr/exec
echo $?
1
因此當你下次運行register.py時,它不會試圖要求域轉換了,但是要簡單地執行默認的域轉換,這會是成功的。

在這一點上,你可能會認爲我們的目標通過嚴格使用TE而不利用角色或SELinux用戶已經達到了,但是,使用角色和用戶在未來將會使系統管理變得更容易,當你看了如何在Fedora Core 8上實施後將會有更清醒的認識。

使用Fedora Core 8

 

默認情況下,Fedora 8是將SELinux起用了的,它集成了最新的SELinux技術,可載入的策略模塊,她使得自定義,semanage和RBAC管理更容易。(semanage用於配置SELinux策略必須的元素,它不需要改變或重新從策略代碼編譯)

讓我們從非常無趣的幾乎是默認的安裝開始,首先從http://fedoraproject.org/get-fedora下載Fedora-8-i386-DVD.iso,爲了方便你可以將起重新命名爲f8.img,在qemu下你可以將其作爲一個cdrom鏡像來安裝Fedora 8:

dd if=/dev/zero of=f8.img bs=1G seek=10 count=1
qemu -hda f8.img -cdrom f8.iso -boot d -m 1024 -vnc 3
然後,啓動VNCviewer:
vncviewer :3

在VNC窗口裏,選擇默認的安裝目錄,但有一個例外:當詢問安裝什麼包時,反選“辦公和生產力”,選擇“軟件開發”。

當安裝完畢後,重新啓動後,創建一個非root用戶,最後,當鏡像準備好了後,用這個用戶登陸。

打開一個瀏覽器窗口然後下載代碼包,地址是http://www.ibm.com/developerworks/views/download.jsp?contentid=288774&filename=code_for_f8.tgz&method=http&locale=worldwide,將其保存到你的home目錄~myuser/cash_register_f8.tgz。

從頂層左方的菜單“應用程序”開始,選擇系統工具終端,然後輸入su - ,回車再輸入root用戶的密碼打開一個root shell,現在你已經爲安裝安全帳簿會計系統作好準備了。
(注意:如果系統太慢以至於不能忍受,你可以退出X-window,將系統運行在級別3下,可以敲入/sbin/init 3來實現,你也可以用/sbin/init 5來重新啓動X-window重新進入級別5,在級別3下,用root登陸)

首先,強制一個後臺進程yum退出,因爲你可以手工運行yum:
killall -9 yum-updatesd
緊接着安裝SELinux策略模塊開發工具包:
yum install selinux-policy-devel.noarch
現在拷貝樣例策略模塊目錄,拷貝現金帳簿策略文件到樣例目錄並編譯它們:

cd /usr/share/selinux/
cp -r devel cash_register
cd cash_register
rm example.*
tar zxf ~myuser/cash_register_f8.tgz
mv register.py /bin
make

策略被編譯成一個在文件cash_register.pp中的二進制策略模塊,要載入它:

semodule -i cash_register.pp
下一步,創建用戶mary和bob:
adduser bob
adduser mary
passwd bob
passwd mary

用戶創建好了,設置RBAC以便他們登陸到合適的角色:

semanage user -a -R cashier_r -P cashier bob_u
semanage login -a -s bob_u bob

semanage user -a -R mgr_r -P mgr mary_u
semanage login -a -s mary_u mary

semanage用戶管理命令創建了一個新的SELinux用戶,SELinux用戶不是Linux用戶名,但是SELinux上下文的第一部分(id –Z返回的內容)是附加到一個進程和文件的,如果你在終端裏敲入id –Z,將會看到system_u或unconfined_u,你的Linux用戶名和SELinux用戶名是可以相同的,他們不是單獨聯繫的,但是,登陸進程爲你的安全上下文使用Linux用戶名來選擇一個SELinux用戶,與前面章節討論的一樣,SELinux用戶是受與其有關聯的角色限制的,同樣,SELinux角色也受與其關聯的SELinux域(類型)限制。

 

你正在使用semanage創建兩個SELinux用戶,mary_u和bob_u,同時,你也正在指定與其關聯的角色,用戶bob_u或許僅僅使用cashier_r角色,mary_u僅僅使用mgr_r角色,你還必須給用戶home目錄類型指定一個前綴。對mary而言,指定mgr,它將爲她的home目錄擴展爲mgr_home_dir_t,併爲那裏面的文件擴大爲mgr_home_t。

Semanage登陸命令把Linux用戶名捆綁到SELinux用戶上,我們指出mary以mary_u登陸,bob以bob_u登陸。

我們還需要爲現金帳簿數據創建預備目錄結構:

mkdir /data
mkdir /data/final
mkdir /data/cashier_r
mkdir /data/mgr_r
chmod 777 /data/cashier_r
chmod 777 /data/mgr_r
chmod 777 /data/final

最後,重新標記所有創建並安裝的文件,同時包括爲新用戶創建的目錄:
fixfiles -f relabel /data /bin/register.py /home

注意此時我們在策略裏並沒有定義SELinux用戶,相反地,semanage命令創建了用戶並將其與合適的角色進行了關聯。

如果你只希望bob以cashier_r角色,mary以mgr_r角色登陸的話,所有事情都很好,但是或許你需要用戶charlie既能以cashier_r登陸,也能以mgr_r登陸,這就需要一點改動了,首先創建用戶:

adduser charlie
passwd charlie
semanage user -a -R mgr_r -R cashier_r -P mgr charlie_u
semanage login -a -s charlie_u charlie

然後告訴PAM模塊charlie想以什麼角色登陸,首先打開/etc/pam.d/login並替換下面這一行:

session required pam_selinux.so open
爲:
session required pam_selinux.so open select_context

這將告訴pam_selinux.so模塊用戶將能選擇一個默認的上下文登陸,緊接着告訴系統基於角色charlie_r的用戶的默認類型,再次登陸時,Charlie將允許除默認角色(mgr_r,我們在semanage命令中列出來了)之外再指定一個角色,當你創建用戶時可以使用-R標記指定任何一個角色,SELinux將使用需要的角色與其關聯的默然類型,因此你必須爲cashier_r指定一個默認的類型:
echo "cashier_r:cashier_t" >> \
/etc/selinux/targeted/contexts/default_type

現在Charlie登陸到終端(按Ctrl-Alt-F2轉到一個終端下或按前面敘述的進入級別3),他將被問及要以什麼角色登陸,默認的將是mgr_r,但是他可以用cashier_r登陸,如果他這樣做了,他將能作爲一個出納存儲他自己的數據,但是由於我們已經定義了策略,他將不能讀取他home目錄下的任何文件。

注意register.py不能防止Charlie爲他自己的現今帳簿存儲數據,不管是作爲經理還是出納登陸,他都可以提交數據,當然,這樣的一個改變將非常容易實施。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章