摘要:返回結(jié)果發(fā)現(xiàn)禁掉能力后,在容器里就無(wú)法改變?nèi)萜鞯乃姓吡恕2僮飨到y(tǒng)中訪問控制安全的發(fā)展早期的操作系統(tǒng)幾乎沒有考慮安全問題,一個(gè)用戶可以訪問任何文件或資源,但很快出現(xiàn)了訪問控制機(jī)制來(lái)增強(qiáng)安全性,其中主要的訪問控制在今天被稱為自主訪問控制。
整理自《Docker進(jìn)階與實(shí)戰(zhàn)》
Docker的安全性Docker的安全性主要體現(xiàn)在如下幾個(gè)方面:
Docker容器的安全性
這是指容器是否會(huì)危害到宿主機(jī)或其他容器;
鏡像的安全性
用戶如何確保下載下來(lái)的鏡像是可信的、未被篡改過的;
Docker daemon的安全性
如何確保發(fā)送給daemon的命令是由可信用戶發(fā)起的。用戶通過CLI或者REST API向daemon發(fā)送命令已完成對(duì)容器的各種操作,例如通過docker exec命令刪除容器里的數(shù)據(jù),因此需要保證client與daemon的連接時(shí)可信的。
容器的安全性問題的根源在于容器和宿主機(jī)共用內(nèi)核,因此受攻擊的面特別大,另外,如果容器里的應(yīng)用導(dǎo)致Linux內(nèi)核崩潰,那么毫無(wú)疑問,整個(gè)系統(tǒng)哥都會(huì)崩潰。這一點(diǎn)與虛擬機(jī)是不同的,虛擬機(jī)與宿主機(jī)的接口非常有限,而且虛擬機(jī)崩潰一般不會(huì)導(dǎo)致宿主機(jī)崩潰。
在共用內(nèi)核的前提下,容器主要通過內(nèi)核的Cgroup和Namespace這兩大特性來(lái)達(dá)到容器隔離和資源限制的目的。目前Cgroup對(duì)系統(tǒng)資源的限制已經(jīng)比較完善了,但Namespace的隔離還是不夠完善,只有PID、mount、network、UTS、IPC和user這幾種。而對(duì)于未隔離的內(nèi)核資源,容器訪問時(shí)也就會(huì)存在影響到宿主機(jī)及其他容器的風(fēng)險(xiǎn)。
比如,procfs里的很多接口都沒有被隔離,因此通過procfs可以查詢到整個(gè)系統(tǒng)的信息,例如系統(tǒng)的CPU、內(nèi)存等資源信息。這也是為什么Docker容器的procfs是以只讀方式掛載的,否則修改procfs里的內(nèi)核參數(shù)將會(huì)影響甚至破壞宿主機(jī)。還有內(nèi)核syslog也是沒有被隔離的,因此在容器內(nèi)可以看到容器外其他進(jìn)程產(chǎn)生的內(nèi)核syslog。
Namespace的隔離非但是不完善的,甚至可以說是不可能完善的。這是共用內(nèi)核導(dǎo)致的固有缺陷,并且未來(lái)Linux內(nèi)核社區(qū)也不會(huì)對(duì)此做太多的改進(jìn)。
安全策略 – CgroupCgroup用于限制容器對(duì)CPU、內(nèi)存等關(guān)鍵資源的使用,防止某個(gè)容器由于過度使用資源,導(dǎo)致宿主機(jī)或者其他容器無(wú)法正常運(yùn)作。
限制CPUDocker能夠指定一個(gè)容器的CPU權(quán)重,這是一個(gè)相對(duì)權(quán)重,與實(shí)際的處理速度無(wú)關(guān)。事實(shí)上,沒有辦法限制一個(gè)容器只可以獲得1GHZ的CPU。每個(gè)容器默認(rèn)的CPU權(quán)重是1024,簡(jiǎn)單的說,假設(shè)只有兩個(gè)容器,并且這兩個(gè)容器競(jìng)爭(zhēng)CPU資源,那么CPU資源將在這兩個(gè)容器間平均分配。如果其中一個(gè)容器啟動(dòng)時(shí)設(shè)置的CPU權(quán)重是512,那它相對(duì)于另一個(gè)容器只能得到一半的CPU資源,因此這兩個(gè)容器可以得到的CPU資源分別是33.3%和66.6%。但如果另外一個(gè)容器是空閑的,第一個(gè)容器則會(huì)被允許使用100%的CPU。簡(jiǎn)而言之,CPU資源不是預(yù)先硬性分配好的,而是跟各個(gè)容器在運(yùn)行時(shí)對(duì)CPU資源的需求有關(guān)。
例如,需要為容器設(shè)置CPU權(quán)重為2000,命令如下:
$ docker run --rm -ti -c 2000 ubuntu bash
另一方面,Docker也可以明確限制容器對(duì)CPU資源的使用上限
$ docker run --rm -ti --cpu-period=500000 --cpu-quota=250000 ubuntu /bin/bash
上面的命令表示這個(gè)容器在每個(gè)0.5秒里最多只能運(yùn)行0.25秒。除此之外,Docker還可以把容器的進(jìn)程限定在特定的CPU上運(yùn)行,例如將容器限定在0號(hào)和1號(hào)CPU上運(yùn)行
$ docker run --rm -ti --cpuset-cpus=0,1 ubuntu bash限制內(nèi)存
除了CPU,內(nèi)存也是應(yīng)用不可或缺的一個(gè)資源,因此一般來(lái)說必須限制容器的內(nèi)存使用量。限制命令如下
$ docker run --rm -ti -m 200M ubuntu bash
這個(gè)例子將容器可使用的內(nèi)存限制在200MB。不過事實(shí)并非如此簡(jiǎn)單,在系統(tǒng)發(fā)現(xiàn)內(nèi)存不足時(shí),會(huì)將部分內(nèi)存置換到swap分區(qū)里,因此如果只限制內(nèi)存使用量,可能會(huì)導(dǎo)致swap分區(qū)被用光。通過–memory-swap參數(shù)可以限制容器對(duì)內(nèi)存和swap分區(qū)的使用,如果只是指定-m而不指定–memory-swap,那么總的虛擬內(nèi)存大小(即memory加上swap)是-m參數(shù)的兩倍。
限制塊設(shè)備I/O對(duì)于塊設(shè)備,因?yàn)榇疟P帶寬有限,所以對(duì)于I/O密集的應(yīng)用,CPU會(huì)經(jīng)常處于等待I/O完成的狀態(tài),也就是idle狀態(tài),這會(huì)造成其他應(yīng)用可能也要等待那個(gè)應(yīng)用的I/O完成,從而影響到其他的容器。
Docker目前只能設(shè)置容器的I/O權(quán)重,無(wú)法限制容器的I/O讀寫速率的上限,但這個(gè)功能已經(jīng)在開發(fā)之中了。現(xiàn)階段用戶可以通過寫Cgroup文件來(lái)實(shí)現(xiàn)。
# 創(chuàng)建容器 $ docker run --rm -ti --name container1 ubuntu bash # 查詢?nèi)萜鞯膶懰俾?dd if=/dev/zero of=testfile0 bs=8k mount=5000 oflag=direct
下面通過修改相應(yīng)的Cgroup文件來(lái)限制寫磁盤的速度。
# 查找容器掛載的文件系統(tǒng)“/dev/mapper”的位置 $ mount|grep ContainerID # 查看容器掛載的文件系統(tǒng)中的文件(Path為上條命令取得的返回結(jié)果) # 返回結(jié)果“->”標(biāo)記后會(huì)有一個(gè)新的路徑,我們先稱其為DeviceFilePath $ ls -l Path # 查詢?nèi)萜鲯燧d的設(shè)備號(hào) $ ls DeviceFilePath -l # 返回結(jié)果中“root disk”后面會(huì)有一串用“,”隔開的數(shù)字,假設(shè)是128和256 # 限制容器的寫速度 $ sudo echo "128:256 10240000" >/sys/fs/cgroup/blkio/system.slice/docker-DockerID.scope/blkio.throttle.write_bps_device # 10240000是每秒可寫入的最多的字節(jié)數(shù)。ulimit
ulimit是Linux系統(tǒng)中的一個(gè)指令,可以對(duì)某些類型的資源起到限制作用,包括core dump文件的大小、進(jìn)程數(shù)據(jù)段的大小、可創(chuàng)建文件的大小、打開文件的數(shù)量、進(jìn)程棧的大小、CPU時(shí)間、單個(gè)用戶的最大線程數(shù)、進(jìn)程的最大虛擬內(nèi)存等。
在Docker1.6之前,Docker容器的ulimit設(shè)置,繼承自Docker daemon。但是很多時(shí)候,對(duì)于單個(gè)容器來(lái)說,這樣的ulimit實(shí)在太高了。在Docker1.6之后,可以設(shè)置全局默認(rèn)的ulimit,如設(shè)置CPU時(shí)間
$ sudo docker daemon --default-ulimit cpu=1200
或者在啟動(dòng)容器時(shí),多帶帶對(duì)其ulimit進(jìn)行設(shè)置
$ docker run --rm -ti --ulimit cpu=1200 ubuntu bash
進(jìn)入容器后可以查看
# ulimit -t # 返回結(jié)果:1200容器組網(wǎng)
在接入容器隔離不足的情況下,將受信任的和不受信任的容器組網(wǎng)在不同的網(wǎng)絡(luò)中,可以降低風(fēng)險(xiǎn)。關(guān)于Docker的各種網(wǎng)絡(luò)模型及方案可以參考“Docker網(wǎng)絡(luò)”
容器 + 全虛擬化如果將容器運(yùn)行在全虛擬化環(huán)境中(如在虛擬機(jī)中運(yùn)行容器),這樣就算容器被攻破,虛擬機(jī)還具有保護(hù)作用。目前一些安全需求很高的應(yīng)用場(chǎng)景采用的就是這種方式,如公有云場(chǎng)景。
鏡像簽名Docker可信鏡像及升級(jí)框架(The Update Framework,TUF)是Docker 1.8所提供的一個(gè)新功能,可以校驗(yàn)鏡像的發(fā)布者。當(dāng)發(fā)布者將鏡像push到遠(yuǎn)程倉(cāng)庫(kù)時(shí),Docker會(huì)對(duì)鏡像用私鑰進(jìn)行簽名,之后其他人pull該鏡像的時(shí)候,Docker就會(huì)用發(fā)布者的公鑰來(lái)校驗(yàn)該鏡像是否和發(fā)布者所發(fā)布的鏡像一致,是否被篡改過,是否是最新版。點(diǎn)擊查看更多TUF相關(guān)內(nèi)容。
日志審計(jì)Docker 1.6版本開始支持日志驅(qū)動(dòng),用戶可以將日志直接從容器輸出到如syslogd這樣的日志系統(tǒng)中,通過docker –help可以看到Docker daemon支持log-driver參數(shù),目前支持的類型有none、json-file、syslog、gelf和fluentd,默認(rèn)的日志驅(qū)動(dòng)是json-file。
除了在啟動(dòng)Docker daemon時(shí)可以指定日志驅(qū)動(dòng)以外,也可以對(duì)單個(gè)容器指定驅(qū)動(dòng),如
$ docker run --rm -ti --log-driver="syslog" ubuntu bash
通過docker inspect ContainerID可以看到容器使用了哪種日志驅(qū)動(dòng)。另外,只有json-file支持docker logs命令,docker logs ContainerID。
監(jiān)控在使用容器時(shí),應(yīng)注意監(jiān)控容器的信息,以便及時(shí)補(bǔ)救。這些信息包括運(yùn)行狀態(tài)、容器的資源使用情況等。
查看容器的運(yùn)行狀態(tài),命令:docker ps -a。
容器的資源使用情況主要指容器對(duì)內(nèi)存、網(wǎng)絡(luò)I/O、CPU、磁盤I/O的使用情況等,命令:docker stats ContainerID。
文件系統(tǒng)級(jí)防護(hù)Docker可以設(shè)置容器的根文件系統(tǒng)為只讀模式,只讀模式的好處是即使容器與host使用的是同一個(gè)文件系統(tǒng),也不用擔(dān)心會(huì)影響甚至破環(huán)host的根文件系統(tǒng)。但需要注意的是,必須把容器里remount進(jìn)程的文件系統(tǒng)能力禁掉,否則在容器內(nèi)又可以把文件系統(tǒng)重新掛載為可寫。用戶甚至可以禁止容器掛載任何文件系統(tǒng)。
可讀寫掛載:
$ docker run --rm -ti ubuntu bash # echo "hello" >/home/test.txt # cat /home/test.txt
只讀掛載:
$ docker run --rm -ti --read-only ubuntu bash # echo "hello" >/home/test.txt # 返回結(jié)果:bash:/home/test.txt:Read-only file systemcapability
從2.2版開始,Linux有了capability的概念,它打破了Linux操作系統(tǒng)中超級(jí)用戶/普通用戶的概念,讓普通用戶也可以做只有超級(jí)用戶才能完成的工作。capability可以作用在進(jìn)程上,也可以作用在程序文件上。它與sudo不同,sudo可以配置某個(gè)用戶可以執(zhí)行某個(gè)命令或更改某個(gè)文件,而capability則是讓程序擁有某種能力。
每個(gè)進(jìn)程有三個(gè)和能力有關(guān)的位圖:Inheritable(I)Permitted(P)Effective(E),我們可以通過/proc/
命令:cat /proc/$$/status | grep Cap 結(jié)果: # 能夠被當(dāng)前進(jìn)程執(zhí)行的程序繼承的capability。 CapInh: 0000000000000000 # 進(jìn)程能夠使用的能力,可以包含CapEff中沒有的能力,這些能力是被進(jìn)程自己臨時(shí)放棄的,因此可以把CapEff看作是CapPrm的一個(gè)子集。 CapPrm: ffffffffffffffff # 當(dāng)一個(gè)進(jìn)程要進(jìn)行某個(gè)特權(quán)操作時(shí),操作系統(tǒng)會(huì)檢查CapEff的對(duì)應(yīng)位是否有效,而不再是檢查進(jìn)程的有效UID是否為0。 CapEff: ffffffffffffffff
如需了解更多請(qǐng)查閱Linux手冊(cè)。
Docker啟動(dòng)容器的時(shí)候,會(huì)通過白名單的方式來(lái)設(shè)置傳遞給容器的capability,默認(rèn)情況下,這個(gè)白名單只包含CAP_CHOWN等少數(shù)的能力。用戶可以通過 -–cap-add 和 -–cap-drop 這兩個(gè)參數(shù)來(lái)修改這個(gè)白名單。
$ docker run --rm -ti --cap-drop=chown ubuntu bash # chown 2.2/etc/hosts # 返回結(jié)果:chown:changing ownership of "/etc/hosts": Operation not permitted
發(fā)現(xiàn)禁掉CAP_CHOWN能力后,在容器里就無(wú)法改變?nèi)萜鞯乃姓吡恕H绻唤魟t正常。如下
$ docker run --rm -ti ubuntu bash # chown 2.2/etc/hosts
容器應(yīng)遵循最小權(quán)限原則,盡量不要用–privileged參數(shù),不需要的能力全部去掉,甚至禁掉所有的能力。
$ docker run --rm -ti --cap-drop=all ubuntu bashSELinux
操作系統(tǒng)中訪問控制安全的發(fā)展:早期的操作系統(tǒng)幾乎沒有考慮安全問題,一個(gè)用戶可以訪問任何文件或資源,但很快出現(xiàn)了訪問控制機(jī)制來(lái)增強(qiáng)安全性,其中主要的訪問控制在今天被稱為自主訪問控制(DAC – Discretionary[d?’skr???’n?ri] Access Control)。DAC通常允許授權(quán)用戶(通過其程序如一個(gè)shell)改變客體的訪問控制屬性,這樣就可指定其他用戶是否有權(quán)訪問該客體。大部分DAC機(jī)制是基于用戶身份訪問控制屬性的,通常表現(xiàn)為該訪問控制列表機(jī)制。DAC的主要特性是,單個(gè)用戶(通常指某個(gè)資源的屬主)可以指定其他人是否能訪問該資源。
但是,DAC也有其自身的安全脆弱性,它只約束了用戶、同用戶組內(nèi)的用戶、其他用戶對(duì)文件的可讀、可寫、可執(zhí)行權(quán)限,這對(duì)系統(tǒng)的保護(hù)作用非常有限。為了克服這種脆弱性,出現(xiàn)了強(qiáng)制訪問控制(MAC – Mandatory[‘m?nd?t(?)r?] Access Control)機(jī)制,其基本原理是利用組織的安全策略來(lái)控制對(duì)客體的訪問,且這種訪問不被單個(gè)程序所影響。此項(xiàng)研究最早由軍方資助,目的是保護(hù)機(jī)密政府部門數(shù)據(jù)的機(jī)密性。
SELinux(Security-Enhanced Linux)是美國(guó)國(guó)家安全局(NSA)對(duì)于強(qiáng)制訪問控制的實(shí)現(xiàn),它是Linux歷史上最杰出的安全子系統(tǒng)。在這種訪問控制體系的限制下,進(jìn)程只能訪問那些在它的任務(wù)中所需的文件。對(duì)于目前可用的Linux安全模塊來(lái)說,SELinux功能最全面,而且測(cè)試最充分,它是基于對(duì)MAC 20年的研究基礎(chǔ)上建立的。
SELinux定義了系統(tǒng)中每個(gè)用戶、進(jìn)程、應(yīng)用和文件訪問及轉(zhuǎn)變的權(quán)限,然后使用一個(gè)安全策略來(lái)控制這些實(shí)體(即用戶、進(jìn)程、應(yīng)用和文件)之間的交互,安全策略指定了如何嚴(yán)格或?qū)捤傻倪M(jìn)行檢查。另外,SELinux比較復(fù)雜。
SELinux跟內(nèi)核模塊一樣,也有模塊的概念,需要先根據(jù)規(guī)則文件編譯出二進(jìn)制模塊,然后插入到內(nèi)核中。在使用SELinux前,需要安裝一些包,以Fedora 20為例,需要安裝以下組件:
checkpolicy
libselinux
libsemanage
libsepol
policycoreutils
源碼可以在https://github.com/SELinuxProject/selinux中找到,但建議不要自己來(lái)編譯,太耗費(fèi)時(shí)間,而且編譯了也不見得好用。若自己開發(fā)SELinux策略,還需安裝 selinux-policy-devel。
在Fedora 20中,可以直接用yum安裝SELinux開發(fā)所需的工具
$ sudo yum -y install libselinux.x86_64 libselinux-devel.x86_64 libselinux-python.x86_64 libselinux-utils.x86_64 $ sudo yum -y install selinux-policy.noarch selinux-policy-devel.noarch selinux-policy-targeted.noarch $ sudo yum -y install crossfire-selinux.x86_64 libselinux-devel.i686 checkpolicy.x86_64 policycoreutils.x86_64 $ sudo yum -y install policycoreutils-devel.x86_64 selinux-policy-devel.noarch selinux-policy-targeted.noarch
安裝完成之后就可以學(xué)習(xí)一個(gè)Github上的例子,獲取源碼
$ git clone https://github.com/pcmoore/getpeercon_server.git
查看策略文件
$ cd getpeercon_server $ cat selinux/gpexmple.te
會(huì)發(fā)現(xiàn)返回一坨天文似的東西,想看懂還需要看一本《SELinux by Example》。查看測(cè)試程序的代碼
$ cat src/getpeercon_server.c......
又是返回一坨。上面的代碼中有創(chuàng)建tcp socket及bind tcp端口的動(dòng)作,但是上面的策略文件中沒有bind tcp端口的策略,不能成功的bind tcp端口。要測(cè)試該例子,首先需要?jiǎng)?chuàng)建SELinux模塊
$ sudo make build $ sudo make install
然后關(guān)閉SELinux,再插入新編譯的模塊,重啟SELinux,并打上正確的標(biāo)簽
$ sudo setenforce 0 $ sudo semodule -i selinux/gpexmple.pp $ sudo setenforce 1 $ sudo restorecon /usr/bin/getpeercon_server
之后運(yùn)行g(shù)etpeercon_server
$ getpeercon_server 8080
就像多數(shù)事情一樣不會(huì)一帆風(fēng)順,出錯(cuò)了,查看日志
$ cat /var/log/audit/audit.log......
根據(jù)日志中“success=no exit=-13”了解到getpeercon_server執(zhí)行失敗,SELinux阻止了getpeercon_server綁定端口。解決方法
$ cat /var/log/audit/audit.log | audit2allow -m local
這里的audit2allow是用Python寫的一個(gè)命令,用來(lái)處理日志,把日志中違反策略的動(dòng)作記錄轉(zhuǎn)換成access vector。然后把這條命令復(fù)制輸出到gpexmple.te中,然后編譯插入操作,在運(yùn)行
$ getpeercon_server 8080
啟動(dòng)成功。感覺例子好復(fù)雜。但在Docker中使用SELinux卻非常簡(jiǎn)單。Docker使用SELinux的前提是系統(tǒng)支持SELinux,SELinux功能已經(jīng)打開,并且已插入了Docker的SELinux模塊,目前RHEL 7、Fedora 20都已自帶該模塊。查看系統(tǒng)是否支持Docker的SELinux環(huán)境
$ sudo semodule -l |grep docker
如果有Docker的SELinux模塊(即返回類似docker 1.0.0的信息),說明該系統(tǒng)已經(jīng)支持Docker的SELinux環(huán)境。Docker SELinux模塊已經(jīng)幫我們做了復(fù)雜的SELinux策略,我們只需在Docker daemon啟動(dòng)的時(shí)候加上--selinux-enabled=true選項(xiàng)就可以使用SELinux了。
$ sudo docker daemon --selinux-enabled=true
另外也可以在啟動(dòng)容器時(shí),使用–-security-opt選項(xiàng)對(duì)指定的文件做限制(前提是Docker daemon啟動(dòng)時(shí)加了--selinux-enabled=true)
AppArmorAppArmor也是一種MAC控制機(jī)制,其主要作用是設(shè)置摸個(gè)可執(zhí)行程序的訪問控制權(quán)限,可以限制程序讀/寫某個(gè)目錄/文件,打開/讀/寫網(wǎng)絡(luò)端口等。AppArmor是一個(gè)高效和易于使用的Linux系統(tǒng)安全特性,它對(duì)操作系統(tǒng)和應(yīng)用程序進(jìn)行了從內(nèi)到外的保護(hù),即使是0day漏洞和未知的應(yīng)用程序漏洞所導(dǎo)致的攻擊也可被識(shí)破。AppArmor安全策略可以完全定義個(gè)別應(yīng)用程序所能訪問的系統(tǒng)資源與各自的特權(quán),它包含了大量的默認(rèn)策略,并將先進(jìn)的靜態(tài)分析和基于學(xué)習(xí)的工具結(jié)合了起來(lái),可以在很短的時(shí)間內(nèi),為非常復(fù)雜的應(yīng)用制定AppArmor規(guī)則。配置文件官方文檔。
Docker daemon在啟動(dòng)過程中會(huì)判斷當(dāng)前內(nèi)核是否支持AppArmor,若支持,就創(chuàng)建默認(rèn)的AppArmor配置文件/etc/apparmor.d/docker,并應(yīng)用這個(gè)配置文件。啟動(dòng)容器時(shí),在初始化過程中Docker會(huì)使用相應(yīng)的AppArmor配置作用于容器。也可以使用–security-opt選項(xiàng)來(lái)指定作用于容器的AppArmor配置文件。
制定一個(gè)AppArmor規(guī)則,并應(yīng)用到容器上。先拷貝一個(gè)模板
$ sudo cp /etc/apparmor.d/docker /etc/apparmor.d/container
編輯/etc/apparmor.d/container,將
profile docker-default flags=(attach_disconnected,mediate_deleted){
改為
profile container-default flags=(attach_disconnected,mediate_deleted){
上面修改的主要是配置的名字,該名字在傳給Docker時(shí)要用到,也可以修改配置文件中其他的內(nèi)容(如在配置文件中加入“deny/etc/hosts rwklx,”一行,容器啟動(dòng)后執(zhí)行“cat /etc/hosts”命令時(shí)會(huì)發(fā)現(xiàn)容器沒有權(quán)限讀取/etc/hosts的內(nèi)容了)。使用這個(gè)配置
$ docker run --rm -ti --security-opt apparmor:container-default ubuntu bash
在使用Docker的過程中,最好打開SELinux或AppArmor。目前在支持SELinux的系統(tǒng)上,Docker的SELinux是默認(rèn)關(guān)閉的,需要在啟動(dòng)Docker daemon時(shí)加上--selinux-enabled=true參數(shù)。而在支持AppArmor的系統(tǒng)上,AppArmor的功能默認(rèn)是開啟的。
SeccompSeccomp(secure computing mode)是一種Linux內(nèi)核提供的安全特性,它可以實(shí)現(xiàn)應(yīng)用程序的沙盒機(jī)制,以白名單或黑名單的方式限制進(jìn)程進(jìn)行系統(tǒng)調(diào)用。
Seccomp首次于內(nèi)核2.6.12版合入Linux主線。早期的Seccomp只支持過濾少數(shù)幾個(gè)系統(tǒng)調(diào)用。較新版本的內(nèi)核支持動(dòng)態(tài)Seccomp策略,也就是seccomp-bpf,因?yàn)橹С钟肂PF生成過濾規(guī)則,從而使Seccomp可以限制任意的系統(tǒng)調(diào)用,并且可以限制系統(tǒng)調(diào)用傳入的參數(shù)。
Seccomp的使用
生成BPF形式的過濾規(guī)則;
調(diào)用prctl系統(tǒng)調(diào)用將規(guī)則傳入內(nèi)核。
在Docker容器啟動(dòng)的過程中,會(huì)對(duì)Seccomp設(shè)置一個(gè)默認(rèn)的配置,但目前還不支持命令行參數(shù)做配置。點(diǎn)擊了解更多Seccomp相關(guān)。
grsecuritygrsecurity提供了一個(gè)系統(tǒng)的內(nèi)核patch,使Linux內(nèi)核的安全性大大增強(qiáng),并且它提供了一些工具讓用戶配置、使用這些安全特性。grsecurity可以用來(lái)控制資源訪問權(quán)限。下面是一張關(guān)于grsecurity、SELinux和AppArmor的對(duì)比圖。
在grsecurity官網(wǎng)有更完整的對(duì)比,這里只是一部分。由于grsecurity提供的安全特性是對(duì)整個(gè)系統(tǒng)都有效的,因此用戶不需要對(duì)Docker做專門的配置。不過grsecurity并沒有被Linux內(nèi)核主線接受,因此Redhat和Ubuntu等發(fā)行版都不支持grsecurity。
與Docker安全相關(guān)的項(xiàng)目Notary
Docker對(duì)安全模塊進(jìn)行了重構(gòu),剝離出了名為Notary的獨(dú)立項(xiàng)目。Notary的目標(biāo)是保證server和client之間的交互使用可信任的連接,用于解決互聯(lián)網(wǎng)的內(nèi)容發(fā)布的安全性。該項(xiàng)目并未局限于容器應(yīng)用,在容器場(chǎng)景下可以對(duì)鏡像源認(rèn)證、鏡像完整性等安全需求提供更好的支持。點(diǎn)擊了解更多信息。
docker-bench-security
docker-bench-security提供一個(gè)腳本,它可以檢測(cè)用戶的生產(chǎn)環(huán)境是否符合Docker的安全實(shí)踐。點(diǎn)擊了解更多信息。
上面提到了Docker的安全策略,接下來(lái)將結(jié)合上面的安全策略做一個(gè)加固Docker安全的實(shí)例。
主機(jī)逃逸主機(jī)逃逸實(shí)為虛擬機(jī)逃逸,主要指利用虛擬機(jī)軟件或虛擬機(jī)中運(yùn)行的軟件的漏洞進(jìn)行攻擊,以達(dá)到攻擊或控制虛擬機(jī)宿主操作系統(tǒng)的目的,下文的Shocker攻擊就屬于這類攻擊,在此為了方便理解,暫且簡(jiǎn)單的把Docker容器當(dāng)作虛擬機(jī)對(duì)待。Docker的安全問題主要來(lái)源于容器的隔離性,容器隔離性的不足可能導(dǎo)致容器影響host,或者影響其他容器,Shocker攻擊就是容器影響host的一個(gè)例子。
Shocker攻擊
Github上有個(gè)項(xiàng)目叫Shocker,它描述了怎樣逃逸Docker容器并讀取到host的/etc/shadow文件的內(nèi)容。完整代碼。
下載Shocker源碼
$ git clone https://github.com/gabrtv/shocker.git $ cd shocker
在編譯之前,需要將main函數(shù)中的
if((fd1 = open("/.dockerinit",O_RDONLY))<0)
改為
if((fd1 = open("/etc/hosts",O_RDONLY))<0)
然后構(gòu)建鏡像
$ docker build -t shocker:latest .
接著運(yùn)行Shocker
$ docker run --rm -ti --cap-add=all shocker bash # ./shocker
接下來(lái)容器中的Shocker就會(huì)遍歷host的文件系統(tǒng),并讀取/etc/shadow文件。
Shocker原理
Shocker攻擊的核心是利用了一個(gè)不常見的系統(tǒng)調(diào)用:open_by_handle_at。它和name_to_handle_at一起將系統(tǒng)調(diào)用open分解成了兩步。
handle是由name_to_handle_at系統(tǒng)調(diào)用得來(lái)的,它本身對(duì)用戶是透明的。Shocker攻擊沒有使用name_to_handle_at,它通過暴力手段(brute force)猜測(cè)出指向host根目錄的handle,由此達(dá)到讀取host文件系統(tǒng)中文件的目的。
另外,之所以要將/.dockerinit改為/etc/hosts,是因?yàn)榕f版Docker的/.dockerinit是由主機(jī)bind mount到容器的,但較新版本的Docker已經(jīng)不是這樣了,因此要改用/etc/hosts,這個(gè)也是由主機(jī)bind mount的。對(duì)此,在容器中輸入mount命令就能看到
$ docker run --rm -ti shocker bash # mount
另外,除了/etc/hosts,通過/etc/resolv.conf或/etc/hostname,上面的攻擊也同樣有效。
安全加固 – capability
Shocker攻擊的關(guān)鍵是執(zhí)行了系統(tǒng)調(diào)用open_by_handle_at,這個(gè)系統(tǒng)調(diào)用需要用到dac_read_search這個(gè)capability,如果去掉這個(gè)capability,攻擊自然就不奏效了
$ docker run --rm -ti --cap-add=all --cap-drop=dac_read_search shocker bash # ./shocker
返回一坨···,結(jié)論就是:Operation not permitted!
其實(shí),Docker默認(rèn)提供以下十幾種能力:
Capabilities:[]string{ "CHOWN", "DAC_OVERRIDE", "FSETID", "FOWNER", "MKNOD", "NET_RAW", "SETGID", "SETUID", "SETFCAP", "SETPCAP", "NET_BIND_SERVICE", "SYS_CHROOT", "KILL", "AUDIT_WRITE" }
這其中并不包括dac_read_search,也就是說,只要命令行不設(shè)置任何capability的參數(shù),那上面的攻擊也是不奏效的。從中我們也可以總結(jié)出一點(diǎn),賦予容器的能力越小,相對(duì)越安全,即賦予容器必需的最小能力。所以啟動(dòng)容器時(shí)最好不要使用--privileged,并且將不需要的能力盡量都去掉。
安全加固 – SELinux
要把SELinux和Docker結(jié)合起來(lái),需要內(nèi)核支持SELinux,而且要在系統(tǒng)打開,并且在啟動(dòng)Docker daemon時(shí)加SELinux選項(xiàng)。以Fedora 20為例,要先確保Docker的SELinux模塊已經(jīng)插入到內(nèi)核(發(fā)行版本中已有)。啟動(dòng)Docker daemon
$ sudo docker daemon --selinux-enabled=true
同樣以Shocker為例,運(yùn)行Shocker
$ docker run --rm -ti --cap-add=all shocker bash # ./shocker
返回的結(jié)果很有意思,shocker的代碼在暴力破解的過程中使用了一個(gè)循環(huán),在第一次沒有成功的情況下開始執(zhí)行循環(huán)操作。通過查看audit日志就可以看出這種方式永遠(yuǎn)也不會(huì)成功。因?yàn)槿罩拘畔⒅酗@示Shocker成功的找到了/etc/shadow,但是在讀取內(nèi)容時(shí)被SELinux阻止了。目前SELinux是效果最好的Docker安全加固手段。
安全加固 – AppArmor
《Docker的進(jìn)階與實(shí)戰(zhàn)》一書的作者的建議是在Ubuntu上做AppArmor的測(cè)試,修改上面提到的/etc/apparmor.d/container配置文件,在“profile container-default flags”一項(xiàng)下加入一行“deny /etc/hosts rwklx,”,然后應(yīng)用該規(guī)則,再運(yùn)行Shocker
$ sudo apparmor_parser -r /etc/apparmor.d/container $ docker run --rm -ti --cap-add=all --security-opt apparmor:container-default shocker bash # ./shocker
返回的結(jié)果最終的結(jié)論:open: Permission denied。也就是說攻擊依然不奏效,“deny /etc/hosts rwklx,”阻止了容器內(nèi)的其他程序?qū)?b>/etc/hosts的讀取。
Docker安全遺留問題在Docker的安全問題上Docker社區(qū)做了很多的工作,但Docker依然有不少跟安全相關(guān)的問題尚未解決。
User NamespaceUser Namespace可以將host中的一個(gè)普通用戶映射成容器里的root用戶,不過雖然允許進(jìn)程在容器里執(zhí)行特權(quán)操作,但這些特權(quán)只局限于該容器內(nèi)。這對(duì)容器的安全是一個(gè)非常大的提升,惡意程序通過容器入侵host或者其他容器的風(fēng)險(xiǎn)大大降低,但這并不意味著容器就足夠安全了。另外,由于內(nèi)核層面隔離性不足,如果用戶在容器的一個(gè)特權(quán)操作會(huì)影響到容器外,那么這個(gè)特權(quán)操作一般也是不被User Namespace所允許的。
非root運(yùn)行Docker daemon目前Docker daemon需要由root用戶啟動(dòng),而Docker daemon創(chuàng)建的容器以及容器里運(yùn)行的應(yīng)用實(shí)際上也是以root用戶運(yùn)行的。實(shí)現(xiàn)由普通用戶啟動(dòng)Docker daemon和運(yùn)行容器,有益于Docker的安全。但這個(gè)問題很難解決,因?yàn)閯?chuàng)建容器需要執(zhí)行很多特權(quán),包括掛載文件系統(tǒng)、配置網(wǎng)絡(luò)等。目前社區(qū)還沒有一個(gè)好的方案。
Docker熱升級(jí)Docker管理容器的方式是中心式管理,容器由主機(jī)上的Docker daemon進(jìn)程統(tǒng)一管理。中心式管理方式對(duì)于第三方的任務(wù)編排工具并不友好,因?yàn)槭裁垂δ芏夹枰鶧ocker關(guān)聯(lián)起來(lái)。更大的問題是,如果Docker daemon掛掉了,重啟daemon后,它無(wú)法接管容器,容器也不能運(yùn)行了。在實(shí)際應(yīng)用中,很多業(yè)務(wù)都是不能中斷的,而停止容器就往往相當(dāng)于停止業(yè)務(wù),但如果因?yàn)榘踩┒吹脑蛐枰?jí)Docker,用于就將處于兩難的境地。點(diǎn)擊了解該問題的進(jìn)展。
磁盤限額默認(rèn)情況下,Docker鏡像、容器rootfs、數(shù)據(jù)卷都存放在/var/lib/docker目錄里,也就是說跟host是共享同一個(gè)文件系統(tǒng)的。如果不對(duì)Docker容器做磁盤大小的配額限制,容器就可能用完磁盤的可用空間,導(dǎo)致host和其他容器無(wú)法正常工作。
但是目前Docker幾乎沒有提供任何接口用于限制容器的磁盤大小。但graphdriver為devicemapper時(shí),容器會(huì)被默認(rèn)分配一個(gè)100GB的空間。這個(gè)空間大小可以在啟動(dòng)Docker daemon時(shí)設(shè)置為另一個(gè)默認(rèn)值,但無(wú)法對(duì)每個(gè)容器多帶帶設(shè)置一個(gè)不同的值。
$ sudo docker daemon --storage-opt dm.basesize=5G
除此之外,用戶只能通過其他手段自行做一些隔離措施,例如為/var/lib/docker多帶帶分配一個(gè)磁盤或分區(qū)。
網(wǎng)絡(luò)I/O目前同一臺(tái)機(jī)器上的Docker容器會(huì)共享寬帶,但這可能出現(xiàn)某個(gè)容器占用大部分帶寬資源,從而影響其他需要網(wǎng)絡(luò)資源的容器正常工作的情況。Docker需要一個(gè)好的網(wǎng)絡(luò)方案,除了要解決容器跨主機(jī)通信的問題,還要解決網(wǎng)絡(luò)I/O限制的問題。
小結(jié)Docker的隔離性還遠(yuǎn)達(dá)不到虛擬機(jī)的水平,應(yīng)該避免把Docker容器當(dāng)成虛擬機(jī)來(lái)使用,除非在虛擬機(jī)里部署容器,否則一般來(lái)說Docker容器應(yīng)該只跑可信應(yīng)用。另外,用戶應(yīng)該評(píng)估自己所需的安全等級(jí),針對(duì)自身的需求采取相應(yīng)的安全策略。而這些策略說白了就是對(duì)系統(tǒng)做的加減法,通過各種限制來(lái)達(dá)到安全性,這也是最主流、有效的加固方法。此外,還應(yīng)該保證內(nèi)核的安全和穩(wěn)定,并啟用監(jiān)控、容錯(cuò)等系統(tǒng)。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/26626.html
摘要:為容器設(shè)計(jì)的商業(yè)安全套件,功能包括安全審計(jì)容器鏡像驗(yàn)證運(yùn)行時(shí)保護(hù)自動(dòng)策略學(xué)習(xí)或入侵預(yù)防。基于一種稱為的新內(nèi)核技術(shù),允許根據(jù)容器身份定義并執(zhí)行網(wǎng)絡(luò)層和層安全策略。自動(dòng)發(fā)現(xiàn)應(yīng)用程序容器和服務(wù)的行為,以及與其他類似方式檢測(cè)安全升級(jí)和其他威脅。 數(shù)人云:隨著越來(lái)越多的企業(yè)將生產(chǎn)工作負(fù)載遷移到容器當(dāng)中,關(guān)于Docker的安全性,成了普遍關(guān)注的問題。 這是一個(gè)簡(jiǎn)單卻又沒有答案的問題,不要試圖用二進(jìn)...
摘要:本系列教程翻譯自,系列共有九篇,本文譯自第五篇。因此,本系列教程關(guān)鍵的第五章用來(lái)討論可能面臨的安全問題以及它們是如何影響到整體的安全性的。一些必要的安全措施包括使用非特權(quán)用戶運(yùn)行容器。本圖中列舉了幾個(gè)用于維護(hù)和授權(quán)的安全性。 本系列教程翻譯自 Flux7 Docker Tutorial Series,系列共有九篇,本文譯自第五篇 Part 5: Docker Security。該系列所...
摘要:安全基準(zhǔn)測(cè)試工具互聯(lián)網(wǎng)安全中心為容器安全提供了指導(dǎo)方針,這一方針已被和類似的安全基準(zhǔn)工具所采用。該容器安全工具可以利用機(jī)器學(xué)習(xí)提供自適應(yīng)威脅保護(hù)這是一個(gè)可以掃描容器鏡像的托管安全解決方案,它甚至可以允許企業(yè)在它們的環(huán)境內(nèi)執(zhí)行安全策略。 在Docker容器技術(shù)興起的初期,對(duì)于許多企業(yè)而言,容器安全問題一直是他們?cè)谏a(chǎn)環(huán)境中采用Docker的一大障礙。然而,在過去的一年中,許多開源項(xiàng)目、初...
摘要:你首先需要了解的安全工具之一就是。是另一個(gè)可為進(jìn)行安全漏洞掃描的工具。和相似,是的安全審核工具。和其他容器安全工具不同,使用創(chuàng)建自定義配置文件非常容易。月日,北京海航萬(wàn)豪酒店,容器技術(shù)大會(huì)即將舉行。 網(wǎng)絡(luò)安全問題的重要性大概毋庸置疑,最近無(wú)數(shù)關(guān)于惡意軟件和安全漏洞的消息已充分證明了這一點(diǎn)。 假如你要管理一個(gè)Docker環(huán)境,并希望幫助自己的公司或用戶在下一個(gè)大漏洞來(lái)臨時(shí)避免遇到麻煩,那...
閱讀 2034·2021-11-11 16:54
閱讀 2111·2019-08-30 15:55
閱讀 3611·2019-08-30 15:54
閱讀 391·2019-08-30 15:44
閱讀 2228·2019-08-30 10:58
閱讀 424·2019-08-26 10:30
閱讀 3048·2019-08-23 14:46
閱讀 3191·2019-08-23 13:46