在容器化技術迅速發展的今日,Kubernetes 已成為企業佈署雲端應用的核心平台。然而,隨著其普及,Kubernetes 的安全問題也日益凸顯。在處理敏感資料和關鍵業務應用時,安全防護不再是可選項,而是必要條件。
安全從來不是絕對的概念。作為技術工作者,我從不會簡單地宣稱某個系統「安全」,而是會評估其相對安全程度。本文將分享如何提升 Kubernetes 叢集的安全性,並根據不同風險情境提供相應的防護策略。
Kubernetes 安全威脅模型
在深入討論具體安全措施前,我們需要了解 Kubernetes 環境中的主要攻擊向量:
- 叢集設定漏洞 - 不安全的 API Server 設定、etcd 暴露等
- 身分驗證缺陷 - 弱密碼、過期憑證、許可權管理不當
- 容器映像問題 - 未修補的漏洞、惡意程式碼、供應鏈攻擊
- 執行時安全 - 容器逃逸、許可權提升、資源濫用
- 網路安全 - 未加密通訊、網路政策缺失、服務暴露
- 機密資訊管理 - 未加密的 Secret、硬編碼憑證
本文將逐一探討這些安全領域,提供實用的防護策略和最佳實踐。
叢集安全基礎:保護 Kubernetes 核心元件
Kubernetes 叢集的安全性首先取決於其核心元件的設定。不當的設定可能導致整個環境遭受攻擊。
API Server 安全加固
API Server 是 Kubernetes 的核心控制點,所有操作都需經過它處理,因此它是首要的安全防護目標。
apiVersion: v1
kind: Pod
metadata:
name: kube-apiserver
namespace: kube-system
spec:
containers:
- name: kube-apiserver
image: k8s.gcr.io/kube-apiserver:v1.21.0
command:
- kube-apiserver
- --authorization-mode=Node,RBAC
- --enable-admission-plugins=NodeRestriction,PodSecurityPolicy
- --anonymous-auth=false
- --insecure-port=0
- --audit-log-path=/var/log/kubernetes/audit.log
- --audit-log-maxage=30
- --tls-cert-file=/etc/kubernetes/pki/apiserver.crt
- --tls-private-key-file=/etc/kubernetes/pki/apiserver.key
這個設定範例展示了 API Server 的安全設定:
- 啟用 Node 和 RBAC 授權模式,確保所有操作都受到適當的許可權控制
- 啟用 NodeRestriction 和 PodSecurityPolicy 准入控制器,限制 Pod 的許可權
- 停用匿名存取,要求所有請求都必須經過身分驗證
- 關閉不安全的 HTTP 連線埠,只允許 HTTPS 連線
- 啟用稽核日誌,記錄所有操作以便追蹤可能的安全事件
- 設定 TLS 憑證,確保通訊加密
在實際佈署中,我發現許多團隊忽略了 API Server 的安全設定,直到發生安全事件才意識到問題。建議在初始設定時就應用這些安全引數,並定期檢查設定是否符合最新的安全建議。
Kubelet 安全設定
Kubelet 是每個節點上的代理,負責管理容器的生命週期。不安全的 Kubelet 設定可能允許攻擊者在節點上執行惡意容器。
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
authentication:
anonymous:
enabled: false
webhook:
enabled: true
x509:
clientCAFile: /etc/kubernetes/pki/ca.crt
authorization:
mode: Webhook
readOnlyPort: 0
tlsCertFile: /etc/kubernetes/pki/kubelet.crt
tlsPrivateKeyFile: /etc/kubernetes/pki/kubelet.key
這個 Kubelet 設定範例實施了以下安全措施:
- 停用匿名存取,確保所有連線都需要身分驗證
- 啟用 Webhook 身分驗證,與 API Server 協調驗證請求
- 設定 X.509 憑證認證,確保只有受信任的客戶端可以連線
- 設定授權模式為 Webhook,將授權決策委託給 API Server
- 關閉唯讀連線埠,減少攻擊面
- 設定 TLS 憑證,確保通訊加密
在我的實踐中,發現許多安全事件源於 Kubelet 設定不當。特別是允許匿名存取或開放唯讀連線埠,這些設定在開發環境中可能方便除錯,但在生產環境中卻是嚴重的安全隱患。
安全執行 etcd
etcd 儲存了 Kubernetes 的所有設定和狀態訊息,包括敏感的 Secret 資料。保護 etcd 至關重要。
# 啟動 etcd 的安全設定範例
etcd \
--cert-file=/etc/kubernetes/pki/etcd/server.crt \
--key-file=/etc/kubernetes/pki/etcd/server.key \
--client-cert-auth \
--trusted-ca-file=/etc/kubernetes/pki/etcd/ca.crt \
--peer-cert-file=/etc/kubernetes/pki/etcd/peer.crt \
--peer-key-file=/etc/kubernetes/pki/etcd/peer.key \
--peer-client-cert-auth \
--peer-trusted-ca-file=/etc/kubernetes/pki/etcd/ca.crt \
--data-dir=/var/lib/etcd
這個 etcd 啟動設定實施了多層安全防護:
- 啟用 TLS 加密,保護客戶端與 etcd 之間的通訊
- 啟用客戶端憑證認證,確保只有授權客戶端可以存取
- 設定受信任的 CA 證書,用於驗證客戶端憑證
- 啟用節點間通訊的 TLS 加密和憑證認證
- 指定資料儲存目錄,便於實施檔案系統級別的保護
etcd 的安全設定常被忽視,但它實際上是 Kubernetes 安全架構中的關鍵環節。我建議將 etcd 佈署在專用節點上,並限制對這些節點的網路存取,同時定期備份 etcd 資料。
Kubernetes Dashboard 安全防護
Kubernetes Dashboard 提供了便捷的 Web 介面,但也可能成為安全風險。2018年,特斯拉雲環境被入侵就是因為暴露了未受保護的 Kubernetes Dashboard。
# Dashboard 安全存取設定
apiVersion: v1
kind: Service
metadata:
name: kubernetes-dashboard
namespace: kube-system
spec:
type: ClusterIP # 不要使用 LoadBalancer 或 NodePort
ports:
- port: 443
targetPort: 8443
selector:
k8s-app: kubernetes-dashboard
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: dashboard-minimal
namespace: kube-system
rules:
- apiGroups: [""]
resources: ["secrets"]
verbs: ["create"]
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "update", "delete"]
resourceNames: ["kubernetes-dashboard-settings"]
這個設定範例展示了 Dashboard 的安全佈署方式:
- 使用 ClusterIP 服務型別,避免直接從外部存取
- 限制 Dashboard 的 RBAC 許可權,遵循最小許可權原則
- 未顯示但建議:設定存取令牌或身分驗證代理
在實際佈署中,我通常建議透過 kubectl proxy 或設定安全的 Ingress 來存取 Dashboard,而不是直接暴露服務。此外,永遠不要給 Dashboard 分配 cluster-admin 許可權,這是一個常見但危險的錯誤。
驗證叢集設定
定期檢查叢集設定是否符合安全最佳實踐至關重要。kube-bench 是一個根據 CIS Kubernetes 基準的開放原始碼工具,可以幫助評估叢集安全性。
# 在主節點上執行 kube-bench
docker run --pid=host -v /etc:/etc:ro -v /var:/var:ro -t aquasec/kube-bench:latest master
# 在工作節點上執行 kube-bench
docker run --pid=host -v /etc:/etc:ro -v /var:ro -t aquasec/kube-bench:latest node
kube-bench 會根據 CIS Kubernetes 安全基準檢查叢集設定,並生成詳細報告,指出潛在的安全問題和改進建議。這個工具對於:
- 識別不符合安全最佳實踐的設定
- 提供具體的修復建議
- 生成可用於合規報告的結果
我經常在新佈署的叢集上執行 kube-bench,並將其納入持續整合流程,確保安全設定不會隨著時間推移而降級。值得注意的是,不是所有的建議都適用於每個環境,需要根據具體情況進行評估。
身分驗證:誰可以存取你的叢集
身分驗證是 Kubernetes 安全的第一道防線,它確定誰可以與叢集互動。
身分識別基礎
Kubernetes 中的身分可以分為兩大類別:
- 服務帳戶:供 Pod 內應用程式使用
- 使用者:供人類使用者和外部系統使用
與許多系統不同,Kubernetes 本身不管理普通使用者,而是依賴外部身分提供者。
# 服務帳戶範例
apiVersion: v1
kind: ServiceAccount
metadata:
name: app-service-account
namespace: production
---
# 將服務帳戶與 Pod 關聯
apiVersion: v1
kind: Pod
metadata:
name: app-pod
namespace: production
spec:
serviceAccountName: app-service-account
containers:
- name: app
image: myapp:1.0.0
這個範例展示瞭如何建立服務帳戶並將其分配給 Pod:
- 在 production 名稱空間中建立名為 app-service-account 的服務帳戶
- 將該服務帳戶分配給 app-pod
- Pod 中的應用程式可以使用此服務帳戶的憑證與 API Server 通訊
服務帳戶是 Kubernetes 中最常用的身分型別,每個名稱空間都有一個預設服務帳戶。然而,我強烈建議為不同的應用程式建立專用的服務帳戶,並限制其許可權,這樣可以減少潛在攻擊的影響範圍。
身分驗證策略
Kubernetes 支援多種身分驗證策略,可以同時啟用多種方式:
- X.509 客戶端憑證
- 靜態令牌檔案
- OpenID Connect (OIDC)
- Webhook 令牌認證
- 身分驗證代理
在企業環境中,OIDC 是最常用的方法,因為它可以與現有的身分管理系統整合。
# 使用 X.509 客戶端憑證生成 kubeconfig
kubectl config set-credentials developer \
--client-certificate=developer.crt \
--client-key=developer.key \
--embed-certs=true
這個命令設定了使用 X.509 客戶端憑證進行身分驗證:
- 建立名為 “developer” 的使用者憑證
- 指定客戶端憑證和私鑰檔案
- 將憑證嵌入到 kubeconfig 檔案中,而不是參照外部檔案
X.509 憑證認證是最基本的方法,適用於小型團隊或開發環境。對於大型組織,我建議實施 OIDC 認證,將 Kubernetes 身分驗證與企業身分提供者(如 Azure AD、Okta 或 Google)整合。
身分驗證最佳實踐
在設計 Kubernetes 身分驗證策略時,我建議遵循以下最佳實踐:
- 避免使用靜態令牌:靜態令牌難以復原,與容易洩露
- 實施短期憑證:使用有限生命週期的憑證,減少憑證洩露的風險
- 整合企業身分系統:利用現有的身分管理基礎設施
- 啟用多因素認證:增加額外的安全層
- 稽核身分驗證事件:記錄並監控所有身分驗證嘗試
# API Server 設定 OIDC 範例
apiVersion: v1
kind: Pod
metadata:
name: kube-apiserver
namespace: kube-system
spec:
containers:
- name: kube-apiserver
image: k8s.gcr.io/kube-apiserver:v1.21.0
command:
- kube-apiserver
- --oidc-issuer-url=https://accounts.google.com
- --oidc-client-id=kubernetes
- --oidc-username-claim=email
- --oidc-groups-claim=groups
這個設定範例展示瞭如何設定 API Server 使用 Google 作為 OIDC 提供者:
- 指定 OIDC 發行者 URL
- 設定客戶端 ID
- 設定使用 email 宣告作為使用者名
- 設定使用 groups 宣告對映到 Kubernetes 組
在實際佈署中,我發現 OIDC 整合是最靈活與安全的身分驗證方法,特別是對於已經使用雲端服務提供商的組織。它允許利用現有的使用者管理、多因素認證和單點登入功能。
授權:控制使用者可以做什麼
身分驗證確定誰可以存取叢集,而授權則決定他們可以做什麼。Kubernetes 提供了多種授權模式,其中根據角色的存取控制 (RBAC) 是最強大與靈活的。
授權模式
Kubernetes 支援以下授權模式:
- Node:專用於 kubelet 存取
- ABAC:根據屬性的存取控制
- RBAC:根據角色的存取控制
- Webhook:委託給外部 REST 服務
- AlwaysDeny/AlwaysAllow:測試用,不應在生產中使用
這些模式可以同時啟用,請求會按順序透過每個授權器,直到其中一個做出決定。
# API Server 授權設定
apiVersion: v1
kind: Pod
metadata:
name: kube-apiserver
namespace: kube-system
spec:
containers:
- name: kube-apiserver
image: k8s.gcr.io/kube-apiserver:v1.21.0
command:
- kube-apiserver
- --authorization-mode=Node,RBAC
# 其他引數...
這個設定啟用了 Node 和 RBAC 授權模式:
- Node 授權器允許 kubelet 存取與其節點相關的資源
- RBAC 授權器根據角色和角色繫結決定使用者許可權
在實際佈署中,我強烈建議使用 RBAC 作為主要授權機制。它提供了細粒度的存取控制,並且與 Kubernetes 的宣告式設定模型很好地結合。
使用 RBAC 進行存取控制
RBAC 是 Kubernetes 中最強大的授權機制,它根據角色和許可權定義存取控制。
RBAC 的核心概念包括:
- 角色:定義在名稱空間內可執行的操作
- 叢集角色:定義在整個叢集範圍內可執行的操作
- 角色繫結:將角色與使用者或服務帳戶關聯
- 叢集角色繫結:將叢集角色與使用者或服務帳戶關聯
# 建立一個只能讀取 Pod 的角色
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:
name: read-pods
namespace: default
subjects:
- kind: ServiceAccount
name: monitoring-sa
namespace: default
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
這個 RBAC 設定範例:
- 建立一個名為 pod-reader 的角色,只允許讀取 Pod 資源
- 建立一個角色繫結,將該角色分配給 monitoring-sa 服務帳戶
- 服務帳戶現在只能讀取 default 名稱空間中的 Pod,無法修改它們或存取其他資源
RBAC 遵循最小許可權原則,只授予完成任務所需的最小許可權。在設計 RBAC 策略時,我建議從最小許可權開始,然後根據需要逐步增加許可權,而不是一開始就授予過多許可權。
RBAC 最佳實踐
根據我的經驗,以下是實施 RBAC 的一些最佳實踐:
- 避免使用 cluster-admin:除非絕對必要,否則不要使用此超級使用者角色
- 使用名稱空間隔離:將應用程式分組到名稱空間,並使用名稱空間級別的角色
- 定期審查許可權:定期檢查和清理不必要的許可權
- 使用組而非個人:將許可權分配給組而不是個人使用者
- 實施最小許可權:只授予完成任務所需的最小許可權
# 審查使用者許可權的有用命令
kubectl auth can-i --list --as=system:serviceaccount:default:app-service-account
# 檢查特定操作的授權
kubectl auth can-i get pods --as=system:serviceaccount:default:app-service-account
這些命令可以幫助審查和驗證 RBAC 許可權:
- 第一個命令列出服務帳戶可以執行的所有操作
- 第二個命令檢查服務帳戶是否可以執行特定操作(取得 Pod)
我經常使用這些命令來驗證 RBAC 設定是否符合預期,特別是在實施複雜的許可權策略時。這種主動驗證可以幫助發現和修復潛在的許可權問題,避免安全漏洞。
容器映像安全:保護供應鏈
容器安全始於映像安全。不安全的容器映像可能包含漏洞、惡意軟體或後門,危及整個環境。
掃描容器映像
定期掃描容器映像是識別和修復安全漏洞的關鍵步驟。
# 使用 Trivy 掃描容器映像
trivy image nginx:1.19
# 在 CI/CD 流程中整合掃描
trivy image --exit-code 1 --severity HIGH,CRITICAL myapp:latest
這些命令使用 Trivy(一個開放原始碼容器掃描工具)來檢查映像中的漏洞:
- 第一個命令掃描 nginx:1.19 映像並顯示所有漏洞
- 第二個命令在發現高危或嚴重漏洞時回傳非零結束碼,適合整合到 CI/CD 流程中
在實際工作中,我發現映像掃描應該在多個階段進行:開發過程中、推播到登入檔時,以及定期掃描已佈署的映像。這種多層掃描策略可以及早發現並修復漏洞。
修補容器映像
發現漏洞後,需要及時修補映像。與傳統系統不同,容器應該透過重建映像而不是在執行時修補來更新。
# 良好的 Dockerfile 實踐
FROM ubuntu:20.04
# 在同一層中更新和安裝,減少層數
RUN apt-get update && \
apt-get upgrade -y && \
apt-get install -y --no-install-recommends nginx && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
# 使用非特權使用者執行
USER nginx
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
這個 Dockerfile 範例展示了一些安全最佳實踐:
- 在同一個 RUN 指令中更新和安裝軟體,確保使用最新的安全補丁
- 安裝後清理 apt 快取,減少映像大小和攻擊面
- 使用非 root 使用者執行應用程式
在容器世界中,修補策略應該圍繞「不可變基礎設施」原則:不要修改現有容器,而是佈署包含修補程式的新容器。這種方法確保了環境的一致性和可重現性。
CI/CD 最佳實踐
將安全檢查整合到 CI/CD 流程中是確保容器映像安全的關鍵。
# GitLab CI 設定範例
stages:
- build
- test
- scan
- deploy
build:
stage: build
script:
- docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
vulnerability_scan:
stage: scan
script:
- trivy image --exit-code 1 --severity HIGH,CRITICAL $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
- docker run --rm -v /var/run/docker.sock:/var/run/docker.sock aquasec/kube-bench:latest image --image $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
deploy:
stage: deploy
script:
- kubectl set image deployment/app container=$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
only:
- master
這個 CI/CD 設定範例實施了多層安全檢查:
- 構建容器映像並標記為提交 SHA
- 使用 Trivy 掃描映像中的漏洞,如果發現高危或嚴重漏洞則失敗
- 使用 kube-bench 檢查映像是否符合安全最佳實踐
- 只有透過所有安全檢查的映像才會佈署到生產環境
在我的實踐中,這種「左移」安全方法(在開發週期早期整合安全檢查)可以顯著減少生產環境中的安全問題。它還培養了開發人員的安全意識,因為他們會立即收到安全問題的反饋。
映像儲存與版本控制
安全地儲存和管理容器映像是容器安全策略的重要組成部分。
# 設定 Pod 使用私有登入檔
apiVersion: v1
kind: Pod
metadata:
name: private-image-pod
spec:
containers:
- name: app
image: private-registry.example.com/myapp:v1.2.3
imagePullSecrets:
- name: registry-credentials
---
# 建立映像提取金鑰
apiVersion: v1
kind: Secret
metadata:
name: registry-credentials
type: kubernetes.io/dockerconfigjson
data:
.dockerconfigjson: <base64-encoded-docker-config>
這個設定範例展示瞭如何使用私有登入檔中的映像:
- 指定完整的映像路徑,包括登入檔網域名稱
- 使用 imagePullSecrets 提供存取私有登入檔的憑證
- 建立包含登入檔認證的 Secret
在生產環境中,我強烈建議使用私有容器登入檔,並實施以下最佳實踐:
- 啟用映像掃描功能
- 實施映像簽名和驗證
- 定期清理未使用的映像
- 強制使用特定的映像標籤,避免使用 “latest”
映像信任與供應鏈安全
確保只佈署受信任的容器映像是防止供應鏈攻擊的關鍵。
# 使用 Notary 簽名映像
docker trust sign myregistry.example.com/myapp:1.0.0
# 在 Kubernetes 中驗證映像簽名
# 需要設定準入控制器,如 Portieris 或 Connaisseur
這個範例展示瞭如何使用 Docker Content Trust (根據 Notary) 簽名和驗證映像:
- 簽名過程為映像建立數字簽名,證明其來源和完整性
- 在 Kubernetes 中,可以使用准入控制器確保只佈署經過簽名的映像
映像簽名是建立容器供應鏈信任的重要機制。在我的實踐中,我發現實施映像簽名可以顯著降低佈署惡意或未經授權映像的風險,特別是在多團隊環境中。
最小化映像以減少攻擊面
較小的容器映像不僅佈署更快,而與通常更安全,因為它們包含較少的潛在漏洞。
# 多階段構建範例
FROM golang:1.16 AS builder
WORKDIR /app
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .
FROM alpine:3.14
RUN apk --no-cache add ca-certificates && \
adduser -D -H -h /app appuser
WORKDIR /app
COPY --from=builder /app/app .
USER appuser
CMD ["./app"]
這個多階段 Dockerfile 展示瞭如何建立最小化的容器映像:
- 使用 golang 映像作為構建階段,編譯應用程式
- 使用輕量級的 alpine 映像作為最終映像
- 只複製編譯好的二進位檔案,不包含原始碼和構建工具
- 增加必要的 CA 證書以支援 HTTPS
- 建立並使用非特權使用者執行應用程式
在我的容器化專案中,我經常使用多階段構建和根據 Alpine 或 distroless 的基礎映像。這種方法可以將映像大小減少 90% 以上,同時顯著減少攻擊面。
安全執行容器:執行時防護
即使容器映像是安全的,不安全的執行時設定也可能導致安全漏洞。
拒絕 Root 許可權
在容器中以 root 身份執行應用程式是一種常見但危險的做法。如果容器被攻破,攻擊者可能獲得對主機的存取許可權。
# 設定 Pod 安全上下文
apiVersion: v1
kind: Pod
metadata:
name: security-context-demo
spec:
securityContext:
runAsUser: 1000
runAsGroup: 3000
fsGroup: 2000
containers:
- name: app
image: myapp:1.0.0
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
這個 Pod 設定實施了多層安全控制:
- 以 UID 1000 執行容器程式,而不是 root (UID 0)
- 設定程式的主組為 GID 3000
- 將掛載的卷的所有權設定為 GID 2000
- 禁止許可權提升,防止程式獲得更多許可權
- 將根檔案系統設定為只讀,防止修改系統檔案
- 刪除所有 Linux 功能,只保留絕對必要的功能
在我的實踐中,這些安全上下文設定是防止容器逃逸和許可權提升攻擊的關鍵。即使應用程式被攻破,這些限制也能顯著減少攻擊者的活動範圍。
准入控制
Kubernetes 准入控制器可以在資源建立或修改時強制執行安全策略。
# 設定 PodSecurityPolicy
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: restricted
spec:
privileged: false
allowPrivilegeEscalation: false
requiredDropCapabilities:
- ALL
volumes:
- 'configMap'
- 'emptyDir'
- 'projected'
- 'secret'
- 'downwardAPI'
- 'persistentVolumeClaim'
hostNetwork: false
hostIPC: false
hostPID: false
runAsUser:
rule: 'MustRunAsNonRoot'
seLinux:
rule: 'RunAsAny'
supplementalGroups:
rule: 'MustRunAs'
ranges:
- min: 1
max: 65535
fsGroup:
rule: 'MustRunAs'
ranges:
- min: 1
max: 65535
readOnlyRootFilesystem: true
這個 PodSecurityPolicy 定義了嚴格的安全要求:
- 禁止特權容器和許可權提升
- 刪除所有 Linux 功能
- 限制可以使用的卷型別
- 禁止存取主機網路、IPC 和 PID 名稱空間
- 要求容器以非 root 使用者執行
- 限制補充組 ID 和 fsGroup ID 的範圍
- 要求根檔案系統為只讀
PodSecurityPolicy 在 Kubernetes v1.21 中被棄用,並在 v1.25 中移除,取而代之的是 Pod Security Admission。然而,理解這些安全控制仍然很重要,因為它們代表了容器安全的最佳實踐。
安全邊界
瞭解 Kubernetes 中的安全邊界對於設計安全的多租戶環境至關重要。
# 使用名稱空間隔離
apiVersion: v1
kind: Namespace
metadata:
name: team-a
labels:
team: a
---
# 使用網路政策限制通訊
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-from-other-namespaces
namespace: team-a
spec:
podSelector: {}
ingress:
- from:
- namespaceSelector:
matchLabels:
team: a
這個設定範例展示瞭如何使用名稱空間和網路政策建立隔離環境:
- 建立名為 team-a 的名稱空間,並增加標籤
- 定義網路政策,只允許來自同一團隊名稱空間的流量
在 Kubernetes 中,名稱空間提供了邏輯隔離,但不提供強安全隔離。為了增強隔離,我建議:
- 實施嚴格的網路政策
- 使用資源配額限制資源使用
- 為每個租戶使用單獨的節點池
- 考慮使用 gVisor 或 Kata Containers 等容器執行時沙箱
安全策略實施
Kubernetes 提供了多種機制來實施安全策略,包括 Pod Security Admission、OPA Gatekeeper 和網路政策。
# Pod Security Standards 設定
apiVersion: v1
kind: Namespace
metadata:
name: production
labels:
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/warn: restricted
---
# OPA Gatekeeper 約束範例
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
name: require-team-label
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Namespace"]
parameters:
labels: ["team"]
這些設定範例展示瞭如何實施安全策略:
- 第一個範例使用 Pod Security Admission 在 production 名稱空間中強制執行 “restricted” 安全標準
- 第二個範例使用 OPA Gatekeeper 要求所有名稱空間都有 “team” 標籤
在我的實踐中,我發現這些策略實施機制最有效的是分層應用:
- 使用 Pod Security Admission 強制執行基本安全標準
- 使用 OPA Gatekeeper 實施組織特定的策略
- 使用網路政策控制 Pod 間通訊
- 使用資源配額防止資源耗盡攻擊
機密管理:保護敏感資料
安全管理密碼、API 金鑰和其他敏感訊息是 Kubernetes 安全的關鍵方面。
應用最小許可權原則
在機密管理中,最小許可權原則意味著只向需要的 Pod 提供必要的機密。
# 限制 Secret 存取的 RBAC 設定
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: default
name: secret-reader
rules:
- apiGroups: [""]
resources: ["secrets"]
resourceNames: ["app-secret"] # 只允許存取特定的 Secret
verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: read-app-secret
namespace: default
subjects:
- kind: ServiceAccount
name: app-service-account
namespace: default
roleRef:
kind: Role
name: secret-reader
apiGroup: rbac.authorization.k8s.io
這個 RBAC 設定範例實施了最小許可權原則:
- 建立一個角色,只允許讀取特定的 Secret (app-secret)
- 將該角色繫結到應用程式的服務帳戶
- 服務帳戶只能存取它需要的 Secret,無法存取其他 Secret
在設計機密管理策略時,我建議將機密分解為最小單位,並只向需要的元件提供存取許可權。這種方法可以限制潛在洩露的影響範圍。
Secret 加密
預設情況下,Kubernetes 將 Secret 以 base64 編碼(非加密)的形式儲存在 etcd 中。啟用 Secret 加密是保護敏感資料的關鍵步驟。
# Secret 加密設定
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
providers:
- aescbc:
keys:
- name: key1
secret: <base64-encoded-key>
- identity: {}
這個設定啟用了 Secret 的靜態加密:
- 使用 AES-CBC 加密演算法
- 指定加金鑰
- 包含 identity 提供者作為回退
在生產環境中,我強烈建議啟用 Secret 加密,並考慮使用外部金鑰管理系統(如 AWS KMS 或 HashiCorp Vault)來管理加金鑰。這提供了更強的安全性和更好的金鑰管理。
Kubernetes Secret 儲存
Kubernetes Secret 是儲存和管理敏感資料的原生方式。
# 建立 Secret
apiVersion: v1
kind: Secret
metadata:
name: db-credentials
type: Opaque
data:
username: YWRtaW4= # base64 encoded "admin"
password: cGFzc3dvcmQxMjM= # base64 encoded "password123"
---
# 在 Pod 中使用 Secret
apiVersion: v1
kind: Pod
metadata:
name: app-pod
spec:
containers:
- name: app
image: myapp:1.0.0
env:
- name: DB_USERNAME
valueFrom:
secretKeyRef:
name: db-credentials
key: username
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-credentials
key: password
這個範例展示瞭如何建立和使用 Kubernetes Secret:
- 建立包含資料函式庫憑證的 Secret
- 在 Pod 中將 Secret 資料作為環境變數使用
雖然 Kubernetes Secret 提供了基本的機密管理功能,但它有一些限制:
- 預設情況下未加密(需要額外設定)
- 缺乏高階功能,如版本控制和自動輪換
- 所有具有名稱空間存取許可權的管理員都可以讀取 Secret
對於更高階的機密管理需求,我建議考慮外部解決方案,如 HashiCorp Vault 或雲提供商的機密管理服務。
將機密傳遞給容器化程式碼
有多種方法可以將機密傳遞給容器中的應用程式,每種方法都有其優缺點。
# 使用環境變數
apiVersion: v1
kind: Pod
metadata:
name: env-pod
spec:
containers:
- name: app
image: myapp:1.0.0
env:
- name: API_KEY
valueFrom:
secretKeyRef:
name: api-secret
key: api-key
---
# 使用卷掛載
apiVersion: v1
kind: Pod
metadata:
name: volume-pod
spec:
containers:
- name: app
image: myapp:1.0.0
volumeMounts:
- name: secret-volume
mountPath: /etc/secrets
readOnly: true
volumes:
- name: secret-volume
secret:
secretName: api-secret
這個範例展示了兩種將機密傳遞給容器的方法:
- 環境變數:直接將機密作為環境變數傳遞
- 卷掛載:將機密作為檔案掛載到容器檔案系統
在我的實踐中,我發現卷掛載通常比環境變數更安全,原因如下:
- 環境變數可能出現在日誌或錯誤報告中
- 環境變數對容器中的所有程式可見
- 卷掛載的機密可以設定更嚴格的檔案許可權
- 某些應用程式框架專門支援從檔案讀取機密
機密輪換與復原
定期輪換機密是安全最佳實踐,可以限制潛在洩露的影響。
# 使用 Kubernetes 定時工作 輪換機密
apiVersion: batch/v1beta1
kind: 定時工作
metadata:
name: secret-rotation
spec:
schedule: "0 0 * * 0" # 每週日午夜
jobTemplate:
spec:
template:
spec:
serviceAccountName: secret-manager
containers:
- name: rotate-secrets
image: secret-rotation:1.0.0
command: ["./rotate-secrets.sh"]
restartPolicy: OnFailure
這個 定時工作 設定範例展示瞭如何自動輪換機密:
- 建立一個定期執行的作業
- 使用具有適當許可權的服務帳戶
- 執行機密輪換指令碼
在實際實施中,機密輪換通常涉及以下步驟:
- 生成新的機密值
- 更新使用該機密的服務
- 更新 Kubernetes Secret
- 驗證所有服務是否正常執行
- 復原舊的機密值
對於關鍵系統,我建議實施自動機密輪換,並確保應用程式能夠在不中斷服務的情況下處理機密更改。
高階主題:深入 Kubernetes 安全
監控、警示與稽核
全面的安全策略必須包括監控和稽核,以便及時發現和回應安全事件。
# 設定 Kubernetes 稽核
apiVersion: v1
kind: Pod
metadata:
name: kube-apiserver
namespace: kube-system
spec:
containers:
- name: kube-apiserver
image: k8s.gcr.io/kube-apiserver:v1.21.0
command:
- kube-apiserver
- --audit-log-path=/var/log/kubernetes/audit.log
- --audit-log-maxage=30
- --audit-log-maxbackup=10
- --audit-log-maxsize=100
- --audit-policy-file=/etc/kubernetes/audit-policy.yaml
volumeMounts:
- name: audit-policy
mountPath: /etc/kubernetes/audit-policy.yaml
readOnly: true
- name: audit-log
mountPath: /var/log/kubernetes/
volumes:
- name: audit-policy
hostPath:
path: /etc/kubernetes/audit-policy.yaml
type: File
- name: audit-log
hostPath:
path: /var/log/kubernetes/
type: DirectoryOrCreate
這個設定範例啟用了 Kubernetes 稽核日誌:
- 指定稽核日誌的路徑和保留策略
- 參照稽核策略檔案,定義要記錄的事件
- 設定卷掛載以存取策略檔案和寫入日誌
在我的實踐中,我發現以下監控和稽核策略特別有效:
- 記錄所有認證和授權決策
- 監控異常的 API 呼叫模式
- 跟蹤特權操作和設定更改
- 設定根據異常行為的警示
- 將稽核日誌傳送到中央日誌管理系統
主機安全
容器安全始於主機安全。不安全的主機可能危及所有執行在其上的容器。
# 加固主機安全的基本步驟
# 1. 最小化作業系統
# 2. 定期更新和修補
# 3. 使用主機防火牆
# 4. 實施強化的 Linux 安全模組 (如 SELinux 或 AppArmor)
# 5. 停用不必要的服務
# 6. 實施強密碼策略和 SSH 金鑰認證
# 7. 使用入侵檢測系統
# 8. 監控系統日誌
這些步驟概述了加固 Kubernetes 節點的基本方法:
- 使用最小化的作業系統減少攻擊面
- 保持系統更新以修復已知漏洞
- 使用防火牆限制網路存取
- 啟用 SELinux 或 AppArmor 提供額外的安全層
- 移除不必要的服務和軟體
- 加強身分驗證機制
- 實施監控和入侵檢測
在設計 Kubernetes 安全策略時,我始終強調主機安全的重要性。容器提供了隔離,但不是完美的安全邊界。如果主機被攻破,所有容器都可能受到影響。
沙箱化與執行時保護
容器執行時安全是防止容器逃逸和其他執行時攻擊的關鍵。
# 使用 gVisor 執行容器
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
name: gvisor
handler: runsc
---
apiVersion: v1
kind: Pod
metadata:
name: secure-pod
spec:
runtimeClassName: gvisor
containers:
- name: app
image: myapp:1.0.0
這個設定範例展示瞭如何使用 gVisor 容器執行時沙箱:
- 定義 RuntimeClass 資源,指定 gVisor (runsc) 處理程式
- 在 Pod 規範中參照該 RuntimeClass
容器執行時沙箱(如 gVisor 和 Kata Containers)提供了額外的隔離層,可以顯著減少容器逃逸的風險。在處理不受信任的工作負載或多租戶環境時,我強烈建議考慮這些技術。
多租戶環境
在多租戶 Kubernetes 環境中,安全隔離尤為重要。
# 多租戶隔離策略
# 1. 使用名稱空間隔離租戶
apiVersion: v1
kind: Namespace
metadata:
name: tenant-a
---
# 2. 實施資源配額
apiVersion: v1
kind: ResourceQuota
metadata:
name: tenant-quota
namespace: tenant-a
spec:
hard:
pods: "10"
requests.cpu: "4"
requests.memory: 8Gi
limits.cpu: "8"
limits.memory: 16Gi
---
# 3. 使用網路政策隔離
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: tenant-isolation
namespace: tenant-a
spec:
podSelector: {}
ingress:
- from:
- namespaceSelector:
matchLabels:
tenant: a
這個設定範例展示了多租戶環境中的隔離策略:
- 為每個租戶建立專用名稱空間
- 實施資源配額,防止一個租戶消耗過多資源
- 使用網路政策限制跨租戶通訊
在設計多租戶 Kubernetes 環境時,我建議考慮以下額外措施:
- 使用節點選擇器將不同租戶的工作負載排程到不同的節點
- 為每個租戶實施自定義准入控制器
- 考慮使用容器執行時沙箱提供更強的隔離
- 實施詳細的稽核和監控,跟蹤跨租戶活動
網路保護
網路安全是 Kubernetes 安全的重要組成部分,可以防止未授權存取和橫向移動。
# 預設拒絕所有流量的網路政策
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: production
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
---
# 允許特定流量的網路政策
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-specific-traffic
namespace: production
spec:
podSelector:
matchLabels:
app: web
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 80
egress:
- to:
- podSelector:
matchLabels:
app: database
ports:
- protocol: TCP
port: 5432
這個網路政策設定範例實施了零信任網路模型:
- 首先,預設拒絕所有入站和出站流量
- 然後,明確允許特定的必要流量:
- 允許標記為 “frontend” 的 Pod 存取 Web 服務的 80 連線埠
- 允許 Web 服務存取資料函式庫服務的 5432 連線埠
在設計 Kubernetes 網路安全策略時,我建議採用"預設拒絕,明確允許"的方法。這種方法雖然初始設定更複雜,但提供了更強的安全保障,防止未授權的網路存取和橫向移動。