Docker容器的root用戶


Docker容器的root用戶

Docker 是 Linux 平台上容器的管理引擎,其提供的容器服務一方面可以很好地分配物理資源,不論是資源還是權限都能夠達到隔離的效果;另一方面,Docker 的設計把更多的目光投向了「應用」本身,簡化了應用從開發、測試、發布等迭代發展的生命周期。

Docker 帶着「重新定義應用」的豪言,沖擊着大家對軟件的理解,在雲計算領域更是如此。然而,新技術的誕生往往需要接受行業千錘百煉似的考驗,安全無疑是業界最關心的因素之一。傳統的硬件虛擬化等技術發展了數十年,逐漸步入成熟期,成為如今雲計算技術的中堅技術,其高隔離性自然是保障安全的首要功臣;對於應用而言,安全問題尤為嚴峻,系統業務核心幾乎全部通過應用來實現,應用的安全一旦失守,后果不堪設想。

正視安全,Docker 無法回避。在眾多安全性考量中,有一點經常被 Docker 實踐者提起,那就是 Docker 容器的 root 安全性。由於截止到目前的 docker 1.8.3 版本,Docker 依然沒有完成對 Linux User Namespace 的支持,因此對於 Docker 容器而言,容器內部的 root 和宿主機上的 root 屬於同一個用戶,兩者的 UID 均為 0。容器中的超級用戶,是否會影響其他容器,乃至宿主機,自然成了大家最關心的安全問題。

Docker 容器 root 和宿主機 root

意識到 Docker 容器內的 root 用戶屬於超級用戶之外,更多的憂慮逐漸表露,比如「使用 root 用戶運行 Docker 容器內部的應用,是否安全?」,比如「容器內的 root 是否可以操縱宿主機資源?」……

如果 Docker 容器內的 root 用戶和宿主機的 root 用戶完全一致,那么 Docker 容器可以認為在權限方面擁有宿主機上 root 相應的權限,此時的 Docker 容器擁有超級管理員權限,原則上 Docker 容器本身完全有能力操縱宿主機的一切。然而,結果真是如此嗎?

答案自然是否定的,否則的話,Docker 的安全簡直不堪一擊。雖然 Docker 容器內的 root 用戶直接是宿主機的 root 用戶,但是 Docker 可以保證兩者在權限方面,擁有巨大的差異。此時,這種差異的存在完全是借助於Linux 內核的 Capabilities 機制。換言之,正是 Capabilities 在保障 Docker 容器的安全性。

Capabilities 在 Docker 容器的管理過程中使用非常方便。如果不需要授予 Docker 容器足夠的系統權限,也就是足夠的 Capabilities,只需在運行 Docker 容器時不使用 --privileged 參數,如:

docker run -it --priviledged=false ubuntu:14.04 /bin/bash
或者
docker run -it ubuntu:14.04 /bin/bash
如果需要授予 Docker 容器足夠的管理權限,則直接將 --privileged 參數設為 true,如:

docker run -it --privileged=true ubuntu:14.04 /bin/bash
另外,在 docker run 命令中,添加 --cap-add 以及 --cap-drop 參數也完全可以更靈活的添加以及移除 Linux Capabilities。

Linux Capabilities

既然 Docker 采用了 Linux Capabilities 機制,那么何為 Linux Capabilities,我們來一探究竟。

大家一定知道,在傳統的 Unix 系統中,為了實現權限的檢查,操作系統上運行的進程可以分為兩種:特權進程(priviledged processes) 和非特權進程(unpriviledged processes) 。其中,前者的有效用戶 ID 為 0,也就是大家常說的超級用戶或者 root 用戶,而后者的有效用戶 ID 為非 0,也常被稱為普通用戶。特權進程在運行時們可以繞過所有的內核權限檢查,而非特權進程則必須完全接受這些檢查。

雖然如此,然而實際情況要比以上的描述復雜一些。實際情況下,Linux 會將傳統超級用戶的特權划分為多個單位,也就是我們關心的 Capabilties。Capabilities 會有很多種,而且對於 root 用戶而言,完全可以單獨啟用或者關閉,因此同為 root 用戶,權限卻因 Capabilities 的不同而存在差異。

Linux Capabilities 機制將超級用戶的權限划分非常之細,所有的 Capabilities 列表有接近 40 項之多。我們可以通過幾個具體的 Capability 來看看他們各自管理的權限范圍。

CAP_SYS_ADMIN:CAP_SYS_ADMIN 實現一系列的系統管理權限,比如實現磁盤配額的 quotactl,實現文件系統掛載的 mount 權限;比如在 fork 子進程時,通過 clone 和 unshare 系統調用,使用 CLONE_* 的 flag 參數來為子進程創建新的 namespaces;比如實現各種特權塊設備以及文件系統的 ioctl 操作等。

CAP_NET_ADMIN:CAP_NET_ADMIN 實現一系列的網絡管理權限,比如網絡設備的配置,IP 防火牆,IP 偽裝以及統計等功能;比如路由表的修改,TOS 的配置,混雜模式的配置等。

CAP_SETUID:CAP_SETUID 有能力對進程 UID 做出任何管控。

CAP_SYS_MODULE:CAP_SYS_MODULE 幫助 root 用戶加載或者卸載相應的 Linux 內核模塊。

CAP_SYS_NICE:CAP_SYS_NICE 有能力對任意進程修改其 NICE 值,同時支持對任何進程設置調度策略與優先級,還有在進程的 CPU 親和性以及 I/O 調度方面有相應的配置權限。
……

Linux 總共有接近 40 項的 Capabilities,然而初步接觸以上 5 項 Capabilties,我們可以發現:Linux 對於超級用戶的特權也進行了種類繁多的划分,有划分就意味着有區別,有區別就意味着並不是所有的 root 用戶都擁有相同的權限.

那么 Linux Capabilties 與 Docker 容器的關系究竟如何?

Docker 容器與 Linux Capabilities

大家已經清楚 Docker 容器中的 root 用戶與宿主機的 root 用戶同屬一個 uid,均為 0;並且大家也可以發現不同的 Capabilities 可以區分 root 用戶的權限,那么 Docker 容器中的 root 用戶的 Capabilities 情況到底是什么樣,這種現狀會存在安全隱患嗎?

上文已經涉及了 docker run 命令創建容器時 privileged 參數的用法,實際上 Docker 容器的Capabilties 情況也會因用戶設置而異。

Docker 容器的非特權模式

默認情況下,docker run 命令的 privileged 參數值為 false。因此,毫無疑問,Docker 容器內部的 root 用戶將受到嚴格的權限限制,很多有系統相關的操作權限都將被剝奪,只具備超級用戶的一些基本權限。

研究 Docker 的源碼,我們可以發現:在 Linux 接近40項的 Capabilities 中,Docker為了確保容器的安全,僅僅支持了其中的14項基本的 Capabilities ,現在,我們不妨來看看這些 Capabilities 到底有哪些,它們分別是: CAP_CHOWN 、 CAP_DAC_OVERRIDE 、 CAP_FSETID 、 CAP_MKNOD 、 FOWNER 、 NET_RAW 、 SETGID 、 SETUID 、 SETFCAP 、 SETPCAP 、 NET_BIND_SERVICE 、 SYS_CHROOT 、 KILL 和 AUDIT_WRITE 。

我們可以發現:在這 14 項中幾乎沒有一項涉及到系統管理權限,比如 Docker 容器的 root 用戶不具備 CAP_SYS_ADMIN,磁盤限額操作、mount 操作、創建進程新命名空間等均無法實現;比如由於沒有 CAP_NET_ADMIN,網絡方面的配置管理也將受到管制。因此,默認情況下,Docker 容器中的 root 用戶並沒有以往我們想象得那么能力超群,Docker 依然對其存在限制,這樣設計的出發點之一自然是安全。

Docker 容器的特權模式

了解完 Docker 容器的非特權模式,大家也許會覺得 Docker 容器的 root 權限被削減得有點難以置信,確保安全,卻剝奪了過多系統權限 。其實,Docker 作為一個管理容器的工具,並未在容器 root 方面「一刀切」,Docker 容器的非特權模式就可以滿足 root 用戶的權限最大化。

一旦將 docker run 命令的 privileged 參數設為 true,那么 Docker 容器的 root 權限將得到大幅度的提升。此時,Docker容器的 root 用戶將獲得 37 項 Capabilities 能力。由於 Docker 容器與宿主機處於共享同一個內核操作系統的狀態,因此,Docker 容器將完全擁有內核的管理權限 。安全隱患,瞬間浮出水面。

兩種模式的比較

Docker 容器的實踐,不能缺少場景。談到以上兩種模式的比較,場景更是如此。安全與權限,孰輕孰重,魚與熊掌,是否可以兼得?

雲計算領域,公有雲一向被認為是一項技術甚至一種產品的試金石。Docker 這項技術更是需要在公有雲領域展現自己的價值。安全這個話題,在公有雲中尤為敏感,這一點相信已經毋庸贅言。那么,在安全至上的情況下,開啟 Docker 容器的特權模式將完全不現實,如此一來,Docker 容器的權限將不得不做出妥協。Docker 技術在公有雲領域,不論服務於 PaaS,還是目前興起的 CaaS,權限的削減是否會影響這兩種雲計算模式?

Docker 容器 root 用戶權限的缺失,主要還是集中於系統管理方面。那我們就從系統管理權限 ,來分析 PaaS 和 CaaS 對 Docker 需求的區別。

PaaS:Docker 作為 PaaS 技術的底層技術,完全有能力支撐起用戶應用的運行。對於提供運行時環境而言,應用將無需過多的與系統管理相關聯;同時,從應用本身出發,高移植性應該是重要的設計目標之一,過多的與系統耦合同樣將會帶來運維成本。

CaaS:CaaS 與 PaaS 最大的區別,在於 CaaS 帶來的服務模式要更廣。CaaS 中容器的范疇很廣,完全可以不限於用戶應用的運行。CaaS 中 Docker 的自足點將不再是專注於應用本身,而是將計算資源的管理也圈入其內,比如提供類似於傳統虛擬機的計算單元。由於為了安全,無法提供與虛擬機 root 用戶相同的權限,因此 Docker 容器的權限問題將無情暴露,CaaS 的服務質量必將受到影響。

Docker與Linux User Namespace
Docker 容器的 root 安全嗎?相信大家已經有了一定的認識。這個問題,其實並不是僅僅涉及安全這一個話題,而是一種安全與權限的博弈 。既然如此,難道就只能取舍,魚和熊掌,不可兼得嗎?

答案是否定的。Linux User Namespace 的支持將大大緩解這種情況。(目前,docker 1.8.3 仍未支持 User Namespace。)一旦完成對 Linux User Namespace 的支持,Docker 容器內部的 root 用戶在宿主機看來 UID 將不再是 0,換言之,在宿主機上僅僅是一個普通用戶,而在 Docker 容器內部,原則上可以應用更多的 Capabilities,實現權限的提升。Docker 與 Linux User Namespace 的淵源,后續我們再深入。

總結

Docker 容器中 root 用戶的安全性一直備受關注。安全性問題,並未想象中的那么壞,當然也絕對不是無懈可擊,更多的是一種安全與權限的博弈 。

Docker 大潮一波高過一波,我們沒有理由懷疑 Docker 的未來。Docker 對 Linux User Namespace 的支持也是萬眾矚目。User Namespace 不僅能夠從 Capabilities 的角度提升 Docker 容器 root 的容器內系統權限,而且也有能力對 ulimit 的支持更加完善。理論上,User Namespace 對於安全與隔離是存在巨大的共享,但是這也僅僅是一種極大的緩解。緣何如此,根在共享內核。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM