Docker Engine 安全
在審視 Docker 安全性時,需要考慮四個主要方面:
- 核心的內在安全性及其對名稱空間和 cgroups 的支援
- Docker 守護程序本身的攻擊面
- 容器配置檔案的漏洞,無論是預設配置還是使用者自定義配置。
- 核心的“加固”安全特性及其與容器的互動方式。
核心名稱空間
Docker 容器與 LXC 容器非常相似,它們具有類似的安全特性。當你使用 docker run
啟動一個容器時,Docker 會在後臺為該容器建立一組名稱空間和控制組。
名稱空間提供了第一種也是最直接的隔離形式。在一個容器內執行的程序無法看到,更無法影響另一個容器或宿主系統中執行的程序。
每個容器還會獲得自己的網路堆疊,這意味著一個容器無法獲得對另一個容器的套接字或介面的特權訪問。當然,如果宿主系統進行了相應設定,容器可以透過它們各自的網路介面進行互動——就像它們與外部主機互動一樣。當你為容器指定公共埠或使用 連結 時,IP 流量是允許在容器之間流動的。它們可以互相 ping 通,傳送/接收 UDP 資料包,並建立 TCP 連線,但如有必要,這些都可以被限制。從網路架構的角度來看,給定 Docker 主機上的所有容器都位於橋接介面上。這意味著它們就像透過一個公共乙太網交換機連線的物理機器一樣;不多也不少。
提供核心名稱空間和私有網路的程式碼成熟度如何?核心名稱空間是在核心版本 2.6.15 和 2.6.26 之間引入的。這意味著自 2008 年 7 月(2.6.26 版本釋出日期)以來,名稱空間的程式碼已經在大量生產系統上得到了實踐和檢驗。而且還有更多:名稱空間程式碼的設計和靈感甚至更早。名稱空間實際上是重新實現 OpenVZ 特性的一項努力,以便它們可以合併到主流核心中。而 OpenVZ 最初於 2005 年釋出,因此設計和實現都相當成熟。
控制組
控制組是 Linux 容器的另一個關鍵元件。它們實現了資源核算和限制。它們提供了許多有用的指標,但它們也幫助確保每個容器獲得其公平的記憶體、CPU、磁碟 I/O 份額;更重要的是,確保單個容器不能透過耗盡這些資源中的一種來使系統宕機。
因此,雖然它們在防止一個容器訪問或影響另一個容器的資料和程序方面不起作用,但它們對於抵禦某些拒絕服務攻擊至關重要。它們在多租戶平臺(如公共和私有 PaaS)上尤其重要,以保證即使某些應用程式開始行為不端,也能有一致的正常執行時間(和效能)。
控制組也已經存在了一段時間:程式碼始於 2006 年,並最初合併到核心 2.6.24 中。
Docker 守護程序攻擊面
使用 Docker 執行容器(和應用程式)意味著需要執行 Docker 守護程序。除非你選擇使用無根模式 (Rootless mode),否則該守護程序需要 root
許可權,因此你應該瞭解一些重要的細節。
首先,只應允許受信任的使用者控制你的 Docker 守護程序。這是 Docker 一些強大功能的直接後果。具體來說,Docker 允許你在 Docker 主機和客戶機容器之間共享一個目錄;並且它允許你這樣做而不限制容器的訪問許可權。這意味著你可以啟動一個容器,其中 /host
目錄是主機上的 /
目錄;並且該容器可以無限制地更改你的主機檔案系統。這類似於虛擬化系統允許檔案系統資源共享的方式。沒有什麼能阻止你與虛擬機器共享你的根檔案系統(甚至是你的根塊裝置)。
這具有強烈的安全影響:例如,如果你透過 API 從 Web 伺服器來編排 Docker 以配置容器,你應該比平時更加小心引數檢查,以確保惡意使用者無法傳遞精心設計的引數,導致 Docker 建立任意容器。
因此,REST API 端點(Docker CLI 用於與 Docker 守護程序通訊)在 Docker 0.5.2 中發生了變化,現在使用 Unix 套接字而不是繫結在 127.0.0.1 上的 TCP 套接字(後者如果你碰巧在本地機器上直接執行 Docker,而不是在 VM 中,則容易受到跨站請求偽造攻擊)。然後,你可以使用傳統的 Unix 許可權檢查來限制對控制套接字的訪問。
如果你明確決定這樣做,你也可以透過 HTTP 暴露 REST API。但是,如果你這樣做,請注意上述的安全隱患。請注意,即使你有防火牆來限制來自網路中其他主機的對 REST API 端點的訪問,該端點仍然可以從容器內部訪問,並且這很容易導致許可權提升。因此,必須使用 HTTPS 和證書來保護 API 端點。不允許在沒有 TLS 的情況下透過 HTTP 暴露守護程序 API,這種配置會導致守護程序在啟動時提前失敗,請參閱未認證的 TCP 連線。還建議確保它只能從受信任的網路或 VPN 訪問。
如果你更喜歡使用 SSH 而不是 TLS,也可以使用 DOCKER_HOST=ssh://USER@HOST
或 ssh -L /path/to/docker.sock:/var/run/docker.sock
。
守護程序也可能受到其他輸入的攻擊,例如透過 docker load
從磁碟載入映象,或透過 docker pull
從網路載入映象。從 Docker 1.3.2 開始,映象現在在 Linux/Unix 平臺上的一個 chrooted 子程序中提取,這是朝著許可權分離更廣泛努力的第一步。從 Docker 1.10.0 開始,所有映象都透過其內容的加密校驗和來儲存和訪問,從而限制了攻擊者與現有映象發生衝突的可能性。
最後,如果你在伺服器上執行 Docker,建議只在該伺服器上執行 Docker,並將所有其他服務移到由 Docker 控制的容器內。當然,保留你喜歡的管理工具(可能至少有一個 SSH 伺服器)以及現有的監控/監督程序,如 NRPE 和 collectd,是沒問題的。
Linux 核心能力
預設情況下,Docker 以一組受限的能力 (capabilities) 啟動容器。這是什麼意思?
能力將二元的“root/非 root”二分法轉變為一個細粒度的訪問控制系統。只需要在 1024 以下埠上繫結的程序(如 Web 伺服器)不需要以 root 身份執行:它們可以只被授予 net_bind_service
能力。還有許多其他能力,幾乎涵蓋了通常需要 root 許可權的所有特定領域。這對容器安全意義重大。
典型的伺服器以 root
身份執行多個程序,包括 SSH 守護程序、cron
守護程序、日誌記錄守護程序、核心模組、網路配置工具等。容器則不同,因為幾乎所有這些任務都由容器周圍的基礎設施處理:
- SSH 訪問通常由執行在 Docker 主機上的單個伺服器管理
cron
,在必要時,應作為使用者程序執行,專用於需要其排程服務的應用,而不是作為平臺級的設施- 日誌管理也通常交給 Docker,或第三方服務如 Loggly 或 Splunk
- 硬體管理是無關緊要的,這意味著你永遠不需要在容器內執行
udevd
或等效的守護程序 - 網路管理在容器外部進行,儘可能地強制關注點分離,這意味著容器永遠不需要執行
ifconfig
、route
或 ip 命令(當然,除非容器被專門設計為路由器或防火牆)。
這意味著在大多數情況下,容器根本不需要“真正的”root 許可權*。因此,容器可以以減少的能力集執行;這意味著容器內的“root”擁有的許可權遠少於真正的“root”。例如,可以:
- 拒絕所有“mount”操作
- 拒絕訪問原始套接字(以防止資料包欺騙)
- 拒絕訪問某些檔案系統操作,如建立新裝置節點、更改檔案所有者或修改屬性(包括不可變標誌)
- 拒絕模組載入
這意味著即使入侵者成功在容器內提升到 root 許可權,也很難造成嚴重損害或升級到宿主機。
這不會影響常規的 Web 應用,但會大大減少惡意使用者的攻擊途徑。預設情況下,Docker 會移除除所需能力之外的所有能力,採用白名單而非黑名單的方法。你可以在 Linux 手冊頁中看到可用能力的完整列表。
執行 Docker 容器的一個主要風險是,預設賦予容器的能力和掛載集可能提供不完整的隔離,無論是獨立地還是與核心漏洞結合使用時。
Docker 支援新增和移除能力,允許使用非預設的配置檔案。這可以透過移除能力使 Docker 更安全,或透過新增能力使其更不安全。使用者的最佳實踐是移除所有能力,除了其程序明確需要的能力。
Docker 內容信任簽名驗證
Docker Engine 可以配置為只執行經過簽名的映象。Docker 內容信任簽名驗證功能直接內置於 dockerd
二進位制檔案中。
這在 Dockerd 配置檔案中進行配置。
要啟用此功能,可以在 daemon.json
中配置信任固定 (trustpinning),這樣只有使用使用者指定的根金鑰簽名的倉庫才能被拉取和執行。
此功能為管理員提供了比以前使用 CLI 執行和強制映象簽名驗證時更多的洞察力。
有關配置 Docker 內容信任簽名驗證的更多資訊,請訪問Docker 中的內容信任。
其他核心安全特性
能力只是現代 Linux 核心提供的眾多安全特性之一。還可以利用現有的、眾所周知的系統,如 TOMOYO、AppArmor、SELinux、GRSEC 等與 Docker 一起使用。
雖然 Docker 目前只啟用了能力,但它並不干擾其他系統。這意味著有很多不同的方法可以加固 Docker 主機。以下是一些例子:
- 你可以執行一個帶有 GRSEC 和 PAX 的核心。這會在編譯時和執行時增加許多安全檢查;它還透過地址隨機化等技術挫敗了許多漏洞利用。它不需要 Docker 特定的配置,因為這些安全特性是系統範圍的,與容器無關。
- 如果你的發行版附帶了 Docker 容器的安全模型模板,你可以直接使用它們。例如,我們提供了一個與 AppArmor 配合使用的模板,而 Red Hat 則為 Docker 提供了 SELinux 策略。這些模板提供了一個額外的安全網(儘管它與能力有很大重疊)。
- 你可以使用你喜歡的訪問控制機制定義自己的策略。
就像你可以使用第三方工具來增強 Docker 容器(包括特殊的網路拓撲或共享檔案系統)一樣,也存在一些工具可以在無需修改 Docker 本身的情況下加固 Docker 容器。
從 Docker 1.10 開始,docker 守護程序直接支援使用者名稱空間。此功能允許將容器中的 root 使用者對映到容器外的非 uid-0 使用者,這有助於減輕容器逃逸的風險。此功能可用但預設未啟用。
有關此功能的更多資訊,請參考命令列參考中的 daemon 命令。關於在 Docker 中實現使用者名稱空間的更多資訊,可以在這篇部落格文章中找到。
結論
預設情況下,Docker 容器是相當安全的;特別是如果你在容器內以非特權使用者身份執行程序。
你可以透過啟用 AppArmor、SELinux、GRSEC 或其他適當的加固系統來增加一層額外的安全保護。
如果你有任何讓 Docker 更安全的想法,我們歡迎在 Docker 社群論壇上提出功能請求、拉取請求或評論。