有人說(shuō)Docker Hub上三成的鏡像包含漏洞?是嗎?
到底Docker Hub上是否三成的鏡像存在漏洞?通過(guò)漏洞計(jì)算發(fā)現(xiàn)確實(shí)有高比例漏洞,對(duì)于官方鏡像遵循Docker的安全指南,如若是自創(chuàng)建鏡像,可找源倉(cāng)庫(kù)或自行處理。但我們發(fā)現(xiàn),這些漏洞中大部分是老鏡像。面對(duì)漏洞鏡像,我們可以采取本地措施,還可用Web安全審查進(jìn)行檢查,如果想讓Docker更加安全,建議用dockerbench來(lái)評(píng)估。文中額外闡述了容器究竟有什么用。
這個(gè)數(shù)字太神奇了!并不是因?yàn)檫@個(gè)比例過(guò)高或者過(guò)低,而是因?yàn)榫尤淮嬖谶@個(gè)比例。既然存在(相對(duì)容易地)計(jì)算出這個(gè)比例的可能性,也就意味著存在(相對(duì)容易地)改善這個(gè)比例的可能性。
聲明:我是Docker官方人員,然而我寫這篇文章并未受到公司批準(zhǔn),所以***帶著批判的思維來(lái)讀本文。
這個(gè)數(shù)字來(lái)源于BanyanOps的博客。
漏洞的計(jì)算
首先,來(lái)看看怎么才能計(jì)算出原文中的數(shù)據(jù)。這過(guò)程比較簡(jiǎn)單:
- 獲取Docker注冊(cè)表的一個(gè)列表
- 下載列表中的鏡像
- 檢查鏡像中的漏洞
這步驟看起來(lái)似乎太簡(jiǎn)單,我們稍微深入下細(xì)節(jié)。
列舉鏡像
列舉官方的鏡像是容易的。這些鏡像是基于一個(gè)叫bashbrew的自動(dòng)化系統(tǒng)構(gòu)建而來(lái)的,使用的都是公布于眾的方法。順便一提,這意味著如果你想重建官方的鏡像,做起來(lái)也會(huì)很容易。(記住那些方法中涉及一些blobs或者tar包,是在啟動(dòng)的時(shí)候用到的;因而有時(shí)你要多費(fèi)一點(diǎn)力,重建這些blobs或者tarbal)。
構(gòu)建官方鏡像的方法在Github上的docker-library倉(cāng)庫(kù)可以找到。
要列出其他的鏡像(即屬非官方的用戶和機(jī)構(gòu)所有的鏡像)要困難點(diǎn)。Docker Hub目前沒(méi)有提供什么方法來(lái)列舉他們,所以一個(gè)暫時(shí)可行的方法是搜索一個(gè)十分寬泛的關(guān)鍵字,然后對(duì)其結(jié)果進(jìn)行提取。當(dāng)然,這需要一些抓取的工作;抓取到的結(jié)果可能會(huì)漏掉一些用戶的數(shù)據(jù),但是你拿到的結(jié)果已經(jīng)會(huì)十分接近了。(雖然這么做肯定可行, 我也聽(tīng)說(shuō)新的注冊(cè)表接口有一些十分好的特性,可以讓這一步完成起來(lái)容易點(diǎn))。
下載鏡像
下載鏡像是一個(gè)繁瑣的任務(wù)。如果你想安安靜靜的做這件事情,運(yùn)行一個(gè)docker的守護(hù)者進(jìn)程,然后執(zhí)行docker pull username/imagename:tag即可。
如果你想拿到容器的文件系統(tǒng)的一個(gè)tar包,也很容易:只需要運(yùn)行docker export username/imagename:tag就行。(記得把標(biāo)準(zhǔn)輸出重定向到其他地方,否則你的終端會(huì)抓狂的)
如果你不十分相信Docker的守護(hù)者進(jìn)程,你可以檢查registry的接口(v1,v2)并且通過(guò)接口來(lái)下載層,然后把層文件重組成鏡像文件。一些細(xì)節(jié)我想留給你自己去做,但是層文件只是普通的tar包,你只需要在彼此之上解包(需要保持正確的順序)就可以重組成鏡像文件。沒(méi)有什么特別難的步驟;唯一需要留心的地方就是“留白”(whiteout)。“留白”是特殊的標(biāo)記文件,用來(lái)表明“此處曾經(jīng)有文件存在于此,但目前沒(méi)有了”。換句話說(shuō),如果一個(gè)層包含文件/etc/foo.conf,但是之上的層把其刪除了,上一層就會(huì)包含一個(gè)/etc/.wh.foo.conf文件,并且foo.conf不會(huì)出現(xiàn)在容器里面。這個(gè)文件相當(dāng)于被留白文件加上了蒙板。
我后來(lái)發(fā)現(xiàn),了不起的Tianon已經(jīng)為此寫好了一個(gè)腳本,如果感興趣你可以去看看。
#p#
檢查鏡像
在這個(gè)階段你有幾件事情需要做。細(xì)節(jié)繁瑣,本文無(wú)法全部敘述;但是在一個(gè)全面的安全檢查中,下面這些步驟你可能需要做:
- 運(yùn)行yum-security或者類似的命令,保證在此刻沒(méi)有安全更新;
- 或者更好的做法是:列舉出所有安裝的包及其版本,然后檢查軟件包在該版本是否包含漏洞;
- 計(jì)算系統(tǒng)中的每一個(gè)文件的hash值,然后去跟已知的有漏洞的文件的hash集合去做比較;
- 執(zhí)行自動(dòng)化工具(如chkrootkit)尋找可疑的文件;
- 運(yùn)行一定數(shù)量的專門為某些漏洞而打造的漏洞測(cè)試。這些測(cè)試的目標(biāo)是嘗試?yán)媚承┞┒矗缓蟾嬖V你,“你的系統(tǒng)有漏洞,因?yàn)槲乙呀?jīng)設(shè)法利用了這個(gè)漏洞”或者“我無(wú)法利用這個(gè)漏洞,所以你的系統(tǒng)很可能沒(méi)有此漏洞”。
事情到了容器的環(huán)境中變得很有趣,因?yàn)橛肈ocker來(lái)自動(dòng)化這些步驟容易且便捷。例如,你可以將你的漏洞分析工具包放在/tmp/toolkit中,然后對(duì)于每一個(gè)鏡像$I,執(zhí)行docker run -v /tmp/toolkit:/toolkit $I /toolkit/runall.sh。
(注意:這里假設(shè)你的工具包是靜態(tài)鏈接并且/或者是自包含的,如不依賴你容器鏡像中的任何地方,因?yàn)檫@又可能讓你的工具包收到蒙騙。我這里主要想說(shuō)的是,如果你想用一系列的測(cè)試來(lái)檢查你的容器鏡像,你可以用容器讓這個(gè)步驟變得很簡(jiǎn)單,并且整個(gè)過(guò)程會(huì)更加的快速,因?yàn)閷?duì)于每一個(gè)測(cè)試你不需要單獨(dú)做一個(gè)檢查的機(jī)器的拷貝)
提升指標(biāo)
那么在我們運(yùn)行完這些測(cè)試,然后發(fā)現(xiàn)出奇高比例的鏡像包含有漏洞的包。我們?cè)趺磥?lái)改善這個(gè)指標(biāo)呢?
對(duì)于官方的鏡像,最容易的方法是遵循Docker的安全指南。以后隨著官方鏡像數(shù)的增長(zhǎng),Docker也會(huì)改善這個(gè)機(jī)制,達(dá)到自動(dòng)提示官方鏡像的上游安全列表的效果。
對(duì)于非官方的鏡像,你可以檢查鏡像中的Author字段:
- $ docker inspect --format '{{.Author}}' bin/ngrep
- Jerome Petazzoni
如果該鏡像是自動(dòng)構(gòu)建出來(lái)的,你可以找到其來(lái)源的倉(cāng)庫(kù),并且直接聯(lián)系他們。
如果你直接受到了漏洞的影響,想事情進(jìn)展的更加快速,你可以自己重建鏡像,并且/或者研究怎么才能修復(fù)這個(gè)漏洞,然后提交一個(gè)包含相應(yīng)修復(fù)的PR。這里的意圖不是把安全的責(zé)任推卸到鏡像的使用者身上,而是讓有意愿和有能力修復(fù)這些漏洞的人能對(duì)Docker鏡像的安全做貢獻(xiàn)。
在將來(lái),這些步驟會(huì)完善,并且流式化。會(huì)有自動(dòng)化的過(guò)程構(gòu)建出來(lái)減少需要聯(lián)系相關(guān)機(jī)構(gòu)的煩瑣,然后盡量降低發(fā)布包含漏洞補(bǔ)丁版本的時(shí)間。
但是30%還是太高了,對(duì)不對(duì)?
30%的“有漏洞的鏡像”可能聽(tīng)起來(lái)非常多。我***次聽(tīng)到也是這么想。但是如果你細(xì)看,你會(huì)發(fā)現(xiàn)其中一大部分的鏡像是老的鏡像,它們是__故意不被更新__的。
什么?__故意不被更新__?
是的,并且對(duì)此有一些好的解釋。***個(gè)是(其中的一部分)照顧其他的媒介。有的發(fā)行版想XYZ想在CD/DVD,網(wǎng)絡(luò)安裝,VM鏡像,和容器都保持一致。第二個(gè)原因是(這也解釋了***個(gè)原因)可重復(fù)的構(gòu)建。
設(shè)想你有一個(gè)服務(wù)器跑著12.04,但是你用一個(gè)新的Ubuntu 12.04的版本(更別提14.04)卻重現(xiàn)不出來(lái)。在更加深入的研究后發(fā)現(xiàn),這個(gè)問(wèn)題只存在于那些在某特定時(shí)間安裝的機(jī)器,其版本是12.04.02。如果一個(gè)容器鏡像有12.04.02的版本,你可以重現(xiàn)出這個(gè)bug;否則,你得從其他地方得到這個(gè)特定版本。這就是為什么Docker Hub有很多老的鏡像,它們保持著發(fā)行時(shí)的狀態(tài) - 同時(shí)包含當(dāng)時(shí)發(fā)行時(shí)的安全問(wèn)題。盡管這么說(shuō),我們已經(jīng)放置了安全警示說(shuō)“歷史的鏡像 - 保持遠(yuǎn)離”,所以我們比較希望這鏡像在計(jì)算出這些安全的指標(biāo)的時(shí)候不應(yīng)該被包含進(jìn)去。
讓我們希望下次有人在計(jì)算安全指標(biāo)的時(shí)候他們能意識(shí)到這一點(diǎn)。
在本地采取措施
我們可能跑著有漏洞的鏡像!求救!怎么辦,怎么辦?
事情沒(méi)有其看起來(lái)那么糟。當(dāng)你(或者其他人)做完對(duì)于這些鏡像(官方的,公開(kāi)的,私有的)的審查,結(jié)果是一個(gè)鏡像的列表(以一個(gè)唯一的hash 串),并且包含“PASS”或者“FAIL”的狀態(tài)。(對(duì)于“FAIL”的鏡像,你可能想知道一些其為何不通過(guò)的細(xì)節(jié),如:“好像有 ShellShock/CVE-2014-7187和其他漏洞”或者“包含軟件包OpenSSL 1.0.1c / CVE-2014-0160”。)
Web規(guī)模的安全審查
你可以拿著這個(gè)列表,然后與你本地的鏡像做比較。這里就是事情變得有趣的地方。根據(jù)本地鏡像和這個(gè)列表做一個(gè)簡(jiǎn)單而廉價(jià)的匹配結(jié)果,你就馬上能知道你是否運(yùn)行著有漏洞的鏡像。這可以很容易的擴(kuò)展到成千上百萬(wàn)的主機(jī)。
這也意味著事情可以很好的解耦:你的安全審查員不需要訪問(wèn)你的生產(chǎn)環(huán)境(甚至不需要訪問(wèn)你的開(kāi)發(fā)環(huán)境中的系統(tǒng))。他們甚至不需要要知道你運(yùn)行著什么鏡像:他們只需大面積的對(duì)鏡像做分析,然后得出結(jié)果給你。你甚至可以從幾個(gè)安全公司那里拿到結(jié)果然后比較他們的結(jié)果。
#p#
我的鏡像在創(chuàng)建后修改過(guò)怎么辦?
對(duì)于新手,你不應(yīng)該這么做。如果你像更新容器中的某些東西,你應(yīng)該創(chuàng)建一個(gè)新的鏡像然后運(yùn)行該新的鏡像。好吧,但是我已經(jīng)這么做了該怎么辦?
那真是什么都說(shuō)不準(zhǔn),但是至少我們能知道你這么做了。安全審查的一部分,你可以在運(yùn)行的容器上運(yùn)行docker diff來(lái)知道是否他們被修改了。(通常docker diff是沒(méi)有結(jié)果的。注意你已經(jīng)用shell啟動(dòng)了一個(gè)容器,或者在容器內(nèi)執(zhí)行過(guò)docker exec,你可能會(huì)看到少許的更改。但是生產(chǎn)環(huán)境的容器不應(yīng)該出現(xiàn)任何的更改結(jié)果。)
專業(yè)的Tip:你甚至可以防止更改,通過(guò)在容器中使用--read-only的標(biāo)記來(lái)達(dá)到這一點(diǎn)。這會(huì)讓容器的文件系統(tǒng)只讀,保證docker diff的結(jié)果為空。
如果你想用一條命令來(lái)檢查所有的容器,可以執(zhí)行:
- docker ps -q | xargs -I {} dockr diff {}
(感謝@diogomonica提供命令!)
我已經(jīng)構(gòu)建了自定義的容器怎么辦
如果你構(gòu)建了自己的容器,我建議你把他們上傳到一個(gè)倉(cāng)庫(kù)里面。如果這是一個(gè)公共的,我們就會(huì)到最初討論的情形。如果這是一個(gè)私有的,讓我們看下一個(gè)部分!
私有的鏡像和注冊(cè)表該怎么辦?
如果你上傳的是私有的鏡像怎么辦?如果你上傳的地方是一個(gè)本地的注冊(cè)表,或者Docker Hub的企業(yè)版怎么辦?
事情顯然變得更加復(fù)雜了。你可能會(huì)看見(jiàn)有人告訴你“設(shè)想ABC有CVE-XYZ的漏洞”如果他們從來(lái)沒(méi)有看到過(guò)鏡像ABC。
這里是一些可能會(huì)發(fā)生的事情:
安全提供商可以提供鏡像的掃描器,你可以用在自己的鏡像上;
安全提供商可以更進(jìn)一步,將其集成到Docker的注冊(cè)表中。這可以通過(guò)分配讀權(quán)限(訪問(wèn)Docker Hub上的私有鏡像)或者部署前置(on-prem)的安全掃描器(對(duì)于Docker Hub企業(yè)版的情形)來(lái)實(shí)現(xiàn)。在兩個(gè)情形中,都能達(dá)到一旦鏡像上傳就會(huì)被自動(dòng)掃描的效果,并且立即報(bào)告任何可能包含的漏洞。
結(jié)論
有兩點(diǎn)我想強(qiáng)調(diào),因?yàn)槲蚁嘈胚@能在安全領(lǐng)域產(chǎn)生好的結(jié)果。
得出數(shù)字是好的。一旦我們得到了量化的數(shù)據(jù),我們可以提升他們。Docker對(duì)于安全問(wèn)題十分延嚴(yán)肅,你可以很肯定我們會(huì)和社區(qū)及鏡像的維護(hù)者一期來(lái)改善這些量化數(shù)據(jù)。
有類似這樣的圍繞著Docker和Docker Hub的生態(tài)環(huán)境和社區(qū),讓他們成為一個(gè)樹(shù)立標(biāo)準(zhǔn)的地方。正如Soloman在一些keynote里面指出的,Docker里面最重要的一點(diǎn)不是技術(shù),而是讓人在某事上達(dá)成一致。
后一點(diǎn)意味著Docker現(xiàn)在有足夠的批評(píng)群體來(lái)校正橫向的工具(包括安全審查)來(lái)讓這個(gè)生態(tài)環(huán)境受益。其結(jié)果會(huì)是更加完善的安全機(jī)制,讓每一個(gè)人受益。
Docker注重安全
如果有Docker公司不在乎安全的印象,那真相離你就太遠(yuǎn)了。正如上面指出的,我們有一個(gè)負(fù)責(zé)的披露安全的政策,并且我們總是很快的解決我們意識(shí)到的問(wèn)題。沒(méi)有哪個(gè)軟件是沒(méi)有bug的。Docker也是由人類編寫出來(lái)的,即時(shí)他們有些人十分的了優(yōu)秀,但是還是會(huì)犯錯(cuò)。重要的是我們對(duì)待安全報(bào)告的嚴(yán)肅態(tài)度如何,我們解決這些問(wèn)題的速度如何;我想我們?cè)谶@些方面都一直做的很好。
如果你想讓你的Docker的環(huán)境更加安全,我推薦你看下dockerbench。我參與了其編寫,該軟件包含了一個(gè)自動(dòng)化的評(píng)估工具可以用來(lái)評(píng)估Docker的主機(jī),使用的是CIS Docker 1.6 Benchmark。它會(huì)檢查很多事情(如是否SELinux和AppArmor是啟用了的)然后生成一個(gè)報(bào)告。
這是Docker會(huì)推出或者參與的一大批軟件的***批,目的是讓你可以在沒(méi)有Docker容器安全方面的Ph.d的證書(shū)的情形下,或者在沒(méi)有聘請(qǐng)一個(gè)Taylor Swift的情形下,安全地運(yùn)行Docker。
并且,我們鼓勵(lì)公開(kāi)的討論,安全的擔(dān)憂也不例外。Docker Library的倉(cāng)庫(kù)里面有一個(gè)十分有趣的有關(guān)于這個(gè)話題的討論。
額外的提示
有人問(wèn)我闡釋下容器究竟為什么有用,如果我們不反復(fù)的檢查我們運(yùn)行的所有的東西的來(lái)源。這里是一些例子:
- 容器讓我們可以在沙箱環(huán)境下測(cè)試一些危險(xiǎn)的操作(如著名的curl ...| sh),并且可以查看到底能產(chǎn)生結(jié)果,這得益與docker diff。
- 容器讓我們可以在沙箱環(huán)境下測(cè)試一些危險(xiǎn)的操作(比如一個(gè)商用軟件的install.sh),并且可以查看到底能產(chǎn)生結(jié)果,這得益與docker diff。
- 容器讓我們可以在沙箱環(huán)境下測(cè)試一些危險(xiǎn)的操作(如安裝一個(gè)npm,pip,gem等等的包,但是我們不清楚其來(lái)源),并且可以查看到底能產(chǎn)生結(jié)果,這得益與docker diff。
- 容器讓我們可以在沙箱環(huán)境下測(cè)試一些危險(xiǎn)的操作(如安裝一個(gè)deb,rpm或者其他的發(fā)行版的包),并且可以查看到底能產(chǎn)生結(jié)果,這得益與docker diff。
- 容器讓我們可以在沙箱環(huán)境下測(cè)試一些危險(xiǎn)的操作(如安裝一個(gè)危險(xiǎn)的squid包),并且可以查看到底能產(chǎn)生結(jié)果,這得益與docker diff。
- 我猜想你能看出這個(gè)模式。僅僅因?yàn)槭虑橐砸环N熟悉的形式呈現(xiàn)給你并不代表它們是安全的。但是我們可以使用Docker來(lái)提升安全性。