容器化應用程式已成為現代軟體架構的根本,Docker 作為主流容器平台,其安全管理也日益重要。本文從 Dockerfile 的基礎結構開始,逐步解析容器構建的每個環節,並探討容器修補的最佳實務,如何利用雲端技術實作不停機更新。同時,也介紹了 LXC/LXD、Rkt 和 Kubernetes 等 Docker 替代方案,讓讀者能根據不同需求選擇合適的技術。此外,本文深入分析了 DirtyCow 等許可權漏洞的原理和攻擊手法,並闡述 Linux 名稱空間、SECComp、AppArmor 等核心安全機制在容器安全中的重要性,提供全面的容器安全管理策略。
深入解析容器技術與Docker實務應用
容器技術的發展已經徹底改變了軟體開發與佈署的方式,其中Docker作為最流行的容器化平台,在現代軟體架構中扮演著舉足輕重的角色。本篇文章將探討Dockerfile的結構、容器修補的最佳實踐,以及Docker的替代方案。
Dockerfile結構解析
Dockerfile是用於定義Docker映像檔構建過程的指令碼檔案,其內部包含了一系列指令,用於指導Docker如何構建映像檔。以下是一個典型的Dockerfile範例:
FROM ubuntu:14.04
MAINTAINER Thibault NORMAND <[email protected]>
EXPOSE 22
# 安裝易受攻擊的bash版本
RUN apt-get update
RUN apt-get install -y build-essential wget
RUN wget https://ftp.gnu.org/gnu/bash/bash-4.3.tar.gz && \
tar zxvf bash-4.3.tar.gz && \
cd bash-4.3 && \
./configure && \
make && \
make install
CMD ["echo", "finished", "building", "Docker-image"]
內容解密:
- FROM指令:指定基礎映像檔為
ubuntu:14.04,這裡的14.04代表Ubuntu的版本號。 - MAINTAINER指令:標明映像檔的維護者資訊,有助於追蹤和管理映像檔。
- EXPOSE指令:宣告容器需要開放的埠,這裡是開放22埠,通常用於SSH連線。
- RUN指令:在映像檔構建過程中執行命令,這裡用於安裝必要的套件和編譯安裝bash。
- 首先更新套件列表。
- 然後安裝
build-essential和wget。 - 下載並編譯安裝特定版本的bash。
- CMD指令:定義容器啟動時預設執行的命令,這裡輸出"finished building Docker-image"。
容器修補的最佳實踐
在生產環境中,保持系統更新至最新狀態是至關重要的。自動化的修補流程能夠確保系統的高用性。傳統的虛擬化環境中,修補程式的安裝通常是自動的,但可能會受到服務重啟的影響。使用Docker和容器化技術,可以透過雲端技術快速生成新的容器例項,並透過負載平衡和自動擴充套件系統進行管理,從而實作無縫替換。
圖表說明:容器化環境下的修補流程
圖表翻譯: 此圖示展示了在容器化環境中修補漏洞的流程。首先發現漏洞並生成修補程式,然後利用修補後的程式碼構建新的容器映像檔。接著佈署新的容器,並透過負載平衡器將流量切換至新容器,最後將舊容器下線。
Docker的替代方案
雖然Docker是目前最流行的容器化平台,但仍有多種替代方案可供選擇。例如:
- LXC/LXD:LXC(Linux Containers)是一種透過Linux核心實作容器化的技術,而LXD則是根據LXC的容器管理守護程式。
- Rocket (Rkt):Rkt是CoreOS發起的一個容器執行時專案,旨在遵循容器化的相關標準。
- Kubernetes:Kubernetes是一個強大的容器協調工具,能夠管理來自不同容器執行時的容器,包括Docker、LXC/LXD和Rkt。
這些替代方案提供了不同的功能和優勢,使得企業能夠根據自身需求選擇最合適的技術堆疊。
2.2.6 容器管理
Docker 容器的建立與維護方式與根據 Hypervisor 的虛擬機器不同,如第 2.1.3 節所述。除了主機作業系統外,整個環境在每次更新或容器內部變更時都會被建立和重建。Docker 守護程式自動化了建立和重建的過程,從而實作了安全修補程式的自動化維護和保養。這種自動化顯著減少了更新和維護應用程式所需的操作次數。
容器技術根據不同的使用場景,但虛擬化技術仍然是一個重要的因素。應用層的虛擬化是一種方法,除了允許軟體控制的負載平衡 [RKNA14] 之外,還可以實作更快、更有效率的應用程式佈署。軟體定義的負載平衡使得平衡本地和分散式資源成為可能。
2.2.7 Docker-Hub
Docker-Hub 是 Docker 提供的一個服務,用於管理和管理 Docker 容器的映像檔。可存取的預定義映像檔倉函式庫是建立正確組態系統的重要資產,同時也使得最新軟體可以從一個來源輕鬆取得。Docker-Hub 倉函式庫包含大量應用程式和函式庫,可以直接佈署到任何執行的 Docker 環境中。
流行的應用程式包括網頁伺服器 Nginx、資料函式庫應用程式 MySQL 和 Ubuntu,這些將在第 4 章中進一步使用。除了提供即時執行的映像檔外,還直接由 Docker 與應用程式開發人員合作提供進一步組態的檔案和描述,建立官方映像檔。從安全形度來看,這降低了錯誤組態的可能性,從而降低了安全漏洞的可能性。保持執行中的系統和容器更新仍然是一項需要管理員互動的任務。除了官方的 Docker-Hub 映像檔外,該中心還包括一個報告服務,用於分析映像檔並發現安全漏洞。
第 3 章:安全性
本章節作為第 4 章實驗的理論基礎。本章節涵蓋了保護虛擬化環境的一般安全功能和措施,以及本論文中使用的特定概念。第 3.1 節涵蓋了與虛擬化技術相關的各種安全原則,第 3.2 和 3.3 節則涵蓋了與第 4 章中使用的漏洞直接相關的主題。除了虛擬化安全性之外,還強調了與第 4 章中描述的實驗中顯示的漏洞直接相關的元素。還涵蓋了每個漏洞利用背後的原理,以及如何利用漏洞來建立可利用的前提。
3.1 虛擬化安全性
虛擬化環境中的安全性高度依賴於系統型別、虛擬化型別和適用於該上下文的一組規則。在第 2.1 章中簡要分類別和描述了一些流行的根據 Hypervisor 的虛擬化方法,而應用層容器虛擬化可以在第 2.2 章中進一步探討。
第 4 章中描述的實驗環境是兩種不同虛擬化方法的基礎:根據 Hypervisor 的虛擬化和容器化。根據雲端的環境使用由 Amazon Web Services 控制檯提供的網頁服務建立虛擬例項,簡化了與虛擬機器相關的管理。首先,終端使用者獨立於 Hypervisor 和硬體;這與透過 VMware vCenter 控制檯建立虛擬例項相關,但與產生虛擬例項的單元的互動程度往往相當不同。更具體地說,這種任意程度與硬體相關。硬體故障和維護對於根據雲端的虛擬例項而言並不是相關的術語;它在更大程度上與根據 Hypervisor 的系統相關。
3.1.1 虛擬伺服器
根據雲端和根據 Hypervisor 的系統都有一個共同點,即虛擬伺服器。這些例項使用不同的工具產生,但包含在第 4 章實驗中測試的應用程式和二進位制檔案。Debian 是一個常用的 Linux 伺服器作業系統,官方 Debian 檔案包含了一個保護該作業系統的安全。 1 由於基礎、核心和結構相似,Debian 的最佳實踐也適用於 Ubuntu,即本報告後面實驗中使用的作業系統 [見第 4 章]。Red Hat 是最大的企業版 Linux 版本之一,也有一個全面的作業系統安全。 2 以下是從兩個來源中選取的一些重點和措施的描述:
檔案系統結構
- 建立一個允許根據應用程式、用途和許可權對資料進行適當分割的檔案系統結構。
極簡主義
- 只安裝必要的套件和應用程式,未使用的軟體往往由於過時的軟體更新和忽視而成為漏洞來源。同時,更少的套件和應用程式減少了日常操作,並簡化了系統升級過程。
更新
- 總是安裝最新的安全修補程式,以減少系統被破壞的可能性。大多數攻擊和漏洞利用都是根據已知和常見的漏洞,以及錯誤組態的系統 [Pro17],這與第 5 點相關。
使用者和許可權
- 建立系統使用者和許可權等級制度,使管理員能夠限制對檔案系統某些部分的存取。同時,這有助於在發生違規時遏制系統。透過將應用程式和資料與使用者關聯,並限制特定授權使用者的讀取、寫入和執行許可權,有助於遏制和限制潛在安全違規的影響。
Root
- 禁止 Root 登入需要攻擊者找到有效的使用者名稱進行暴力破解,同時攻擊者在成功登入嘗試後必須穿越另一個安全層級,才能完全控制系統。
3.1 虛擬化安全強化與最佳實踐
在現代雲端運算環境中,虛擬化技術的安全性至關重要。適當的虛擬化安全管理能夠有效預防潛在漏洞並提升系統整體安全性。
3.1.1 虛擬化安全基礎
虛擬化環境的安全需要多層次的防護措施,主要包括:
日誌記錄與分析
透過日誌分析,系統管理員能夠識別錯誤組態和潛在的攻擊行為,從而採取相應的安全措施。安全殼層(SSH)
使用安全通訊協定能夠確保使用者資訊的安全處理,並對潛在的竊聽或中間人攻擊進行資料加密。同樣地,透過SSH協定使用安全檔案傳輸協定(sFTP)能夠保障檔案傳輸的安全性。IPTables與安全群組
透過管理輸入和輸出的通訊通道,可以減少系統的暴露攻擊面,限制可能的攻擊途徑。對於非公開系統,可以隱藏其存在,要求攻擊者必須先破壞網路才能進一步攻擊系統。
3.1.2 虛擬機器監控與最佳實踐
確保虛擬機器的適當組態是安全管理的重要步驟。Hypervisor負責管理和控制虛擬機器對硬體資源的存取,因此對Hypervisor的成功攻擊可能會危及所有在其上佈署的虛擬例項。
Hypervisor特性
- Hypervisor作業系統是一種專門設計來管理虛擬機器的作業系統,具有高度的可用性和穩定性要求。
- 這種專門的作業系統由於其穩定性需求,通常較難快速套用零日安全性修補程式。
- 為了降低風險,通常會限制對Hypervisor的存取和公開連線端點。
3.1.3 資源限制
在現代威脅環境中,拒絕服務(DoS)和破壞性攻擊非常常見。透過限制虛擬例項的資源分配,可以確保單一例項的安全問題不會影響其他例項或整個實體主機。
資源管理
- Hypervisor能夠限制每個虛擬例項的CPU、RAM和頻寬資源。
- 容器技術在應用層進行資源限制,每個容器例項可以有獨立的管理計畫。
3.1.4 Docker安全特性與最佳實踐
Docker容器技術透過以下方式增強安全性:
- 減少攻擊面
- 簡化沙盒機制
- 提供硬體/核心與使用者之間的API介面
Docker實作了Linux核心的安全特性,並新增可組態的安全層來管理容器的資源存取。透過Dockerfile組態容器的最小必要元件,實作「預設安全」的原則。
SECComp安全特性
SECComp是Linux核心提供的安全功能,可用於限制容器內行程對系統資源的存取。透過限制系統呼叫(Syscall),能夠強化作業系統的安全性。
AppArmor安全工具
AppArmor是另一種Linux核心安全功能,用於在執行階段限制應用程式的能力。它能夠分析應用程式在執行階段所需的資源,並產生可調整的安全規範。
SELinux安全機制
SELinux是Linux核心提供的重要安全功能,能夠實作細緻的安全控制。相關細節可參考Cliffe Z. Schreuders等人的研究論文。
3.2 檔案系統與許可權管理
檔案系統中的許可權層級對於Linux系統的內容和資源管理至關重要。Unix和Linux系統以檔案結構為基礎組織所有系統元件,並透過許可權進行管理。攻擊者通常會嘗試透過許可權提升漏洞來取得更高的存取許可權。
檔案系統結構
- Unix檔案系統以階層式或單一目錄結構組織檔案和目錄。
- 透過存取角色和許可權管理檔案系統的存取控制。
- 可以針對特設定檔案或目錄設定精細的存取許可權。
程式碼範例:檔案許可權設定
# 設定檔案許可權範例
chmod 644 /path/to/file
chown user:group /path/to/file
內容解密:
chmod 644用於設定檔案許可權,6表示檔案擁有者具有讀寫許可權,4表示群組和其他使用者僅具有讀取許可權。chown指令用於變更檔案的擁有者和群組,有效實作存取控制。- 正確設定檔案許可權對於防止未授權存取至關重要。
Plantuml檔案系統許可權架構
圖表翻譯:
此圖示呈現了檔案系統的許可權架構,包括目錄結構、檔案許可權設定以及存取控制列表(ACL)的組態關係。圖中展示了檔案系統如何透過不同的許可權層級來管理存取控制。
3.2 檔案系統與許可權管理
容器技術的核心在於如何有效地隔離應用程式及其依賴項,而檔案系統的管理是實作這一點的關鍵。Linux 名稱空間(Namespaces)提供了一種抽象化的資源管理方式,讓容器內的程式認為自己擁有獨立的資源例項。
3.2.1 名稱空間(Namespaces)
名稱空間是容器管理檔案系統的核心機制。透過名稱空間,容器可以掛載檔案系統的特定部分,使其在容器內可存取。這種掛載的部分通常被視為容器的根目錄,構成了一個檔案系統的子樹 [RKNA14]。名稱空間在管理容器和存取許可權方面扮演著至關重要的角色,是建立應用層虛擬環境(jail)的關鍵技術。
名稱空間將全域系統資源包裝在一個抽象層中,使名稱空間內的程式看起來像是擁有該資源的獨立例項。對全域資源的修改對於同屬該名稱空間的其他程式是可見的,但對於其他名稱空間的程式則是不可見的。名稱空間的一個重要應用就是實作容器化技術 [Lin17]。
Linux 預設的名稱空間包括 Cgroup(見第 3.1.4 節)、網路、PID(程式 ID)和使用者等。這些名稱空間使得作業系統能夠區分不同的資源例項,避免例項間的互相干擾。
內容解密:
- 名稱空間提供了一種資源隔離機制,使得容器內的程式看起來像是執行在獨立的環境中。
- 這種隔離機制對於容器安全至關重要,因為它限制了容器對全域資源的存取。
- Linux 預設的名稱空間為容器的隔離提供了基礎。
3.2.2 隔離(Isolation)
傳統的虛擬應用伺服器通常使用根據 Hypervisor 的虛擬化技術來託管單一應用程式及其依賴項。這種做法提高了可擴充套件性,並在某些組態中引入了私有網路來保護後端應用程式 [DO14]。元件隔離是增強安全性的重要手段,它透過將應用程式分散到不同的伺服器上,並根據使用場景限制存取許可權,從而減少了應用程式的攻擊面,使攻擊者更難以入侵其他伺服器。
在傳統的物理伺服器環境中,作業系統直接與硬體互動,這種方式雖然效能較佳,但資源利用率不高。大多數系統和應用程式大部分時間處於閒置狀態,因此硬體虛擬化技術應運而生,以提高硬體資源的利用率。多個虛擬伺服器分享同一硬體資源,從而減少了每 CPU 小時的閒置和低使用率伺服器數量。
當從物理伺服器轉向根據 Hypervisor 的虛擬伺服器時,資源分享成為一個重要的考量因素。網路、磁碟、CPU 等硬體資源在虛擬化伺服器之間分享,因此虛擬化資源之間的隔離對於確保虛擬化的安全性至關重要。
容器分享核心的組態意味著應用程式之間的隔離程度較低,這對系統型別有一定的限制。應用程式之間的資料交換通常需要經過加密,並在受控環境中進行管理 [Sta02]。分享核心的一個主要安全問題是許可權提升。如果攻擊者在容器內獲得 root 許可權,那麼也就意味著對主機系統具有相同的許可權 [PFH03]。因此,正確管理容器以及透過不同的物理或虛擬機器進行隔離,是確保容器化安全的關鍵。
內容解密:
- 元件隔離是提高安全性的關鍵技術,透過將應用程式分散到不同的伺服器上來限制攻擊面。
- 虛擬化技術提高了硬體資源的利用率,但也引入了資源分享的安全問題。
- 容器分享核心組態下的許可權提升是主要的安全風險之一。
3.2.3 Dirtycow 漏洞
Dirtycow(CVE-2016-5195)是一個典型的許可權相關漏洞,利用該漏洞可以透過多種方法獲得更高的存取許可權 [The16]。該漏洞利用了核心在執行系統呼叫時對記憶體內容的處理,特別是在相同的記憶體位址空間中進行操作。
攻擊者首先以唯讀許可權開啟一個只有 root 使用者可以存取的檔案,然後嘗試向該檔案寫入內容。通常,這種操作會被許可權層級機制拒絕,但攻擊者透過將檔案載入到記憶體中的唯讀區段,並使用特定的引數設定,成功繞過了這一限制。
接下來,攻擊者透過記憶體處理系統呼叫 madvise,並帶有 MADV_DONTNEED 旗標,放棄並重新載入這段記憶體。這使得攻擊者能夠修改本來不可存取的記憶體內容,從而提升許可權。
程式碼範例:
#include <stdio.h>
#include <sys/mman.h>
#include <fcntl.h>
int main() {
// 開啟檔案
int fd = open("/path/to/file", O_RDONLY);
if (fd == -1) {
perror("open");
return 1;
}
// 將檔案對映到記憶體
void *addr = mmap(NULL, sizeof(int), PROT_READ, MAP_SHARED, fd, 0);
if (addr == MAP_FAILED) {
perror("mmap");
return 1;
}
// 使用 madvise 修改記憶體
if (madvise(addr, sizeof(int), MADV_DONTNEED) != 0) {
perror("madvise");
return 1;
}
// 這裡可以嘗試寫入內容到原本唯讀的記憶體區域
// 注意:實際操作中這裡需要精心設計以避免當機或被檢測
return 0;
}
內容解密:
- Dirtycow 漏洞利用了 Linux 核心在處理記憶體時的競爭條件,允許攻擊者提升許可權。
- 攻擊者透過開啟唯讀檔案並使用
madvise系統呼叫來修改記憶體內容,從而繞過了許可權檢查。 - 該漏洞展示了核心分享組態下的容器安全風險,強調了正確組態和隔離的重要性。
此圖示顯示了 Dirtycow 漏洞的攻擊流程:
@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle
title Docker容器技術安全與最佳實務
package "Docker 架構" {
actor "開發者" as dev
package "Docker Engine" {
component [Docker Daemon] as daemon
component [Docker CLI] as cli
component [REST API] as api
}
package "容器運行時" {
component [containerd] as containerd
component [runc] as runc
}
package "儲存" {
database [Images] as images
database [Volumes] as volumes
database [Networks] as networks
}
cloud "Registry" as registry
}
dev --> cli : 命令操作
cli --> api : API 呼叫
api --> daemon : 處理請求
daemon --> containerd : 容器管理
containerd --> runc : 執行容器
daemon --> images : 映像檔管理
daemon --> registry : 拉取/推送
daemon --> volumes : 資料持久化
daemon --> networks : 網路配置
@enduml
圖表翻譯:
此圖示呈現了 Dirtycow 漏洞的攻擊步驟。首先,攻擊者開啟一個唯讀檔案並將其對映到記憶體中。接著,使用 madvise 系統呼叫來修改記憶體內容,最終實作許可權提升。