當企業將應用程式遷移到 Kubernetes 環境時,網路安全往往是最容易被忽略卻又最為關鍵的環節。在預設配置下,Kubernetes 叢集內的所有 Pod 都可以自由地相互通訊,這種完全開放的網路架構雖然簡化了開發流程,卻也為攻擊者提供了橫向移動的絕佳機會。一旦攻擊者成功滲透進入叢集內部的任何一個 Pod,就能輕易地探測並攻擊其他服務,包括資料庫、內部 API 與敏感的後端系統。Network Policy 機制的引入徹底改變了這個局面,它允許管理者以宣告式的方式定義 Pod 之間的通訊規則,實現微分隔架構與零信任網路的安全理念。
建構網路策略環境基礎
在開始設定網路策略之前,必須確保 Kubernetes 叢集使用的 CNI 插件支援 Network Policy API。許多開發環境預設使用的 CNI 實作並不支援網路策略功能,例如某些版本的 flannel 或基本的 bridge 模式。在 minikube 環境中,可以透過啟用 Cilium 插件來獲得網路策略支援。對於使用 KinD 建立的開發叢集,則需要在叢集配置中停用預設 CNI,然後手動安裝 Calico 或 Cilium 等支援網路策略的 CNI 提供者。生產環境的選擇則更為多樣,主流的雲端服務供應商通常提供原生支援網路策略的 CNI 實作。
建立測試環境時,我們可以透過兩個命名空間來模擬典型的多層應用程式架構。第一個命名空間 webapp 用於部署前端應用程式,第二個命名空間 database 則用於部署資料庫服務。這種命名空間的劃分不僅符合應用程式的邏輯分層,也為後續的網路隔離提供了清晰的邊界。在 webapp 命名空間中部署一個 Nginx Web 伺服器,並透過 Service 資源暴露 80 連接埠。在 database 命名空間中部署 PostgreSQL 資料庫實例,需要特別注意的是,在生產環境中絕對不應該使用環境變數的方式傳遞資料庫密碼,而應該使用 Kubernetes Secret 配合適當的存取控制機制。
為了驗證預設情況下的網路連通性,可以在 default 命名空間中啟動一個包含網路診斷工具的容器。這個容器應該包含 curl 與 nmap 等工具,用於測試 HTTP 連線與連接埠掃描。從這個測試容器中,能夠成功存取 webapp 命名空間的 Nginx 服務,也能透過 nmap 掃描到 database 命名空間中 PostgreSQL 監聽的 5432 連接埠。這個測試結果清楚地展示了 Kubernetes 預設的網路模型,也就是所有 Pod 之間都可以自由通訊,不受命名空間邊界的限制。
@startuml
!define PLANTUML_FORMAT svg
!theme _none_
skinparam dpi auto
skinparam shadowing false
skinparam linetype ortho
skinparam roundcorner 5
skinparam defaultFontName "Microsoft JhengHei UI"
skinparam defaultFontSize 14
skinparam minClassWidth 100
package "default 命名空間" {
component [測試容器\nclient] as Client
}
package "webapp 命名空間" {
component [Nginx\ntestwebapp] as WebApp
}
package "database 命名空間" {
component [PostgreSQL\ntestdb] as Database
}
Client --> WebApp : HTTP 80\n完全允許
Client --> Database : PostgreSQL 5432\n完全允許
WebApp --> Database : PostgreSQL 5432\n完全允許
note right of Client
預設情況下
所有 Pod 可自由通訊
無任何網路限制
end note
@enduml實施預設拒絕策略
網路安全強化的第一步是實施預設拒絕策略,這是零信任架構的核心原則。透過在每個命名空間中套用一個空的 podSelector 與 Ingress 策略類型,可以阻止所有進入該命名空間的流量。這個策略不需要定義任何 ingress 規則,空的策略配置就代表拒絕所有入站連線。當這個預設拒絕策略套用到 webapp 與 database 命名空間後,先前能夠成功存取的服務都會開始出現連線逾時或被拒絕的情況。
---
# Webapp 命名空間的預設拒絕策略
# 此策略會阻止所有進入 webapp 命名空間的流量
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
# 策略名稱,建議使用描述性的命名
name: deny-all-ingress
# 目標命名空間
namespace: webapp
spec:
# 空的 podSelector 表示選擇此命名空間中的所有 Pod
# 這確保策略套用到命名空間內的每個工作負載
podSelector: {}
# policyTypes 定義此策略影響的流量方向
# Ingress 表示控制進入 Pod 的流量
policyTypes:
- Ingress
# 注意:此處刻意不定義任何 ingress 規則
# 空的規則集合代表拒絕所有入站流量
# 這是實施零信任架構的基礎配置
---
# Database 命名空間的預設拒絕策略
# 保護資料庫服務不受未授權存取
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-all-ingress
namespace: database
spec:
podSelector: {}
policyTypes:
- Ingress
套用預設拒絕策略後,叢集的安全態勢獲得了顯著提升,但同時也阻斷了所有合法的服務通訊。接下來需要根據應用程式的實際需求,逐一定義允許的流量規則。這種白名單方式雖然需要更多的前期規劃工作,但能確保只有明確授權的通訊路徑才會被開放,大幅降低了攻擊面。
精細化的存取控制策略
為了讓 webapp 命名空間中的應用程式能夠存取 database 命名空間的資料庫服務,需要建立一個允許特定流量的網路策略。首先為 webapp 命名空間添加一個標籤,這個標籤將作為網路策略中的選擇器條件。透過 namespaceSelector 機制,可以基於命名空間的標籤來定義流量來源,而不是直接使用命名空間的名稱,這種做法提供了更好的彈性與可維護性。
---
# 允許 webapp 存取資料庫的網路策略
# 此策略套用在 database 命名空間,控制誰可以進入
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
# 策略名稱應清楚說明其用途
name: allow-webapp-to-database
# 套用在資料庫命名空間
namespace: database
spec:
# 空的 podSelector 表示此策略套用到 database 命名空間的所有 Pod
podSelector: {}
# 定義策略類型為入口流量控制
policyTypes:
- Ingress
# ingress 區塊定義允許的流量規則
ingress:
# 第一條規則:允許來自 webapp 命名空間的流量
- from:
# 使用 namespaceSelector 選擇來源命名空間
# 這比直接使用命名空間名稱更靈活
- namespaceSelector:
matchLabels:
# 只允許具有 tier: webapp 標籤的命名空間
# 這個標籤需要事先透過 kubectl label 命令添加
tier: webapp
# ports 區塊定義允許的連接埠與協定
ports:
# 允許 TCP 協定的 5432 連接埠
# 這是 PostgreSQL 的預設連接埠
- protocol: TCP
port: 5432
這個網路策略的設計體現了最小權限原則,它僅允許來自 webapp 命名空間的流量存取資料庫的 5432 連接埠。其他命名空間的 Pod,包括 default 命名空間中的測試容器,都無法存取資料庫服務。這種精細的控制機制確保即使攻擊者成功入侵了叢集中的某個 Pod,也無法輕易地橫向移動到資料庫層。
套用這個策略後的測試結果應該會顯示,從 default 命名空間的測試容器仍然無法存取資料庫,但在 webapp 命名空間中啟動的容器則能夠成功連線到 PostgreSQL 服務。這個行為正是我們期望的安全態勢,只有應用層的服務能夠存取資料層,其他來源的連線都會被阻擋。
@startuml
!define PLANTUML_FORMAT svg
!theme _none_
skinparam dpi auto
skinparam shadowing false
skinparam linetype ortho
skinparam roundcorner 5
skinparam defaultFontName "Microsoft JhengHei UI"
skinparam defaultFontSize 14
skinparam minClassWidth 100
package "default 命名空間" {
component [測試容器\nclient] as Client
}
package "webapp 命名空間\n(tier: webapp)" {
component [Nginx\ntestwebapp] as WebApp
}
package "database 命名空間" {
component [PostgreSQL\ntestdb] as Database
note right of Database
套用網路策略:
allow-webapp-to-database
end note
}
Client -[#red]x Database : PostgreSQL 5432\n<font color=red>被拒絕</font>
WebApp -[#green]-> Database : PostgreSQL 5432\n<font color=green>允許通過</font>
note bottom of Client
預設拒絕策略生效
僅允許來自 webapp 的流量
end note
@enduml出口流量的安全控制
網路策略不僅能控制進入 Pod 的流量,也能限制 Pod 對外發起的連線。這在防範資料外洩與阻止惡意程式回連攻擊者伺服器時特別重要。一個常見的安全風險是容器能夠存取雲端環境的元資料服務,這個服務通常位於固定的 IP 位址 169.254.169.254,提供了實例的認證資訊、角色權限等敏感資料。透過 Egress 策略可以明確阻止對這個特定 IP 的存取。
---
# 阻止存取雲端元資料服務的出口策略
# 保護敏感的實例認證資訊不被竊取
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: block-metadata-service
namespace: webapp
spec:
# 選擇此命名空間中的所有 Pod
podSelector: {}
# 定義策略類型為出口流量控制
policyTypes:
- Egress
# egress 區塊定義允許的出站流量
egress:
- to:
# 使用 ipBlock 定義允許存取的 IP 範圍
- ipBlock:
# 0.0.0.0/0 代表所有 IP 位址
# 這是一個寬鬆的基準設定
cidr: 0.0.0.0/0
# except 區塊定義例外的 IP 範圍
# 這些 IP 即使在 cidr 範圍內也會被拒絕
except:
# 169.254.169.254/32 是雲端元資料服務的位址
# AWS、Azure、GCP 等主流雲端都使用這個位址
# 阻止存取這個位址可防止認證資訊洩露
- 169.254.169.254/32
這個策略採用了「允許大多數,拒絕特定」的模式,允許 Pod 存取幾乎所有的外部位址,但明確排除了元資料服務。在更嚴格的安全環境中,可能會採用相反的做法,預設拒絕所有出站流量,只允許存取特定的外部服務或 IP 範圍。選擇哪種模式取決於應用程式的特性與企業的安全政策。
Cilium 的進階網路策略功能
標準的 Kubernetes Network Policy 雖然已經提供了基本的流量控制能力,但在某些進階場景中仍顯得不足。Cilium 作為基於 eBPF 技術的 CNI 提供者,擴充了許多強大的網路策略功能,其中最實用的是基於 DNS 名稱的存取控制。傳統的網路策略只能基於 IP 位址或標籤選擇器來定義規則,但許多外部服務的 IP 位址是動態變化的,使用 IP 位址控制變得不切實際。Cilium 允許直接使用 FQDN 來定義允許存取的目標,大幅簡化了策略配置。
---
# Cilium 網路策略:允許存取特定網域
# 展示基於 DNS 名稱的進階流量控制
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: allow-google-access
namespace: webapp
spec:
# endpointSelector 選擇此策略套用的端點
# 空的選擇器表示命名空間中的所有端點
endpointSelector: {}
# egress 定義出站流量規則
egress:
# 第一條規則:允許 DNS 查詢
# 這是基於 FQDN 策略的前提條件
- toEndpoints:
# 選擇 kube-system 命名空間中的 DNS 服務
- matchLabels:
io.kubernetes.pod.namespace: kube-system
k8s-app: kube-dns
toPorts:
# 允許 UDP 53 連接埠(DNS 查詢)
- ports:
- port: "53"
protocol: UDP
# dns 區塊定義允許查詢的網域模式
rules:
dns:
# 允許查詢任何網域名稱
# 實務上應該限制為特定的網域模式
- matchPattern: "*"
# 第二條規則:允許存取特定 FQDN
- toFQDNs:
# matchPattern 支援萬用字元
# 這裡允許存取所有 google.com 的子網域
- matchPattern: "*.google.com"
toPorts:
# 允許 HTTPS 與 HTTP 連接埠
- ports:
- port: "443"
protocol: TCP
- port: "80"
protocol: TCP
Cilium 還提供了 CiliumClusterwideNetworkPolicy 資源,允許定義不受命名空間限制的叢集範圍策略。這對於建立組織層級的基準安全政策特別有用,例如阻止所有工作負載對外部網際網路的直接存取,或是強制所有出站流量都必須經過代理伺服器。這種叢集範圍的策略會先於命名空間層級的策略被評估,提供了一個統一的安全基準線。
---
# Cilium 叢集範圍網路策略
# 在整個叢集層級實施基準安全控制
apiVersion: cilium.io/v2
kind: CiliumClusterwideNetworkPolicy
metadata:
# 叢集範圍策略不屬於任何命名空間
name: cluster-baseline-security
spec:
# 空的 endpointSelector 表示套用到叢集中的所有端點
endpointSelector: {}
# ingressDeny 定義預設拒絕的入站流量
ingressDeny:
# 拒絕所有來自外部世界的流量
- fromEntities:
# "world" 代表叢集外部的所有實體
- "world"
# ingress 定義允許的入站流量
ingress:
# 允許來自叢集內所有實體的流量
- fromEntities:
# "all" 包含叢集內的所有 Pod 與主機
- "all"
Calico 的網路策略增強功能
Calico 是另一個廣受歡迎的 CNI 提供者,它同樣擴充了標準的 Kubernetes Network Policy API。Calico 最具特色的功能之一是能夠記錄被網路策略阻止或允許的流量,這對於安全事件調查與策略除錯都極為有用。透過在策略規則中加入 Log 動作,所有符合該規則的流量都會被記錄到系統日誌中,管理者可以透過分析這些日誌來了解實際的流量模式,進而優化網路策略配置。
---
# Calico 網路策略:流量記錄與控制
# 展示如何記錄網路流量以協助安全稽核
apiVersion: projectcalico.org/v3
kind: NetworkPolicy
metadata:
name: webapp-logging-policy
namespace: webapp
spec:
# 定義入站流量規則
ingress:
# 第一條規則:記錄所有 TCP 80 連接埠的流量
# Log 動作不會影響流量的允許或拒絕
- action: Log
protocol: TCP
destination:
ports:
- 80
# 第二條規則:允許 TCP 80 連接埠的流量
# 注意:Calico 策略是依序評估的
# 先記錄再允許,確保所有流量都被記錄
- action: Allow
protocol: TCP
destination:
ports:
- 80
Calico 的策略語法相較於標準 Kubernetes Network Policy 更為豐富,支援更精細的規則定義。例如可以基於服務帳戶、Pod 的特定標籤組合,甚至是流量的方向性來定義規則。這種靈活性讓管理者能夠實施更複雜的安全策略,例如只允許具有特定服務帳戶的 Pod 存取敏感資源,或是根據流量的來源與目的地組合來決定是否允許通訊。
工作負載安全上下文強化
網路策略雖然能有效控制 Pod 之間的通訊,但完整的安全防護還需要配合工作負載層級的安全強化。Kubernetes 提供的 Security Context 機制允許管理者在 Pod 或容器層級設定各種安全相關的屬性。例如可以要求容器以非 root 使用者執行、禁止特權模式、限制 Linux Capabilities 的使用,以及設定 SELinux 或 AppArmor 的安全標籤。這些設定雖然不直接涉及網路流量控制,但能夠限制容器的行為能力,降低容器逃逸或權限提升的風險。
@startuml
!define PLANTUML_FORMAT svg
!theme _none_
skinparam dpi auto
skinparam shadowing false
skinparam linetype ortho
skinparam roundcorner 5
skinparam defaultFontName "Microsoft JhengHei UI"
skinparam defaultFontSize 14
skinparam minClassWidth 100
package "Kubernetes 安全防護體系" {
component "網路層防護" as Network {
[Network Policy]
[CNI 擴充功能]
}
component "CNI 提供者" as CNI {
[Cilium]
[Calico]
}
component "工作負載安全" as Workload {
[Security Context]
[Pod Security Standards]
}
component "准入控制" as Admission {
[OPA Gatekeeper]
[Kyverno]
}
[Network Policy] --> [CNI 擴充功能]
[CNI 擴充功能] --> [Cilium]
[CNI 擴充功能] --> [Calico]
[Security Context] --> [Pod Security Standards]
[Pod Security Standards] --> [OPA Gatekeeper]
[Pod Security Standards] --> [Kyverno]
Network -down-> Workload : 互補防護
Workload -down-> Admission : 策略強制執行
}
note right of Network
控制 Pod 間的
網路通訊流量
end note
note right of Workload
限制容器的
執行權限與能力
end note
note right of Admission
確保工作負載
符合安全標準
end note
@endumlPod Security Standards 是 Kubernetes 引入的新機制,用於取代已被廢棄的 PodSecurityPolicy。這個標準定義了三個層級的安全要求:Privileged 層級不施加任何限制、Baseline 層級提供基本的安全防護、Restricted 層級則實施最嚴格的安全限制。管理者可以在命名空間層級設定這些標準,確保該命名空間中的所有 Pod 都符合指定的安全要求。對於需要更細緻控制的場景,OPA Gatekeeper 或 Kyverno 等准入控制器提供了更強大的策略定義能力,能夠實施複雜的多條件驗證規則。
在企業環境中實施 Kubernetes 網路安全時,建議採用分層防禦的策略。首先在網路層透過 Network Policy 實施微分隔,確保只有必要的通訊路徑被開放。然後在工作負載層透過 Security Context 限制容器的能力,即使攻擊者成功入侵也難以進行權限提升。最後透過准入控制器強制執行安全標準,確保所有部署到叢集的工作負載都符合組織的安全政策。這三個層次相互配合,共同建構起完整的防禦體系。
透過合理運用 Kubernetes 提供的網路策略機制,配合 Cilium 或 Calico 等 CNI 提供者的進階功能,企業能夠在享受容器化帶來的敏捷性與彈性的同時,也建立起符合零信任原則的網路安全架構。從預設拒絕到精細化的存取控制,從基於標籤的策略到基於 DNS 的規則,這些機制提供了豐富的工具來應對各種安全需求。配合工作負載安全上下文的強化與准入控制的策略執行,Kubernetes 叢集能夠達到企業級的安全防護水準,有效抵禦來自內部與外部的各種威脅。