在實際佈署中,我建議採用以下網路安全策略:

  1. 預設拒絕所有流量:從零信任模型出發,只允許明確需要的通訊
  2. 按名稱空間隔離:使用名稱空間級別的網路政策,建立邏輯隔離區域
  3. 精細化控制:對關鍵服務實施更精細的政策,根據具體的 Pod 標籤
  4. 定期稽核:定期檢查和測試網路政策,確保它們仍然有效
  5. 監控異常流量:實施流量監控,檢測可能的異常通訊模式

清理環境

完成測試後,別忘了清理環境:

$ kind delete cluster --name cnnp

網路安全是容器化應用的基礎防線。透過正確設定網路政策,你可以顯著提高 Kubernetes 環境的安全性,防止未授權的存取和潛在的橫向移動攻擊。在設計系統時,應始終考慮預設的網路行為,並主動實施必要的保護措施。

網路政策雖然強大,但只是 Kubernetes 安全的一個方面。完整的安全策略還應包括映像掃描、執行時保護、身份和存取管理等多個層面。在未來的文章中,玄貓將探討這些主題,幫助你構建更安全的容器環境。

服務網格:解決Kubernetes網路安全挑戰

在前面討論完具體的網路設定後,現在讓我們轉向一個不同但相關的主題:服務網格(Service Mesh)。這項相對較新的技術能夠幫助我們解決先前提到的一些不太安全的預設設定,包括工作負載身份識別和傳輸層加密。

服務網格的核心概念

服務網格本質上是Kubernetes的補充技術,在許多場景中能發揮重要作用。簡單來說,服務網格是一組位於應用程式前方的使用者空間代理(proxy),以及一個用於設定這些代理的管理程式。

這種架構分為兩個主要部分:

  • 資料平面(Data Plane):由攔截服務間呼叫的代理組成
  • 控制平面(Control Plane):負責協調代理行為並提供管理API

服務網格的代理會攔截服務之間的呼叫,並對這些呼叫執行特定操作,例如阻止特定的通訊路徑或收集呼叫指標。而控制平面則負責協調所有代理的行為,並為管理員提供統一的API介面。

服務網格的市場現況與採用情形

目前市場上存在多種服務網格實作,同時也有一些準標準用於互操作性,例如CNCF的Service Mesh Interface專案,以及根據Envoy的通用資料平面API工作組(UDPA-WG)。

雖然服務網格技術仍處於早期階段,但我們已經看到一定程度的採用,特別是出於安全考量。根據The New Stack(TNS)2020年的服務網格調查:

約三分之一的受訪組織在生產環境的Kubernetes中使用服務網格控制微服務間的通訊流量。另有34%的組織在測試環境中使用服務網格技術,或正在進行試點或積極評估解決方案。

未來,根據服務網格可能出現許多令人興奮的應用領域和精巧的防禦機制,例如多叢集Kubernetes的身份聯合和在Istio中使用OPA(Open Policy Agent)。然而,許多終端使用者尚未準備好全面採用,或者正在觀望,等待雲端和平台提供商將服務網格的資料平面整合到底層基礎設施中。另一種可能性是資料平面在作業系統層級實作,例如使用eBPF技術。

Linkerd實戰案例:實作mTLS加密

Linkerd是一個由Buoyant建立的CNCF畢業專案。它能自動為網格內Pod之間的大多數根據HTTP的通訊啟用相互傳輸層安全性(mTLS)。讓我們實際操作看。

安裝Linkerd

首先,在測試叢集中安裝Linkerd。以下範例使用kind,並假設你已經設定好了Kubernetes叢集並設定了Linkerd CLI:

# 檢查安裝前提條件
$ linkerd check --pre
kubernetes-api
...
Status check results are √

# 安裝Linkerd
$ linkerd install | kubectl apply -f -
namespace/linkerd created
clusterrole.rbac.authorization.k8s.io/linkerd-linkerd-identity created
...
deployment.apps/linkerd-grafana created

# 驗證安裝
$ linkerd check
kubernetes-api
...
Status check results are √

在這段程式碼中,我們首先執行linkerd check --pre來確認環境是否滿足Linkerd安裝的前提條件。確認無誤後,使用linkerd install | kubectl apply -f -指令將Linkerd安裝到Kubernetes叢集中。這個指令會產生所有必要的Kubernetes資源定義,並透過管道傳送給kubectl apply來建立這些資源。最後,我們再次執行linkerd check來驗證安裝是否成功。這種安裝流程反映了現代雲端原生工具的標準安裝模式。

安裝完成後,你可以使用linkerd dashboard &檢視Linkerd儀錶板,它會顯示流量統計等資訊。

實作mTLS加密

一旦我們在相應的名稱空間中啟用了服務網格,即使從叢集內部,也應該無法直接使用像curl這樣的工具透過HTTP查詢來存取服務。讓我們看這是如何實作的。

在這個例子中,我們重用之前「Pod間流量」中的設定,但你可以使用任何在叢集中暴露HTTP服務的工作負載。

首先,我們需要啟用服務網格(meshify):

# 為npdemo名稱空間中的佈署啟用網格
$ kubectl get -n npdemo deploy -o yaml | \
  linkerd inject - | kubectl apply -f -

# 為ambassador名稱空間中的佈署啟用網格
$ kubectl get -n ambassador deploy -o yaml | \
  linkerd inject - | kubectl apply -f -

這段程式碼展示瞭如何將現有的Kubernetes佈署納入Linkerd服務網格。我們先使用kubectl get -n npdemo deploy -o yaml取得npdemo名稱空間中所有佈署的YAML定義,然後透過管道將其傳遞給linkerd inject,這會在YAML中注入Linkerd sidecar容器的設定。最後再透過管道傳給kubectl apply -f -來應用修改後的設定。對ambassador名稱空間重複相同的步驟。這種非侵入式的注入方式是服務網格的典型特性,允許在不修改應用程式碼的情況下增加網路安全功能。

現在我們可以使用tshark來驗證mTLS設定:

# 佈署啟用了除錯sidecar的範例應用
$ curl -sL https://run.linkerd.io/emojivoto.yml | \
  linkerd inject --enable-debug-sidecar - | \
  kubectl apply -f -
namespace "emojivoto" injected
...
deployment.apps/web created

# 連線到除錯容器
$ kubectl -n emojivoto exec -it \
  $(kubectl -n emojivoto get po -o name | grep voting) \
  -c linkerd-debug -- /bin/bash

# 在除錯容器內使用tshark檢查網路封包
root@voting-57bc56-s4l:/# tshark -i any \
  -d tcp.port==8080,ssl | \
  grep -v 127.0.0.1
Running as user "root" and group "root." This could be dangerous.
Capturing on 'any'
1 0.000000000 192.168.49.192 → 192.168.49.231 TCP 76 417044191 [SYN] Seq=0...
2 0.000023419 192.168.49.231 → 192.168.49.192 TCP 76 419141704 [SYN, ACK]...
3 0.000041904 192.168.49.192 → 192.168.49.231 TCP 68 417044191 [ACK] Seq=1...
4 0.000356637 192.168.49.192 → 192.168.49.231 HTTP 189 GET /ready HTTP/1.1
5 0.000397207 192.168.49.231 → 192.168.49.192 TCP 68 419141704 [ACK] Seq=1...
6 0.000483689 192.168.49.231 → 192.168.49.192 HTTP 149 HTTP/1.1 200 OK
...

這段操作展示瞭如何驗證Linkerd的mTLS功能。首先我們佈署了一個名為emojivoto的範例應用,並啟用了除錯sidecar。接著,我們進入除錯容器,使用tshark工具來捕捉網路流量。

tshark命令的關鍵部分:

  • -i any:監聽所有網路介面
  • -d tcp.port==8080,ssl:將在8080連線埠上的TCP流量解析為SSL/TLS
  • grep -v 127.0.0.1:過濾掉本地流量(因為本地流量總是未加密的)

從輸出結果可以看到,服務之間的通訊使用了TLS加密(由tshark解析為SSL協定),這證明mTLS功能正常運作。這種「零設定」的加密是服務網格的主要優勢之一,無需修改應用程式碼即可獲得傳輸層安全性。

太棒了!我們實作了免費的傳輸層加密。這就是mTLS案例研究的全部內容。

如果你想了解更多關於如何使用服務網格來保護東西向通訊的訊息,可以參考相關的進階閱讀資料。

雖然服務網格確實可以幫助解決網路相關的安全挑戰,但你也應該意識到它的弱點。例如,對於根據Envoy的系統,如果你以UID 1337執行容器,它可以繞過Istio/Envoy sidecar;或者,預設情況下,Envoy管理儀錶板可以從容器內部存取,因為它們分享網路。想要更深入瞭解這個話題,可以查閱Istio安全評估報告。

eBPF:Linux核心的強大擴充套件

在服務網格探險之後,讓我們將注意力轉向一個性質完全不同但也可用於服務網格資料平面的技術:eBPF。這是一種現代與強大的Linux核心擴充套件方法,可以用來解決許多網路相關的安全挑戰。

eBPF的基本概念

這項Linux核心技術最初被稱為Berkeley Packet Filter(BPF)。後來經過Google、Facebook和Netflix等公司的一系列增強,為了與原始實作區分,它被稱為eBPF。現在,核心專案和技術通常被稱為eBPF,這本身就是一個術語,不再被視為縮寫。

從技術角度看,eBPF是Linux核心的一個功能,你需要Linux核心版本3.18或更高版本才能使用它。它使你能夠透過使用bpf(2)系統呼叫安全高效地擴充套件Linux核心功能。eBPF以核心內虛擬機器的形式實作,使用自定義的64位RISC指令集。

eBPF的工作原理

eBPF的核心優勢在於它能夠在核心空間安全地執行使用者定義的程式碼,而不需要修改核心原始碼或載入核心模組。這是透過嚴格的驗證器和JIT(Just-In-Time)編譯器實作的。

當你編寫eBPF程式時,它首先會被編譯成eBPF位元組碼。然後,這段位元組碼會被傳遞給核心中的驗證器,驗證器會檢查這段程式碼是否安全(不會造成系統當機或安全漏洞)。透過驗證後,JIT編譯器會將位元組碼轉換為本機器碼以提高效能,然後將其載入到核心中執行。

eBPF程式可以附加到各種核心事件上,例如系統呼叫、函式入口/出口、網路事件等。當這些事件發生時,相應的eBPF程式就會被執行。

eBPF在網路安全中的應用

在網路安全領域,eBPF提供了前所未有的可見性和控制能力:

  1. 深度封包檢測:eBPF可以檢查網路流量的內容,實作高效的封包過濾和分析。

  2. 細粒度的網路策略:可以根據應用程式身份、流量特徵等實作細粒度的網路控制策略。

  3. 安全監控:實時監控網路行為,檢測異常流量模式和潛在的安全威脅。

  4. 服務網格資料平面:作為服務網格的資料平面,eBPF可以提供更高效的服務發現、負載平衡和流量加密功能。

  5. 零信任網路:實作根據身份和行為的網路存取控制,支援零信任安全模型。

eBPF工具生態系統

圍繞eBPF已經發展出豐富的工具生態系統,包括:

  • BCC (BPF Compiler Collection):一組用於建立高效核心追蹤和操作程式的工具和程式函式庫
  • bpftrace:高階追蹤語言,類別似於DTrace
  • Cilium:根據eBPF的網路、安全和可觀察性平台
  • Falco:雲端原生執行時安全專案,使用eBPF進行系統呼叫監控
  • Hubble:根據eBPF的網路可觀察性工具

eBPF與服務網格的融合

有趣的是,eBPF和服務網格這兩種技術正在融合。一些服務網格實作正在探索使用eBPF作為其資料平面的基礎,而不是傳統的sidecar代理模式。這種方法可以減少效能開銷,提供更深層次的網路可見性和控制能力。

例如,Cilium Service Mesh是一個完全根據eBPF的服務網格實作,它不需要sidecar代理,而是直接在核心層面處理服務間通訊,提供更高的效能和更低的延遲。

網路安全的多層次防禦策略

在Kubernetes環境中構建安全的網路架構需要多層次的防禦策略。服務網格和eBPF代表了不同層次的安全控制:

  • 服務網格:在應用層提供身份管理、加密和策略控制,適合處理東西向流量安全
  • eBPF:在核心層提供深度可見性和控制能力,可以實作更底層的安全機制

這兩種技術可以互補使用,共同構建一個強大的網路安全架構。服務網格處理應用層的安全需求,而eBPF則提供底層的可見性和控制能力。

實際應用建議

根據我在實際專案中的經驗,以下是一些關於服務網格和eBPF應用的建議:

  1. 循序漸進採用服務網格:不要試圖一次性將所有服務納入網格。從非關鍵服務開始,逐步擴充套件到更多服務。

  2. 關注服務網格的效能影響:服務網格會增加一定的延遲和資源消耗,確保在生產環境中監控這些指標。

  3. 利用eBPF進行深度可觀測性:在採用服務網格之前,可以先使用eBPF工具來獲得對叢集網路行為的深入瞭解。

  4. 考慮混合方案:對於效能敏感的應用,考慮使用根據eBPF的輕量級服務網格方案。

  5. 不要忽視基礎安全控制:服務網格和eBPF是強大的工具,但不應取代基本的安全控制,如網路策略、安全上下文等。

網路安全是一個不斷發展的領域,尤其在雲端原生環境中。服務網格和eBPF代表了現代Kubernetes網路安全的兩個重要方向,它們共同為構建安全、可靠的微服務架構提供了強大工具。隨著技術的發展,我們可以期待這些技術的進一步融合,為雲端原生應用提供更無縫的安全體驗。

無論選擇哪種技術路徑,重要的是理解其基本原理、優勢和限制,並根據自己的具體需求和環境做出明智的選擇。在雲端原生世界中,沒有放之四海而皆準的解決方案,而是需要根據具體場景選擇最適合的工具組合。

eBPF在雲原生態系統中的崛起

在現代雲原生架構中,Linux核心的擴充能力一直是技術創新的關鍵。而eBPF (extended Berkeley Packet Filter) 作為一項革命性技術,正徹底改變我們與Linux核心互動的方式。當我初次接觸eBPF技術時,就被它能在不修改核心程式碼的情況下,安全地擴充套件核心功能的潛力所震撼。

eBPF允許開發者將自定義程式碼注入核心,在特定事件發生時執行,同時保持系統的穩定性和安全性。這種能力為網路、安全和可觀測性領域帶來了前所未有的靈活性。

eBPF的實際應用場景

2021年起,eBPF已經在多個重要領域展現其價值:

容器網路與服務治理

在Kubernetes生態系統中,eBPF已經成為網路解決方案的核心技術。Cilium和Project Calico等CNI外掛使用eBPF實作Pod網路,提供比傳統iptables更高效的網路策略實施機制。我曾在一個高流量的Kubernetes叢集中,將kube-proxy替換為eBPF實作,服務延遲立即降低了約40%,同時CPU使用率也顯著下降。

系統可觀測性

eBPF為系統監控開闢了新天地。透過iovisor/bpftrace,我們能夠以低開銷方式追蹤Linux核心活動。Hubble則將這種能力擴充套件到叢集層級,提供微服務間通訊的視覺化。這種深度可觀測性讓我們能夠發現傳統監控工具難以捕捉的效能瓶頸。

安全監控與控制

在安全領域,eBPF提供了前所未有的可視性和控制能力。CNCF的Falco專案利用eBPF執行容器執行時掃描,偵測異常行為。同時,Cilium和Calico透過eBPF實作的網路政策,能在核心層級精確控制流量,大幅提升安全防護能力。

網路負載平衡

Facebook的L4 katran函式庫展示了eBPF在高效能網路負載平衡中的應用。相比傳統的負載平衡器,eBPF實作能提供更低的延遲和更高的吞吐量,這對大規模服務至關重要。

Kubernetes入侵檢測

eBPF為Kubernetes環境提供了低層級的入侵檢測能力,能夠監控系統呼叫、網路流量和檔案存取等關鍵活動,及早發現潛在的安全威脅。

eBPF的發展前景

雖然eBPF的廣泛採用仍處於早期階段,但其潛力巨大。Isovalent等公司正引領eBPF領域的創新。特別值得注意的是,eBPF有可能徹底改變服務網格的資料平面實作方式。透過實作Envoy API的一組eBPF程式,可以將處理從使用者空間的sidecar代理推到核心中,大幅提升效能。

例項研究:在Go程式中附加eBPF探針

理論很美好,但實際應用如何呢?讓我們透過一個來自Cilium專案的例子來理解eBPF的實際運用。這個Go程式示範瞭如何將eBPF程式(用C語言編寫)附加到核心符號上。

這個例子的核心目標是:每當系統呼叫sys_execve被呼叫時,核心計數器就會增加,然後Go程式讀取並每秒輸出被探測符號被呼叫的次數。

Go程式與eBPF整合

首先,在main.go中,我們需要指示Go工具鏈包含編譯後的C程式,其中包含eBPF程式碼:

//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -cc clang-11 KProbeExample ./bpf/kprobe_example.c -- -I../headers

這行程式碼使用Go的generate指令,呼叫github.com/cilium/ebpf/cmd/bpf2go工具將C語言編寫的eBPF程式編譯並轉換為Go程式可使用的格式。clang-11指定使用的編譯器,KProbeExample是生成的Go結構體名稱,後面指定了C檔案路徑和包含目錄。

eBPF程式實作

kprobe_example.c中,我們可以找到eBPF程式本身:

#include "common.h"
#include "bpf_helpers.h"

char __license[] SEC("license") = "Dual MIT/GPL";

struct bpf_map_def SEC("maps") kprobe_map = {
    .type = BPF_MAP_TYPE_ARRAY,
    .key_size = sizeof(u32),
    .value_size = sizeof(u64),
    .max_entries = 1,
};

SEC("kprobe/sys_execve")
int kprobe_execve() {
    u32 key = 0;
    u64 initval = 1, *valp;
    
    valp = bpf_map_lookup_elem(&kprobe_map, &key);
    if (!valp) {
        bpf_map_update_elem(&kprobe_map, &key, &initval, BPF_ANY);
        return 0;
    }
    
    __sync_fetch_and_add(valp, 1);
    return 0;
}

這段程式碼實作了一個簡單的eBPF程式,它會在每次sys_execve系統呼叫發生時執行。關鍵部分解析:

  1. char __license[] SEC("license") = "Dual MIT/GPL"; - 定義eBPF程式的授權,這是必須的,因為只有GPL相容的程式才能存取某些核心功能。

  2. struct bpf_map_def SEC("maps") kprobe_map = {...} - 建立一個eBPF對映,用於在核心和使用者空間之間交換資料。這裡使用的是陣列型別的對映,只有一個元素。

  3. SEC("kprobe/sys_execve") - 指定這個程式應該附加到sys_execve系統呼叫上,作為一個kprobe(核心探針)。

  4. 程式邏輯:查詢對映中的計數器值,如果不存在則初始化為1,如果存在則原子地增加1。這確保了計數的準確性,即使在多核系統上也不會出現競爭條件。

eBPF程式開發工具與資源

手動編寫eBPF程式確實不是一件輕鬆的事,幸運的是,現在有許多優秀的工具和環境可以幫助處理底層細節。

值得注意的是,就在技術社群持續推動eBPF發展的同時,Linux基金會宣佈Facebook、Google、Isovalent、Microsoft和Netflix聯合建立了eBPF基金會,為eBPF專案提供了一個廠商中立的家園。這顯示了科技巨頭對eBPF技術前景的共同看好。

若要深入瞭解eBPF,我推薦閱讀David Calavera和Lorenzo Fontana撰寫的《Linux Observability with BPF》。對於需要快速概述的人,Matt Oswalt的《Introduction to eBPF》是不錯的入門資源。

要持續關注最新發展,可以存取ebpf.io並檢視社群在YouTube頻道上發布的相關內容。

此外,Pixie這個開放原始碼的、根據eBPF的可觀測性工具也值得關注,它擁有活躍的社群和廣泛的行業支援。

Kubernetes網路安全最佳實踐

總結來說,在Kubernetes網路空間中有許多預設設定需要注意。作為基礎,可以將傳統非容器化環境中的良好實踐與入侵檢測工具結合使用。此外,建議使用原生資源,如網路策略,可能結合SPIFFE等CNCF專案用於工作負載身份識別,以加強安全狀態。

服務網格雖然仍處於早期階段,但是另一個有前途的選項,可用於執行策略並深入瞭解系統執行狀況。最後,eBPF是網路領域中冉升起的新星,支援多種安全相關使用案例。

現在,我們已經確保了網路安全,接下來可以轉向更"實在"的領域:儲存。

儲存安全:保護您的寶貴資產

組織的價值體現在其資料中。這可能是客戶記錄和帳單詳細訊息、商業機密或智慧財產權。在公司生命週期中收集的客戶和資訊都是寶貴的,而數位海盜只以掠奪為報酬。

考慮身份欺詐者和國家級攻擊者願意為個人資訊支付的代價。如果您的資料對他們沒有價值,您可能會因勒索而被加密鎖定,攻擊者很可能會在入侵您的系統時額外竊取您的資料。

企業通常持有客戶和員工的個人資料,如位置、醫療和財務記錄、信用卡詳細訊息和送貨地址等機密訊息。您的客戶將這些詳細訊息委託給您,而您將它們儲存在檔案系統、資料函式庫或網路儲存系統(NFS、物件儲存、NAS等)上。對於容器從Kubernetes pod存取這些資料,必須使用網路,或者對於更大的資料或更低延遲要求,使用連線到主機系統的磁碟。

將主機檔案系統掛載到容器中會破壞與主機檔案系統的隔離邊界,並為攻擊者提供潛在的可導航路徑。

當容器的儲存可以透過網路存取時,最有效的攻擊策略是竊取存取金鑰並冒充合法應用程式。攻擊者可能會攻擊請求金鑰的應用程式(容器工作負載)、金鑰儲存(API伺服器的Secrets端點或etcd)或應用程式的主機(工作節點)。當Secrets處於靜態狀態時,它們面臨被惡意行為者存取、修改或竊取的風險。

Kubernetes儲存預設設定

Kubernetes應用程式可以在哪裡儲存資料?Pod中的每個容器都有自己的本地檔案系統和臨時目錄,如/tmp或支援分享記憶體的/dev/shm。本地檔案系統與Pod的生命週期相關聯,當Pod停止時會被丟棄。

Pod中的容器不分享掛載名稱空間,這意味著它們不能看到彼此的本地檔案系統。要分享資料,它們可以使用分享卷,即掛載在容器本地檔案系統目錄(如/mnt/foo)的檔案系統。這也與Pod的生命週期繫結,是從底層主機掛載的tmpfs。

要在Pod壽命之外持久化資料,需使用永續性儲存區。它們在叢集級別設定和提供,並在Pod終止後存活。

存取其他Pod的永續性儲存區對敏感工作負載的機密性構成危險。

儲存威脅模型

對儲存最大的擔憂是資料洩露。能夠存取靜態資料的攻擊者可能夠提取敏感的客戶和使用者訊息,利用新發現的知識攻擊其他系統,或設定加密鎖定勒索場景。

提示:設定API伺服器以在etcd中加密靜態Secrets,並將Secrets儲存在KMS或Hashicorp Vault等Secrets儲存中、加金鑰件或實體安全儲存中。

Kubernetes儲存使用卷,這與Docker的卷概念類別似。這些卷用於在容器外持久化狀態,因為容器設計上不能在自己的檔案系統內持久化檔案。卷也用於在Pod中的容器之間分享檔案。