在容器化環境中,網路安全是保障系統穩定性和資料安全的關鍵環節。Kubernetes作為主流的容器協調平台,其網路安全架構需要特別關注。玄貓在多年實踐中發現,許多團隊往往專注於應用程式安全,而忽略了底層網路通訊的安全性,這正是許多安全漏洞的溫床。

Pod到節點的通訊風險

在Kubernetes預設設定下,Pod可以查詢它們所執行的工作節點(Node)以及佈署環境的相關訊息。這種設計雖然便於監控和診斷,但也帶來了潛在的安全風險。

當CNI(Container Network Interface)允許Pod存取節點時,若沒有適當的防護措施,攻擊者可能利用這一通道存取節點資源,進而取得雲端環境的敏感資料或API伺服器。這種情況下,整個叢集的安全邊界就被打破了。

雲端環境的防護策略

各大雲端服務提供商都提供了特定的解決方案來緩解這一風險:

  • Google提供了受保護的GKE節點(Shielded GKE Nodes)
  • Amazon EKS建議限制對執行個體中繼資料的存取
  • GKE提供了保護叢集中繼資料的方法

玄貓在實施雲端安全策略時,經常採用的一個方法是為工作節點設定嚴格的網路政策,限制Pod只能存取其正常執行所需的節點資源。這種「最小許可權」原則在實踐中能有效降低風險。

除了雲提供商的解決方案,也可以考慮使用商業產品如Nirmata的虛擬叢集和工作負載政策來加強安全邊界。

叢集外部流量管理

Kubernetes提供了多種機制來允許Pod與叢集外部端點通訊,其中最常用的是Ingress資源。

Ingress控制器的選擇

Ingress允許第7層(HTTP)路由,而對於第3/4層路由則需要使用其他方法。要使用Ingress資源,需要選擇一個Ingress控制器。市面上有許多開放原始碼選擇:

  • Emissary-ingress
  • Contour
  • HAProxy Ingress
  • NGINX Ingress Controller
  • Traefik

雲端服務提供商通常也提供自己的解決方案,這些解決方案與其代管的負載平衡服務整合。

在選擇Ingress控制器時,玄貓建議考慮以下因素:效能需求、功能豐富度、社群活躍度以及團隊的熟悉程度。例如,對於需要高度自定義路由規則的場景,Traefik可能是更好的選擇;而對於追求穩定性和廣泛支援的團隊,NGINX Ingress Controller可能更合適。

傳輸加密與安全

現今,傳輸層加密(TLS)幾乎已成為標準設定,大多數Ingress解決方案都內建支援。此外,也可以考慮使用服務網格來保護南北向流量。

在應用層面,可以考慮使用Web應用防火牆(WAF),這類別服務由大多數雲提供商提供,也可以使用獨立產品如Wallarm。

越來越多的實踐者分享他們在這方面的經驗,可以關注相關部落格文章和CNCF網路研討會。例如「Shaping Chick-fil-A One Traffic in a Multi-Region Active-Active Architecture」。

ARP欺騙與防護

地址解析協定(ARP)是一種用於將IP網路地址對映到硬體(MAC)地址的鏈路層協定。Liz Rice在KubeCon NA 2019的演講「CAP_NET_RAW and ARP Spoofing in Your Cluster: It’s Going Downhill From Here」中展示了預設設定如何允許開啟原始網路通訊端,以及這如何導致安全問題。

ARP攻擊的風險

這種攻擊涉及使用ARP和DNS欺騙受害Pod存取假URL,這是由於Kubernetes處理本地FQDN的方式,與需要Pod具有CAP_NET_RAW能力。

更多詳情可參見Aqua Security的部落格文章「DNS Spoofing on Kubernetes Clusters」。

防禦措施

好訊息是,有多種防禦措施可以緩解根據ARP的攻擊:

  1. 使用Pod安全策略(PSP)來移除CAP_NET_RAW能力
  2. 使用通用策略引擎如Open Policy Agent/Gatekeeper或使用Kyverno轉換PSP
  3. 在第3層使用Calico或Cilium等工具

玄貓在實踐中發現,移除不必要的容器能力是提高安全性的簡單有效方法。特別是CAP_NET_RAW這類別高風險能力,在絕大多數應用場景中都不是必需的。

要檢測是否受到影響,可以使用kube-hunter等工具進行掃描和評估。

安全上下文與工作負載保護

安全上下文的重要性

預設情況下,工作負載可以升級到其執行的工作節點的網路介面。例如,執行特權容器時,攻擊者可以使用核心模組逃逸容器。此外,正如微軟Azure團隊在「Threat matrix for Kubernetes」部落格文章中指出:

攻擊者若能存取主機網路(例如透過在受損容器上執行程式碼),可以向Kubelet API傳送API請求。具體來說,查詢https://[NODE IP]:10255/pods/可以取得節點上執行的pod訊息;https://[NODE IP]:10255/spec/可以取得關於節點本身的訊息,如CPU和記憶體消耗。

防護策略

為避免這些情況,可以應用Pod安全策略(PSP)。例如,基準/預設策略定義了以下限制:

  • 禁止分享主機名稱空間:
    • spec.hostNetwork
    • spec.hostPID
    • spec.hostIPC
  • 禁止特權Pod(停用大多數安全機制):
    • spec.containers[*].securityContext.privileged
    • spec.initContainers[*].securityContext.privileged
  • 禁止或至少限制HostPorts到已知列表:
    • spec.containers[].ports[].hostPort
    • spec.initContainers[].ports[].hostPort

除此之外,還可以使用商業產品,如Palo Alto Networks Prisma Cloud(前身為Twistlock),來加強工作節點的安全性。

玄貓在實施容器安全策略時,通常建議從最嚴格的安全設定開始,然後根據應用需求逐步放寬限制,而不是從寬鬆設定開始再逐步加強。這種「安全優先」的方法能有效防止設定漏洞。

工作負載身分識別

預設情況下,Kubernetes不會為服務分配身分識別。SPIFFE/SPIRE可用於管理工作負載身分並啟用mTLS。

SPIFFE與SVID

SPIFFE(Secure Production Identity Framework for Everyone)是一組用於安全識別工作負載的規範。它提供了一個框架,透過API定義短期加密身分檔案—稱為SPIFFE可驗證身分檔案(SVID)—來動態地為跨環境的服務發放身分識別。

工作負載可以在與其他工作負載進行身分驗證時使用這些SVID。例如,SVID可用於建立TLS連線或驗證JWT令牌。

玄貓在設計微服務架構時,工作負載身分識別是我最關注的安全環節之一。沒有明確的身分識別機制,微服務之間的互信就建立在脆弱的網路隔離上,這在現代雲原生環境中是遠不夠的。

傳輸加密的必要性

對於受監管行業的工作負載,即任何需要符合(政府發布的)法規的應用,傳輸加密通常是要求之一。例如,如果你是銀行擁有符合支付卡行業資料安全標準(PCI DSS)的應用,或者是醫療提供者擁有符合健康保險可攜性和責任法案(HIPAA)的應用,你需要確保容器化微服務之間的通訊受到保護,防止嗅探和中間人攻擊。

TLS協定與實作

如今,通常使用傳輸層安全(TLS)協定(在RFC 8446和較早的IETF檔案中定義)來加密傳輸中的流量。它使用非對稱加密在工作階段開始時(「握手」)協商分享金鑰,然後使用對稱加密來加密工作負載資料。這種設定是效能與安全之間的良好平衡。

雖然控制平面元件如API伺服器、etcd或kubelet可以依賴內建的PKI基礎設施,為證書提供API和最佳實踐,但對於工作負載來說,情況遺憾地並非如此。

這段技術內容解釋了TLS協定的工作原理,它使用兩種加密方式:初始的「握手」階段用非對稱加密(計算成本高但更安全)來安全地交換金鑰,之後的資料傳輸使用對稱加密(更高效)。這種雙重機制在安全性和效能之間取得了平衡。值得注意的是,雖然Kubernetes控制平面元件內建了PKI支援,但使用者工作負載需要自行實作TLS加密。

提示:你可以使用openssl檢視API伺服器的主機名和編碼到其TLS證書中的任何IP。

預設情況下,Pod之間以及Pod與外部世界之間的流量是不加密的。為了緩解這一問題,可以啟用工作負載傳輸加密,例如:

  • 使用Calico
  • 使用Wireguard 虛擬私人網路
  • 使用Cilium(支援Wireguard和IPsec)

另一個選擇是服務網格,它不僅提供加密,還能提供工作負載身分識別。

網路安全威脅模型

在網路安全空間中,我們需要考慮什麼樣的威脅模型?什麼是我們對攻擊者可能對工作負載和基礎設施做什麼的假設?

以下觀察應該能讓你瞭解潛在的威脅模型。我們用2018-2020年間的一些過去攻擊案例來說明這些情景:

常見攻擊向量

  1. 使用前門入侵:透過Ingress控制器或負載平衡器,然後進行橫向移動或執行拒絕服務攻擊,如CVE-2020-15127中觀察到的

  2. 開發者存取路徑:利用kubectl cp(CVE-2019-11249)或Minikube等開發環境,如CVE-2018-1002103中所見

  3. 特權容器濫用:啟動具有主機網路存取許可權或不必要能力的Pod

  4. 橫向移動:利用已被入侵的工作負載連線到另一個工作負載

  5. 網路掃描:對所有CNI外掛進行連線埠掃描,並進一步使用這些訊息識別漏洞,例如CVE-2019-9946

  6. 控制平面攻擊:攻擊API伺服器、etcd、kubelet或kube-proxy等控制平面元件,例如CVE-2020-8558、CVE-2019-11248、CVE-2019-11247和CVE-2018-1002105

  7. 伺服器端請求偽造(SSRF):針對託管環境,如雲提供商的VM

  8. 中間人攻擊:如在IPv6路由環境中看到的,另見CVE-2020-10749

玄貓在安全評估中發現,大多陣列織對第1、5、6類別攻擊有一定的防範意識,但對於2、3、4、7、8類別攻擊的防護往往不足。特別是橫向移動和SSRF這類別攻擊,在微服務架構中尤為危險,因為它們可以繞過外部防禦機制,直接在內部網路中擴散。

網路安全加固策略

根據上述威脅模型,玄貓建議採取以下網路安全加固策略:

基礎防護措施

  1. 實施網路政策:使用Kubernetes NetworkPolicy或CNI提供的高階網路政策功能,限制Pod之間的通訊。採用「白名單」模式,只允許明確定義的流量。

  2. 啟用加密傳輸:在所有微服務間啟用mTLS,可以透過服務網格如Istio或Linkerd實作,或使用Cilium等CNI外掛提供的加密功能。

  3. 限制容器能力:移除所有不必要的Linux能力,特別是CAP_NET_RAW,可以透過Pod安全策略或OPA Gatekeeper實作。

  4. 監控異常流量:佈署網路流量監控工具,及時發現異常連線和流量模式。Cilium的Hubble或Calico的流量日誌功能都是不錯的選擇。

高階防護技術

  1. 工作負載身分識別:實施SPIFFE/SPIRE或服務網格的身分機制,確保所有服務間通訊都經過身分驗證。

  2. 安全邊界分層:將叢集分為多個安全區域,實施不同級別的安全控制。例如,將包含敏感資料的服務隔離在更嚴格的安全區域。

  3. API伺服器防護:限制對API伺服器的存取,使用RBAC嚴格控制許可權,並考慮實施附加的認證機制。

  4. 節點中繼資料保護:在雲環境中,限制對節點中繼資料服務的存取,防止憑證洩露。

玄貓在實施這些策略時,通常建議分階段進行,先從最關鍵的服務開始,然後逐步擴充套件到整個叢集。這種漸進式的方法可以減少對現有服務的影響,同時確保安全措施的有效性。

安全網路設計的最佳實踐

在設計Kubernetes網路安全架構時,以下最佳實踐可以幫助建立更強大的安全防護:

架構設計考量

  1. 分層防禦:不要依賴單一安全控制,而是實施多層防禦機制。例如,結合網路政策、加密傳輸和工作負載身分識別。

  2. 最小特權原則:為每個服務和Pod分配最小必要的網路存取許可權。預設拒絕所有流量,只允許明確定義的必要通訊。

  3. 可觀測性設計:將網路流量監控和日誌記錄納入架構設計,確保能夠及時發現和回應異常行為。

維運安全實踐

  1. 定期安全掃描:使用kube-hunter、kubeaudit等工具定期掃描叢集,識別潛在的網路安全漏洞。

  2. 自動化合規檢查:實施自動化檢查,確保所有工作負載都符合組織的安全標準。OPA Gatekeeper或Kyverno是實作這一目標的好工具。

  3. 安全更新策略:建立明確的流程來及時應用CNI外掛、Ingress控制器和其他網路元件的安全更新。

  4. 演練與測試:定期進行安全演練,測試防禦機制的有效性,並識別潛在的改進領域。

玄貓在與客戶合作時發現,許多安全事故不是因為缺乏技術解決方案,而是因為缺乏持續的安全維運實踐。即使是最好的安全架構,如果沒有定期的評估和更新,也會隨著時間的推移而變得脆弱。

雲原生環境的特殊考量

在雲原生環境中佈署Kubernetes叢集時,需要特別考慮以下網路安全因素:

多雲與混合雲環境

在跨多個雲平台或混合雲/本地環境的佈署中,網路安全變得更加複雜。玄貓建議:

  1. 統一身分管理:實施跨雲的統一身分管理解決方案,確保一致的身分驗證和授權。

  2. 加密跨雲通訊:所有跨雲或雲到本地的通訊都應該加密,可以考慮使用虛擬私人網路或專用線路。

  3. 統一策略管理:使用如Anthos Config Management或Rancher Fleet等工具,確保網路安全策略在所有環境中一致應用。

服務網格的應用

服務網格技術如Istio、Linkerd或Consul提供了強大的網路安全功能:

  1. 自動mTLS:服務網格可以自動為服務間通訊啟用mTLS,無需修改應用程式碼。

  2. 細粒度存取控制:實施根據身分的授權策略,控制哪些服務可以相互通訊。

  3. 流量觀測:獲得服務間通訊的詳細可視性,幫助識別異常模式。

玄貓在實施服務網格時發現,雖然它提供了強大的安全功能,但也增加了系統的複雜性和資源消耗。因此,建議先在非生產環境中充分測試,並確保團隊具備管理服務網格的技能,再考慮在生產環境中大規模佈署。

結論

Kubernetes網路安全是一個不斷發展的領域,隨著技術的進步和威脅環境的變化,安全策略也需要不斷調整和改進。

從Pod到節點的通訊安全、叢集外部流量管理、ARP欺騙防護到工作負載身分識別,每一層面都需要周密的規劃和實施。透過採用本文討論的最佳實踐和安全加固策略,組織可以顯著提高其Kubernetes環境的安全性。

玄貓認為,未來的Kubernetes網路安全將更加註重自動化、人工智慧化和零信任架構。隨著技術的成熟,我們可以期待看到更多內建的安全功能和更簡單的安全實施方法,使得即使是資源有限的團隊也能達到高水平的安全防護。

最後,安全不是一次性的工作,而是一個持續的過程。定期評估、更新和改進你的網路安全策略,是保持Kubernetes環境安全的關鍵。

Kubernetes 網路流量安全:從預設風險到全面防護

在容器協調世界中,網路安全常被忽視,直到問題發生才引起注意。在我多年管理 Kubernetes 叢集的經驗中,發現許多工程師對 K8s 的網路預設行為認知不足,導致不必要的安全漏洞。本文將帶你從零開始建立一個測試環境,並展示如何透過網路政策來確保外部流量的安全。

預設網路行為的隱藏風險

Kubernetes 預設允許所有 Pod 之間的通訊,這種設計雖然便於開發,但在生產環境中可能造成嚴重的安全隱患。想像一下,如果一個惡意容器成功入侵你的叢集,在沒有網路限制的情況下,它可以自由地探測和攻擊叢集中的任何服務。

建立測試環境:使用 Kind 和 Calico

為了展示這些概念,我們將使用 Kind (Kubernetes IN Docker) 建立一個本地 Kubernetes 叢集,並設定 Calico 作為網路外掛來實作網路政策。

環境準備與叢集設定

首先,我們需要建立一個設定來定義我們的 Kind 叢集:

kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
  kubeadmConfigPatches:
  - |
    kind: InitConfiguration
    nodeRegistration:
      kubeletExtraArgs:
        node-labels: "ingress-ready=true"
  extraPortMappings:
  - containerPort: 80
    hostPort: 80
    protocol: TCP
  - containerPort: 443
    hostPort: 443
    protocol: TCP
- role: worker
networking:
  disableDefaultCNI: true
  podSubnet: 192.168.0.0/16

這個設定了一個定義包含一個控制平面節點和一個工作節點的 Kubernetes 叢集。關鍵設定包括:

  1. 在控制平面節點上設定 ingress-ready=true 標籤,為後續的 Ingress 控制器做準備
  2. 設定連線埠對映,將容器內的 80 和 443 連線埠對映到主機上,使我們能從主機直接存取服務
  3. 停用預設的 CNI (Container Network Interface),因為我們將使用 Calico
  4. 設定 Pod 網路的子網為 192.168.0.0/16,這是 Calico 的預設設定

假設上述設定已儲存為 cluster-config.yaml,現在我們可以建立叢集:

$ kind create cluster --name cnnp --config cluster-config.yaml

安裝與設定 Calico

接下來,我們需要安裝 Calico 網路外掛,並進行必要的修補,使其能在 Kind 環境中正常工作:

$ kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml
$ kubectl -n kube-system set env daemonset/calico-node FELIX_IGNORELOOSERPF=true
  1. 第一個命令安裝 Calico 的所有必要元件,包括 ConfigMap、CRD 和守護程式等
  2. 第二個命令是一個關鍵調整,設定 FELIX_IGNORELOOSERPF=true 環境變數,使 Calico 在 Kind 這種特殊環境中能正常運作。這是因為 Kind 使用 Docker 容器模擬節點,其網路設定與標準 Kubernetes 節點略有不同

確認 Calico 節點代理程式已在所有節點上執行:

$ kubectl -n kube-system get pods | grep calico-node

佈署 Ingress 控制器

為了讓外部流量能夠進入叢集,我們需要安裝 Ingress 控制器。這裡選擇使用 Ambassador 作為我們的 Ingress 控制器:

$ kubectl apply -f https://github.com/datawire/ambassador-operator/releases/latest/download/ambassador-operator-crds.yaml && \
kubectl apply -n ambassador -f https://github.com/datawire/ambassador-operator/releases/latest/download/ambassador-operator-kind.yaml && \
kubectl wait --timeout=180s -n ambassador --for=condition=deployed ambassadorinstallations/ambassador

這串命令執行了三個主要操作:

  1. 安裝 Ambassador 所需的自定義資源定義 (CRD)
  2. ambassador 名稱空間中佈署 Ambassador 操作器
  3. 等待 Ambassador 完全佈署完成,最長等待 180 秒

佈署測試應用程式

現在基礎設施已經準備就緒,我們可以佈署一個簡單的 Web 服務來測試我們的網路設定。

建立專用名稱空間

首先,建立一個專用的名稱空間來佈署我們的應用:

$ kubectl create ns npdemo

佈署 Web 服務與 Ingress 規則

接下來,建立一個包含佈署 (Deployment)、服務 (Service) 和入口 (Ingress) 資源的設定:

kind: Deployment
apiVersion: apps/v1
metadata:
  labels:
    app: nginx
  name: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:alpine
        name: main
        ports:
        - containerPort: 80
---
kind: Service
apiVersion: v1
metadata:
  name: nginx
spec:
  selector:
    app: nginx
  ports:
  - port: 80
---
kind: Ingress
apiVersion: extensions/v1beta1
metadata:
  name: mainig
  annotations:
    kubernetes.io/ingress.class: ambassador
spec:
  rules:
  - http:
      paths:
      - path: /api
        backend:
          serviceName: nginx
          servicePort: 80

這個設定定義了三個資源:

  1. Deployment:佈署一個執行 NGINX Alpine 版本的 Pod
  2. Service:建立一個服務,將流量轉發到帶有 app: nginx 標籤的 Pod
  3. Ingress:設定路由規則,將 /api 路徑的請求轉發到 NGINX 服務

特別注意 Ingress 資源上的註解 kubernetes.io/ingress.class: ambassador,這告訴 Kubernetes 使用 Ambassador 作為此 Ingress 的控制器。

將這些資源應用到叢集中:

$ kubectl -n npdemo apply -f workload.yaml

測試初始網路行為

現在讓我們測試一下是否能從外部存取我們的應用:

$ curl -s 127.0.0.1/api | wc -l
25

果然,我們收到了回應!這證實了 Kubernetes 的預設網路行為:所有流量都被允許。這種寬鬆的預設設定在生產環境中可能帶來嚴重的安全風險。

實施網路政策強化安全

現在我們將透過網路政策來限制流量,展示如何保護我們的應用免受未授權存取。

阻擋所有入站流量

首先,我們建立一個網路政策來阻擋所有入站 (Ingress) 流量:

kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: deny-all
spec:
  podSelector: {}
  policyTypes:
  - Ingress

這個網路政策非常簡單但功能強大:

  • podSelector: {} 表示選擇名稱空間中的所有 Pod
  • policyTypes: ["Ingress"] 指定這是一個入站流量政策
  • 由於沒有定義任何 ingress 規則,這實際上阻擋了所有入站流量

應用這個網路政策:

$ kubectl -n npdemo apply -f np-deny-all.yaml

驗證網路政策效果

讓我們再次嘗試存取應用:

$ curl --max-time 3 127.0.0.1/api
curl: (28) Operation timed out after 3005 milliseconds with 0 bytes received

太好了!請求超時,這表明我們的網路政策生效了,成功阻擋了所有入站流量。

網路政策的除錯與管理工具

在實際環境中,網路政策的設定可能相當複雜。以下是一些有用的工具,可以幫助你管理和除錯網路政策:

  1. networkpolicy.io - 提供視覺化編輯器,幫助你編寫和理解網路政策
  2. krew-net-forward - 用於除錯網路政策的 kubectl 外掛
  3. netassert - 測試網路政策是否按預期工作的工具

超越網路政策的安全措施

除了 Kubernetes 網路政策,某些雲端服務提供商還提供其他本地機制來限制 Pod 的流量。例如,AWS 提供了適用於 Pod 的安全組,可以在 VPC 層面進一步加強安全性。

當我在大型金融機構實施 Kubernetes 時,發現結合 Kubernetes 網路政策與雲提供商的安全功能,可以建立深度防禦架構,大幅提高安全性。這種多層防護方法在處理敏感工作負載時尤為重要。