Docker安全部署的17條建議

dockerone發表於2015-02-03

本文作者從Docker映象、網路名稱空間、日誌和稽核、守護程式特權、SELinux、二進位制SUID/GUID、裝置控制組、服務和應用、 Linux核心、使用者名稱空間、libseccomp等方面給出了自己的建議,可以一讀。

當前持續增長的雲端計算市場對虛擬化技術有著強烈的需求。遺憾的是,大多數的虛擬化解決方案不夠靈活,無法滿足研發需求,且使用全虛擬化解決方案的潛在開銷變成了制約基礎設施擴充套件性的負擔。

Docker讓開發和運維人員能無縫地部署容器,用於執行業務所需的應用與服務,從而減少這類開銷。然而,因為Docker與宿主系統使用同一核心,配置不當的容器將造成重大安全隱患。

以下列表每一條在相關容器環境內對提高其安全性提出了建議。需要注意的是,這些方案僅適用於部署在Linux主機上的Docker容器,並使用最新的Docker版本(1.4.0,commit 4595d4f,日期 11/12/14)。

以下部分內容參考了Jérôme Petazzoni[1]和Daniel J Walsh[2]的文章。本文旨在對他們的建議進行補充,並說明如何在Docker具體實現。

注:大多數建議的命令列選項可以在Dockerfile中以類似的方式儲存和使用,實現自動化映象構建。(譯者注:原文17項建議以表格形式呈現,由於編輯器原因,這裡將改為列表形式表述)

1. Docker映象

Docker 1.3開始支援使用數字簽名[3]來驗證官方倉庫映象的來源和完整性。該功能仍在開發中,因此Docker只對(譯者注:沒有數字簽名的)映象發出警告資訊但不會阻止其實際執行。此外,這點對非官方映象不適用。

一般情況下,我們要確保只從受信任的庫中獲取映象,並且不要使用--insecure-registry=[]引數。

2. 網路名稱空間[4]

預設情況下,Docker守護程式暴露出來用於控制容器的REST API只能在本地通過Unix Domain Socket進行訪問。

在一個TCP埠上執行Docker(比如,啟動Docker守護程式時使用-H選項強制繫結地址)將允許任何可以訪問該埠的人獲取容器的訪問許可權,甚至在本地使用者屬於Docker組的某些情況下有可能獲得宿主的root許可權。[5]

在允許通過TCP訪問守護程式時,確保通訊使用SSL加密[6]和許可權控制能有效地防止未授權使用者與其進行互動。

可在Docker的標準網路橋接介面docker0上啟用核心防火牆iptables規則,用於加強這些控制。

例如,可以使用以下iptables過濾器[7]限制Docker容器的源IP地址範圍與外界通訊。iptables -t filter -A FORWARD -s <source_ip_range> -j REJECT –reject-with icmp-admin-prohibited

3. 日誌和稽核

收集並歸檔與Docker相關的安全日誌來達到稽核和監控的目的。可以在宿主[8]上使用以下命令在容器外部訪問日誌檔案:

docker run -v /dev/log:/dev/log <container_name> /bin/sh

使用Docker內建命令:

docker logs ... (-f to follow log output)

日誌檔案也可以匯出成一個壓縮包實現持久儲存:

docker export ...

4. SELinux 或 AppArmor

通過訪問控制的安全策略,可以配置Linux核心安全模組,如安全增強型Linux(SELinux)和AppArmor,從而實現強制性的訪問控制(MAC)用以將程式約束在一套有限的系統資源或許可權中。

如果先前已經安裝並配置過SELinux,那麼可以在容器使用setenforce 1來啟用它。Docker守護程式的SELinux功能預設是禁用的,需要使用--selinux-enabled來啟用。

容器的標籤限制可使用新增的—-security-opt載入SELinux或者AppArmor的策略進行配置,該功能在Docker版本1.3[9]引入。

例如:

docker run --security-opt=secdriver:name:value -i -t centos bash

5. 守護程式特權

不要使用--privileged命令列選項。否則將允許容器訪問宿主上的所有裝置,另外,為容器提供特定的LSM(例如SELinux或AppArmor)配置,將給予它與執行在宿主上的程式同等訪問許可權。

避免使用--privileged有助於減少攻擊面和可能的宿主威脅。但是,這並不意味著執行守護程式時不需要root許可權,在最新版本中這仍然是必須的。

啟動守護程式和容器的許可權只能賦予受信任的使用者。

可通過使用-u選項弱化容器內訪問許可權。例如:

docker run -u <username> -it <container_name> /bin/bash

Docker組的任何使用者部分可能最終從容器中的主機上獲得根源。

6. cgroups[10]

為了防止通過耗盡系統資源引發拒絕服務(DoS)攻擊,可使用特定的命令列引數被來啟用一些資源限制。

CPU使用:

docker run -it --rm --cpuset=0,1 -c 2 ...

記憶體使用:

docker run -it --rm -m 128m ...

儲存使用:

docker -d --storage-opt dm.basesize=5G

磁碟I/O:
目前Docker不支援。通過systemd暴露的BlockIO*特性可以在支援的作業系統中用來控制磁碟使用配額。

7. 二進位制SUID/GUID

SUID和GUID程式在受攻擊導致任意程式碼執行(如緩衝區溢位)時將非常危險,因為它們將執行在程式檔案所有者或組的上下文中。

如果可能的話,使用特定的命令列引數減少賦予容器的能力,阻止SUID和SGID生效。

docker run -it --rm --cap-drop SETUID --cap-drop SETGID ...

還有種做法,可以考慮在掛載檔案系統時使用nosuid屬性來移除掉SUID能力。

最後一種做法是,刪除系統中不需要的SUID和GUID程式。這類程式可在Linux系統中執行以下命令而找到:

find / -perm -4000 -exec ls -l {} \; 2>/dev/null
find / -perm -2000 -exec ls -l {} \; 2>/dev/null

然後,可以使用類似於下面的[11]命令將移除SUID和GUID檔案許可權:

sudo chmod u-s filename   sudo chmod -R g-s directory

8. 裝置控制組(/dev/*)

如果需要,使用內建的--device選項(-v引數不要與–privileged一起使用)。此功能在1.2版本[12]引入。

例如(使用音效卡):

docker run --device=/dev/snd:/dev/snd …

9. 服務和應用

如果Docker容器有可能被入侵,為了減少橫向運動的可能,應考慮隔離敏感服務(如在宿主或虛擬機器上執行SSH服務)。

此外,不要在容器內使用root許可權執行不受信任的應用。

10. 掛載點

使用原生容器庫(如libcontainer)時,Docker會自動處理這項。

但是,使用LXC容器庫時,敏感的掛載點最好以只讀許可權手動掛載,包括:

/sys
/proc/sys
/proc/sysrq-trigger
/proc/irq
/proc/bus

掛載許可權應在之後移除,以防止重新掛載。

11. Linux核心

使用系統提供的更新工具(如apt-get、yum等)確保核心是最新的。過時的核心相比已公開的漏洞危險性更大。

使用GRSEC或PAX來強化核心,例如針對記憶體破壞漏洞提供更高的安全性。

12. 使用者名稱空間

Docker不支援使用者名稱空間,但它是目前正在開發[13]的功能。現在,LXC驅動支援UID對映,但原生的libcontainer庫不支援。

該功能允許Docker守護程式以非特權使用者身份執行在宿主上,但在容器內看起來像是以root執行。

13. libseccomp(和seccomp-bpf 擴充套件)

libseccomp庫允許基於白名單方法來限制Linux核心的系統呼叫程式的使用。最好禁用受攻擊容器中對於系統操作不是很重要的系統呼叫程式,以防止其被濫用或誤用。

此功能目前正在開發中(LXC驅動中存在,但是現在預設的libcontainer中沒有)。使用LXC驅動程式[14]來重啟Docker程式:

docker -d -e lxc

如何生成seccomp配置的說明都在GitHub倉庫的“contrib”[15]資料夾。之後可用下面的命令來建立一個以LXC為基礎的Docker容器:

docker run --lxc-conf="lxc.seccomp=$file" <rest of arguments>

14. 能力[7]

儘可能降低Linux能力。Docker預設的能力包括:chowndac_overridefownerkill、setgid、setuid、setpcap、net_bind_service、net_raw、sys_chroot、mknod、setfcap、和audit_write`。

在命令列啟動容器時,可以通過--cap-add=[]--cap-drop=[]進行控制。

例如:

docker run --cap-drop setuid --cap-drop setgid -ti <container_name> /bin/sh

此功能在Docker 1.2版本引入[16]。

15. 多租戶環境

由於Docker容器核心的共享性質,無法在多租戶環境中安全地實現責任分離。建議將容器執行在沒有其它目的,且不用於敏感操作的宿主上。可以考慮將所有服務遷移到Docker控制的容器城。

可能的話,設定守護程式使用--icc=false,並根據需要在docker run時指定-link,或通過—-export=port暴露容器的一個埠,而不需要在宿主上釋出。

將相互信任的容器的組對映到不同機器上[17]。

16. 完全虛擬化

使用一個完全虛擬化解決方案來容納Docker,如KVM。如果容器內的核心漏洞被發現,這將防止其從容器擴大到宿主上。

如同Docker-in-Docker工具[18]所示,Docker映象可以巢狀來提供該KVM虛擬層。

17. 安全稽核

定期對你的宿主系統和容器進行安全核查,以找出可能導致系統被入侵的錯誤配置或漏洞。

參考文獻:

[1] Docker, Linux Containers (LXC), and security (August, 2014). Jérôme Petazzoni. [presentation slides]
[2] Docker and SELinux (July, 2014). Daniel Walsh [video]
[3] Docker 1.3: Signed Images, Process Injection, Security Options, Mac shared directories (October, 2014). Scott Johnston
[4] Exploring LXC Networking (November, 2013). Milos Gajdos.
PaaS under the hood, episode 1: kernel namespaces (November, 2012). Jérôme Petazzoni.
Exploring networking in Linux containers (January, 2014). Milos Gajdos. [presentation slides]
[5] How to grant rights to users to use Docker in Fedora (October 2014). Daniel Walsh
[6] Running Docker with https. [Docker documentation]
[7] security suggestions when running malicious code, Google Groups (August, 2013). Jérôme Petazzoni
[8] Monitoring Images and Containers. [Red Hat documentation]
[9] Docker 1.3: Signed Images, Process Injection, Security Options, Mac shared directories (October, 2014). Scott Johnston
[10] Resource management in Docker (September, 2014). Marek Goldmann.
Gathering LXC and Docker Containers Metrics (October, 2013). Jérôme Petazzoni.
[11] Removing SUID and SGID flags off binaries (August, 2008). Eric Thern.
[12] Announcing Docker 1.2.0 (August, 2014). Victor Vieux.
[13] Having non-root privileges on the host and root inside the container #2918 (November, 2013). [GitHub issue]
Support for user namespaces #4572 (March 2014). [GitHub issue]
Proposal: Support for user namespaces #7906 (September, 2014). [GitHub issue]
Issue 8447: syscall, os/exec: Support for User Namespaces (July, 2014) [Google Code issue]
[14] Docker 0.9: Introducing Execution Drivers and libcontainer (March, 2014). Solomon Hykes
[15] A simple helper script to help people build seccomp profiles for Docker/LXC (November 2013). Martijn van Oosterhout.
https://github.com/docker/dock … ample
[16] Announcing Docker 1.2.0 (August, 2014). Victor Vieux.
[17] Docker Container Breakout Proof-of-Concept Exploit (June, 2014). James Turnbull
[18] docker2docker GitHub repository. Jérôme Petazzoni.

相關文章