相信很多開發者都預設docker這樣的容器是一種沙盒(sandbox)應用,也就是說他們可以用root權限在docker中運作随便什麼應用,而docker有安全機制能保護宿主系統。比如,有些人覺得docker容器裡面的程序跟虛拟機裡面的程序一樣安全;還有的人随便找個源就下載下傳沒有驗證過的docker鏡像,看都不看内容就在主控端器上嘗試、學習和研究;還有一些提供paas服務的公司竟然允許使用者向多租戶系統中送出自己定制的docker鏡像。請注意,上述行為均是不安全的。
本文将介紹docker的隔離性和安全性,以及為什麼它在隔離和安全性上不如傳統的虛拟機。
<a target="_blank"></a>
單單就docker來說,安全性可以概括為兩點:
不會對主機造成影響
不會對其他容器造成影響
是以安全性問題90%以上可以歸結為隔離性問題。而docker的安全問題本質上就是容器技術的安全性問題,這包括共用核心問題以及namespace還不夠完善的限制:
/proc、/sys等未完全隔離
top, free, iostat等指令展示的資訊未隔離
root使用者未隔離
/dev裝置未隔離
核心子產品未隔離
selinux、time、syslog等所有現有namespace之外的資訊都未隔離
當然,鏡像本身不安全也會導緻安全性問題。
其實傳統虛拟機系統也絕非100%安全,隻需攻破hypervisor便足以令整個虛拟機毀于一旦,問題是有誰能随随便便就攻破嗎?如上所述,docker的隔離性主要運用namespace 技術。傳統上linux中的pid是唯一且獨立的,在正常情況下,使用者不會看見重複的pid。然而在docker采用了namespace,進而令相同的pid可于不同的namespace中獨立存在。舉個例子,a container 之中pid=1是a程式,而b container之中的pid=1同樣可以是a程式。雖然docker可透過namespace的方式分隔出看似是獨立的空間,然而linux核心(kernel)卻不能namespace,是以即使有多個container,所有的system call其實都是通過主機的核心處理,這便為docker留下了不可否認的安全問題。
傳統的虛拟機同樣地很多操作都需要通過核心處理,但這隻是虛拟機的核心,并非宿主主機核心。是以萬一出現問題時,最多隻影響到虛拟系統本身。當然你可以說黑客可以先hack虛拟機的核心,然後再找尋hypervisor的漏洞同時不能被發現,之後再攻破selinux,然後向主機核心發動攻擊。文字表達起來都嫌繁複,更何況實際執行?是以docker是很好用,但在遷移業務系統至其上時,請務必注意安全性!
在接納了“容器并不是全封閉”這種思想以後,開源社群尤其是紅帽公司,連同docker一起改進docker的安全性,改進項主要包括保護宿主不受容器内部運作程序的入侵、防止容器之間互相破壞。開源社群在解決docker安全性問題上的努力包括:
audit namespace
作用:隔離審計功能
未合入原因:意義不大,而且會增加audit的複雜度,難以維護。
syslognamespace
作用:隔離系統日志
未合入原因:很難完美的區分哪些log應該屬于某個container。
device namespace
作用:隔離裝置(支援裝置同時在多個容器中使用)
未合入原因:幾乎要修改所有驅動,改動太大。
time namespace
作用:使每個容器有自己的系統時間
未合入原因:一些設計細節上未達成一緻,而且感覺應用場景不多。
task count cgroup
作用:限制cgroup中的程序數,可以解決fork bomb的問題
未合入原因:不太必要,增加了複雜性,kmemlimit可以實作類似的效果。(最近可能會被合入)
隔離/proc/meminfo的資訊顯示
作用:在容器中看到屬于自己的meminfo資訊
未合入原因:cgroupfs已經導出了所有資訊,/proc展現的工作可以由使用者态實作,比如fuse。
不過,從08年cgroup/ns基本成型後,至今還沒有新的namespace加入核心,cgroup在子系統上做了簡單的補充,多數工作都是對原有subsystem的完善。核心社群對容器技術要求的隔離性,本的原則是夠用就好,不能把核心搞的太複雜。
一些企業也做了很多工作,比如一些項目團隊采用了層疊式的安全機制,這些可選的安全機制具體如下:
1、檔案系統級防護
檔案系統隻讀:有些linux系統的核心檔案系統必須要mount到容器環境裡,否則容器裡的程序就會罷工。這給惡意程序非常大的便利,但是大部分運作在容器裡的app其實并不需要向檔案系統寫入資料。基于這種情況,開發者可以在mount時使用隻讀模式。比如下面幾個: /sys 、/proc/sys 、/proc/sysrq-trigger 、 /proc/irq、/proc/bus
寫入時複制(copy-on-write):docker采用的就是這樣的檔案系統。所有運作的容器可以先共享一個基本檔案系統鏡像,一旦需要向檔案系統寫資料,就引導它寫到與該容器相關的另一個特定檔案系統中。這樣的機制避免了一個容器看到另一個容器的資料,而且容器也無法通過修改檔案系統的内容來影響其他容器。
2、capability機制
linux對capability機制闡述的還是比較清楚的,即為了進行權限檢查,傳統的unix對程序實作了兩種不同的歸類,高權限程序(使用者id為0,超級使用者或者root),以及低權限程序(uid不為0的)。高權限程序完全避免了各種權限檢查,而低權限程序則要接受所有權限檢查,會被檢查如uid、gid群組清單是否有效。從2.2核心開始,linux把原來和超級使用者相關的進階權限劃分成為不同的單元,稱為capability,這樣就可以獨立對特定的capability進行使能或禁止。通常來講,不合理的禁止capability,會導緻應用崩潰,是以對于docker這樣的容器,既要安全,又要保證其可用性。開發者需要從功能性、可用性以及安全性多方面綜合權衡capability的設定。目前docker安裝時預設開啟的capability清單一直是開發社群争議的焦點,作為普通開發者,可以通過指令行來改變其預設設定。
3、namespace機制
docker提供的一些命名空間也從某種程度上提供了安全保護,比如pid命名空間,它會将全部未運作在開發者目前容器裡的程序隐藏。如果惡意程式看都看不見這些程序,攻擊起來應該也會麻煩一些。另外,如果開發者終止pid是1的程序命名空間,容器裡面所有的程序就會被全部自動終止,這意味着管理者可以非常容易地關掉容器。此外還有網絡命名空間,友善管理者通過路由規則和iptable來建構容器的網絡環境,這樣容器内部的程序就隻能使用管理者許可的特定網絡。如隻能通路公網的、隻能通路本地的和兩個容器之間用于過濾内容的容器。
4、cgroups機制
主要是針對拒絕服務攻擊。惡意程序會通過占有系統全部資源來進行系統攻擊。cgroups機制可以避免這種情況的發生,如cpu的cgroups可以在一個docker容器試圖破壞cpu的時候登入并制止惡意程序。管理者需要設計更多的cgroups,用于控制那些打開過多檔案或者過多子程序等資源的程序。
5、selinux
selinux是一個标簽系統,程序有标簽,每個檔案、目錄、系統對象都有标簽。selinux通過撰寫标簽程序和标簽對象之間通路規則來進行安全保護。它實作的是一種叫做mac(mandatory access control)的系統,即對象的所有者不能控制别人通路對象。
最簡單的就是不要把docker容器當成可以完全替代虛拟機的東西。跑在docker容器中的應用在很長一段時間内都将會是選擇性的,通常隻跑測試系統或可信業務。
門檻再高一點,我們對系統做減法,通過各種限制來達到安全性。這也是最主流的、有效的安全加強方法,比如上一章節介紹的幾種安全機制。同時一定要保證核心的安全和穩定。外部工具的監控、容錯等系統也必不可少。
總之通過适配、加強的docker容器方案,在安全性上完全可以達到商用标準。就是可能對實施人員的技術要求和門檻較高。
docker線上文檔:docker security
opensource.com:bringing new security features to docker
infoq:從社群和核心看docker隔離性和安全性發展
原文釋出時間為:2015-05-29
本文來自雲栖社群合作夥伴“linux中國”