網絡策略(NetworkPolicy)是一種關於pod間及pod與其他網絡端點間所允許的通信規則的規范。NetworkPolicy 資源使用標簽選擇pod,並定義選定pod所允許的通信規則。
前提
網絡策略通過網絡插件來實現,所以用戶必須使用支持 NetworkPolicy 的網絡解決方案 - 簡單地創建資源對象,而沒有控制器來使它生效的話,是沒有任何作用的。
網絡插件:
- Calico
- Romana
- Weave 網絡
隔離和非隔離的Pod
默認情況下,Pod是非隔離的,它們接受任何來源的流量。Pod可以通過相關的網絡策略進行隔離。一旦命名空間中 NetworkPolicy 配置選擇了特定的Pod,該Pod會拒絕網絡策略所不允許的連接。 (命名空間下其他未被網絡策略所選擇的Pod會繼續接收所有的流量)
NetworkPolicy 資源
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: test-network-policy
namespace: default
spec:
podSelector:
matchLabels:
role: db
policyTypes:
- Ingress
- Egress
ingress:
- from:
- ipBlock:
cidr: 172.17.0.0/16
except:
- 172.17.1.0/24
- namespaceSelector:
matchLabels:
project: myproject
- podSelector:
matchLabels:
role: frontend
ports:
- protocol: TCP
port: 6379
egress:
- to:
- ipBlock:
cidr: 10.0.0.0/24
ports:
- protocol: TCP
port: 5978
除非選擇支持網絡策略的網絡解決方案,否則上面的例子沒有任何效果。
必填字段: 與所有其他的Kubernetes配置一樣,NetworkPolicy 需要 apiVersion、 kind和 metadata 。
spec: NetworkPolicy spec 中包含了在一個命名空間中定義特定網絡策略所需的所有信息.
podSelector: 每個 NetworkPolicy 都包括一個 podSelector ,它對該策略所應用的一組Pod進行選擇。因為 NetworkPolicy 目前只支持定義 ingress 規則,這里的 podSelector 本質上是為該策略定義 "目標pod" 。示例中的策略選擇帶有 "role=db" 標簽的pod。空的 podSelector 選擇命名空間下的所有pod。
policyTypes: 每個 NetworkPolicy 都包含一個 policyTypes 列表,其中包含 Ingress 或 Egress 或兩者兼具。policyTypes 字段表示給定的策略是應用於 進入所選 Pod 的入站流量還是來自所選 Pod 的出站流量,或兩者兼有。 如果 NetworkPolicy 未指定 policyTypes 則默認情況下始終設置 Ingress; 如果 NetworkPolicy 有任何出口規則的話則設置 Egress。
ingress: 每個 NetworkPolicy 包含一個 ingress 規則的白名單列表。(其中的)規則允許同時匹配 from 和 ports 部分的流量。示例策略中包含一條簡單的規則: 它匹配一個單一的端口,來自兩個來源中的一個, 第一個通過 namespaceSelector 指定,第二個通過 podSelector 指定。
egress: 每個 NetworkPolicy 包含一個 egress 規則的白名單列表。每個規則都允許匹配 to 和 port 部分的流量。該示例策略包含一條規則,該規則將單個端口上的流量匹配到 10.0.0.0/24 中的任何目的地。
所以,示例網絡策略:
1.隔離 "default" 命名空間下標簽是 "role=db" 的pod (如果它們不是已經被隔離的話)。
2.(Ingress 規則)允許以下 Pod 連接到 "default" 名字空間下的帶有 "role=db" 標簽的所有 Pod 的 6379 TCP 端口:
- "default" 命名空間下帶有 "role=frontend" 標簽的所有 Pod
- 帶有 "project=myproject" 標簽的所有命名空間中的 Pod
- IP 地址范圍為 172.17.0.0–172.17.0.255 和 172.17.2.0–172.17.255.255(即,除了 172.17.1.0/24 之外的所有 172.17.0.0/16)
3.(Egress 規則)允許從帶有 "role=db" 標簽的命名空間下的任何 Pod 到 CIDR 10.0.0.0/24 下 5978 TCP 端口的連接。
選擇器 to 和 from 的行為
可以在 ingress from 部分或 egress to 部分中指定四種選擇器:
podSelector: 這將在與 NetworkPolicy 相同的命名空間中選擇特定的 Pod,應將其允許作為入口源或出口目的地。
namespaceSelector: 這將選擇特定的命名空間,應將所有 Pod 用作其輸入源或輸出目的地。
namespaceSelector 和 podSelector: 一個指定 namespaceSelector 和 podSelector 的 to/from 條目選擇特定命名空間中的特定 Pod。注意使用正確的YAML語法;
下面的策略,在 from 數組中僅包含一個元素,只允許來自標有 role = client 的 Pod 且該 Pod 所在的命名空間中標有user=alice的連接。
...
ingress:
- from:
- namespaceSelector:
matchLabels:
user: alice
podSelector:
matchLabels:
role: client
...
這項策略,在 from 數組中包含兩個元素,允許來自本地命名空間中標有 role = client 的 Pod 的連接,或來自任何命名空間中標有user = alice的任何Pod的連接。
...
ingress:
- from:
- namespaceSelector:
matchLabels:
user: alice
- podSelector:
matchLabels:
role: client
...
ipBlock: 這將選擇特定的 IP CIDR 范圍以用作入口源或出口目的地。 這些應該是群集外部 IP,因為 Pod IP 存在時間短暫的且隨機產生。
群集的入口和出口機制通常需要重寫數據包的源 IP 或目標 IP。在發生這種情況的情況下,不確定在 NetworkPolicy 處理之前還是之后發生,並且對於網絡插件,雲提供商,Service 實現等的不同組合,其行為可能會有所不同。
在進入的情況下,這意味着在某些情況下,您可以根據實際的原始源 IP 過濾傳入的數據包,而在其他情況下,NetworkPolicy 所作用的 源IP 則可能是 LoadBalancer 或 Pod的節點等。
對於出口,這意味着從 Pod 到被重寫為集群外部 IP 的 Service IP 的連接可能會或可能不會受到基於 ipBlock 的策略的約束。
默認策略
默認情況下,如果命名空間中不存在任何策略,則所有進出該命名空間中的Pod的流量都被允許。以下示例使您可以更改該命名空間中的默認行為。
默認拒絕所有入口流量
創建選擇所有容器但不允許任何進入這些容器的入口流量的 NetworkPolicy 來為命名空間創建 "default" 隔離策略。
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny # 沒有設置命令空間則默認命令空間為default
spec:
podSelector: {} # 空的 podSelector 選擇命名空間下的所有pod
policyTypes: # 入口網絡策略
- Ingress
# 未設置進入條件,也就是不允許任何進入
這樣可以確保即使容器沒有選擇其他任何 NetworkPolicy,也仍然可以被隔離。此策略不會更改默認的出口隔離行為。
默認允許所有入口流量
如果要允許所有流量進入某個命名空間中的所有 Pod(即使添加了導致某些 Pod 被視為“隔離”的策略),則可以創建一個策略來明確允許該命名空間中的所有流量。
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-all
spec:
podSelector: {}
ingress: # 未設置進入來源的限制條件
- {}
policyTypes: # 入口網絡策略
- Ingress
默認拒絕所有出口流量
您可以通過創建選擇所有容器但不允許來自這些容器的任何出口流量的 NetworkPolicy 來為命名空間創建 "default" egress 隔離策略。
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny
spec:
podSelector: {} # 該命名空間下的所有pod
policyTypes: # 出口網絡策略
- Egress
# 未設置出口條件,也就是不允許任何出口流量
這樣可以確保即使沒有被其他任何 NetworkPolicy 選擇的 Pod 也不會被允許流出流量。此策略不會更改默認的 ingress 隔離行為。
默認允許所有出口流量
如果要允許來自命名空間中所有 Pod 的所有流量(即使添加了導致某些 Pod 被視為“隔離”的策略),則可以創建一個策略,該策略明確允許該命名空間中的所有出口流量。
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-all
spec:
podSelector: {}
egress:
- {}
policyTypes:
- Egress
默認拒絕所有入口和所有出口流量
可以為命名空間創建 "default" 策略,以通過在該命名空間中創建以下 NetworkPolicy 來阻止所有入站和出站流量.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
這樣可以確保即使沒有被其他任何 NetworkPolicy 選擇的 Pod 也不會被允許進入或流出流量。
SCTP 支持
Kubernetes 支持 SCTP 作為 NetworkPolicy 定義中的協議值作為 alpha 功能提供。要啟用此功能,集群管理員需要在 apiserver 上啟用 SCTPSupport 功能門,例如 “--feature-gates=SCTPSupport=true,...”。啟用功能門后,用戶可以將 NetworkPolicy 的 protocol 字段設置為 SCTP。 Kubernetes 相應地為 SCTP 關聯設置網絡,就像為 TCP 連接一樣。
CNI插件必須在 NetworkPolicy 中將 SCTP 作為 protocol 值支持。
NetworkPolicy網絡策略入門例子
首先需要有一個支持網絡策略的 Kubernetes 集群。已經有許多支持 NetworkPolicy 的網絡提供商,包括:
- Calico
- Romana
- Weave 網絡
注意:以上列表是根據產品名稱按字母順序排序,而不是按推薦或偏好排序。下面示例對於使用了上面任何提供商的 Kubernetes 集群都是有效的
創建一個nginx deployment 並且通過服務將其暴露
為了查看 Kubernetes 網絡策略是怎樣工作的,可以從創建一個nginx deployment 並且通過服務將其暴露開始
$ kubectl run nginx --image=nginx --replicas=2
deployment "nginx" created
$ kubectl expose deployment nginx --port=80
service "nginx" exposed
在 default 命名空間下運行了兩個 nginx pod,而且通過一個名字為 nginx 的服務進行了暴露
$ kubectl get svc,pod
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
svc/kubernetes 10.100.0.1 <none> 443/TCP 46m
svc/nginx 10.100.0.16 <none> 80/TCP 33s
NAME READY STATUS RESTARTS AGE
po/nginx-701339712-e0qfq 1/1 Running 0 35s
po/nginx-701339712-o00ef 1/1 Running 0 35s
測試服務能夠被其它的 pod 訪問
從其它的 pod 訪問這個新的 nginx 服務。為了驗證它,從 default 命名空間下的其它 pod 來訪問該服務。請您確保在該命名空間下沒有執行孤立動作。
啟動一個 busybox 容器,然后在容器中使用 wget 命令去訪問 nginx 服務:
$ kubectl run busybox --rm -ti --image=busybox /bin/sh
Waiting for pod default/busybox-472357175-y0m47 to be running, status is Pending, pod ready: false
Hit enter for command prompt
/ # wget --spider --timeout=1 nginx
Connecting to nginx (10.100.0.16:80)
/ #
限制訪問 nginx 服務
想限制 nginx 服務,只讓那些擁有標簽 access: true 的 pod 訪問它,那么您可以創建一個只允許從那些 pod 連接的 NetworkPolicy:
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: access-nginx
spec:
podSelector:
matchLabels:
run: nginx
ingress:
- from:
- podSelector:
matchLabels:
access: "true"
為服務指定策略
使用 kubectl 工具根據上面的 nginx-policy.yaml 文件創建一個 NetworkPolicy:
$ kubectl create -f nginx-policy.yaml
networkpolicy "access-nginx" created
當訪問標簽沒有定義時測試訪問服務
如果您嘗試從沒有設定正確標簽的 pod 中去訪問 nginx 服務,請求將會超時:
$ kubectl run busybox --rm -ti --image=busybox /bin/sh
Waiting for pod default/busybox-472357175-y0m47 to be running, status is Pending, pod ready: false
Hit enter for command prompt
/ # wget --spider --timeout=1 nginx
Connecting to nginx (10.100.0.16:80)
wget: download timed out
/ #
定義訪問標簽后再次測試
創建一個擁有正確標簽的 pod,您將看到請求是被允許的:
$ kubectl run busybox --rm -ti --labels="access=true" --image=busybox /bin/sh
Waiting for pod default/busybox-472357175-y0m47 to be running, status is Pending, pod ready: false
Hit enter for command prompt
/ # wget --spider --timeout=1 nginx
Connecting to nginx (10.100.0.16:80)
/ #
