1. 程式人生 > 其它 >保障叢集內節點和網路安全

保障叢集內節點和網路安全

在 pod 中使用宿主節點的 Linux 名稱空間

pod 中的容器通常在分開的 Linux 名稱空間中執行。 這些名稱空間將容器中的程序與其他容器中,或者宿主機預設名稱空間中的程序隔離開來。
例如,每一個 pod 有自己的 IP 和埠空間,這是因為它擁有自己的網路名稱空間。類似地,每一個 pod 擁有自己的程序樹,因為它有自己的 PID 名稱空間 。同樣地 pod 擁有自己的 IPC 名稱空間,僅允許同一 pod 內的程序通過程序間通訊 (InterProcess Communication, 簡稱IPC) 機制進行交流。

在 pod 中使用宿主節點的網路名稱空間

部分 pod (特別是系統 pod ) 需要在宿主節點的預設名稱空間中執行,以允許它們看到和操作節點級別的資源和裝置。例如,某個 pod 可能需要使用宿主節點上的網路介面卡,而不是自己的虛擬網路裝置。這可以通過將 pod spec 中的 hostNetwork 設定為true實現。

     spec.hostNetwork:true

在這種情況下,這個 pod 可以使用宿主節點的網路介面,而不是擁有自己獨立的網路。這意味著這個 pod 沒有自己的IP地址;如果這個 pod 中的某一程序綁定了某個埠,那麼該程序將被繫結到宿主節點的埠上。

vim pod-with-host-network.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-with-host-network
spec:
  hostNetwork: true    # 使用宿主機節點的網路名稱空間
  containers:
  - name: main
    image: alpine
    command: ["/bin/sleep", "999999"]


kubectl  exec  pod-with-host-network ifconfig 
docker0   Link encap:Ethernet  HWaddr 02:42:8D:D4:A6:6B  
          inet addr:172.17.0.1  Bcast:172.17.255.255  Mask:255.255.0.0
...

ens33     Link encap:Ethernet  HWaddr 00:0C:29:5F:F0:DB  
          inet addr:192.168.160.135  Bcast:192.168.160.255  Mask:255.255.255.0
          inet6 addr: fe80::494b:af17:216a:3ef0/64 Scope:Link
...

flannel.1 Link encap:Ethernet  HWaddr B6:87:54:A6:FA:9F  
          inet addr:10.244.1.0  Bcast:10.244.1.0  Mask:255.255.255.255
...

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
...

繫結宿主節點上的埠而不使用宿主節點的網路名稱空間

一個與此有關的功能可以讓 pod 在擁有自己的網路名稱空間的同時,將埠繫結到宿主節點的埠上。這可以通過配置 pod 的 spec.containers.ports 欄位中某個容器某一埠的 hostPort 屬性來實現。
不要混淆使用 hostPort 的 pod 和通過 NodePort 服務暴露的 pod ,它們是不同的。

對於一個使用 hostPort 的 pod,到達宿主節點的埠的連線會被直接轉發到 pod 的對應埠上;
然而在 NodePort 服務中,到達宿主節點的埠的連線將被轉發到隨機選取的 pod 上(這個 pod 可能在其他節點上);
另外一個區別是,對於使用 hostPort 的 pod ,僅有運行了這類 pod 的節點會繫結對應的埠;而 NodePort 型別的服務會在所有的節點上繫結埠,即使這個節點上沒有執行對應的 pod (如圖中所示的節點3)。

很重要的一點是,如果一個 pod 綁定了宿主節點上的一個特定埠,每個宿主節點只能排程一個這樣的 pod 例項,因為兩個程序不能繫結宿主機上的同一個埠。排程器在排程 pod 時會考慮這一點, 所以它不會把兩個這樣的 pod 排程到同一個節點上。
如果要在3個節點上部署4個這樣的 pod 副本,只有3個副能夠成功部署(剩餘1個pod 保持Pending 狀態)

vim kubia-hostport.yaml
apiVersion: v1
kind: Pod
metadata:
  name: kubia-hostport
spec:
  containers:
  - image: luksa/kubia
    name: kubia
    ports:
    - containerPort: 8080  # 該容器可以通過 pod IP 的8080埠訪問
      hostPort: 9000   # 也可以通過所在節點的9000埠訪問
      protocol: TCP


kubectl  get pod -o wide 
kubia-hostport   1/1     Running   0          10m   10.244.1.7   node1   <none>           <none>
curl http://10.244.1.7:8080 
You've hit kubia-hostport
curl http://192.168.160.135:9000   node1IP
You've hit kubia-hostport

使用宿主節點的 PIO IPC 名稱空間

pod spec 中的 hostPID 和 hostIPC 選項與 hostNetwork 相似。當它們被設定為 true 時, pod 中的容器會使用宿主節點的 PID 和 IPC 名空間 ,分別允許它們看到宿主機上的全部程序,或通過 IPC 機制與它們通訊。

vim pod-with-host-pid-and-ipc.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-with-host-pid-and-ipc
spec:
  hostPID: true
  hostIPC: true
  containers:
  - name: main
    image: alpine
    command: ["/bin/sleep", "999999"]
	
[root@master aq]# kubectl  exec pod-with-host-pid-and-ipc ps aux 
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
PID   USER     TIME  COMMAND
    1 root      0:03 /usr/lib/systemd/systemd --switched-root --system --deserialize 22
    2 root      0:00 [kthreadd]
    3 root      0:00 [ksoftirqd/0]
    5 root      0:00 [kworker/0:0H]
    7 root      0:00 [migration/0]
...

將 hostIPC 設定為 true,pod 中的程序就可以通過程序間通訊機制與宿上的其他所有程序進行通訊。

配置節點的安全上下文

除了讓 pod 使用宿主節點的 Linux 名稱空間,還可以在 pod 或其所屬容器的描述中通過 security-Context 邊項配置其他與安全性相關的特性。這個選項可以運用於整個 pod ,或者每個 pod 中單獨的容器。
瞭解安全上下文中可以配置的內容
配置安全上下文可以允許你做很多事

  • 指定容器中執行程序的使用者(使用者 ID )
  • 阻止容器使用 root 使用者執行(容器的預設執行使用者通常在其映象中指定,所以可能需要阻止容器 root 使用者執行)
  • 使用特權模式執行容器,使其對宿主節點的核心具有完全的訪問許可權
  • 與以上相反,通過新增或禁用核心功能,配置細粒度的核心訪問許可權
  • 設定SELinux( Security Enhaced Linux, 安全增強型 Linux )選項,加強對容器的限制。
  • 阻止程序寫入容器的根檔案系統

執行 pod 而不配置安全上下文

kubectl run pod-with-defaults --image alp ine --restart Never  -- /bin/sleep 999999 
pod/pod-with-defaults created

kubectl  exec pod-with-defaults id 
uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)

這個容器在使用者 ID (uid )為0的使用者,即 root ,使用者組 ID (gid )為 0(同樣是 root )的使用者組下執行。它同樣還屬於一些其他的使用者組。

注意: #F44336 容器執行時使用的使用者在映象中指定 Dockerfile 中,這是通過使用 USER 命令實現的。 如果該命令被省略,容器將使用 root 使用者執行。

使用指定使用者執行容器

為了使用一個與映象中不同的使用者 ID 來執行 pod, 需要 設定該 podsecurityContext.runAsUser 選項。可以通過以下程式碼清單來執行一個使用 guest 使用者執行的容器,該使用者在 alpine 映象中的使用者 ID 405。

vim pod-as-user-guest.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-as-user-guest
spec:
  containers:
  - name: main
    image: alpine
    command: ["/bin/sleep", "999999"]
    securityContext:
      runAsUser: 405         # 需要指明一個使用者ID,而不是使用者名稱(id 405 對應 guest使用者)
	  
kubectl  exec pod-as-user-guest id 
uid=405(guest) gid=100(users)

阻止容器以 root 使用者執行

假設有一個己經部署好的 pod,它使用一個在 Dockefie 使用 USER daemon 命令製作的映象,使其在 daemon 使用者下執行。 如果攻擊者獲取了訪問映象倉庫的許可權, 並上傳了一個標籤完全相同,在 root 使用者下執行的映象,會發生什麼?當Kubernetes 的排程器執行該 pod 的新例項時,kubelet 會下載攻擊者的映象, 並執行該映象中的任何程式碼。
雖然容器與宿主節點基本上是隔離的,使用 root 使用者執行容器中的程序仍然是一種不好的實踐。 例如,當宿主節點上的一個目錄被掛載到容器中時,如果這個容器中的程序使用了 root 使用者執行,它就擁有該目錄的完整訪問許可權; 如果用非 root使用者執行,則沒有完整許可權。
為了防止以上的攻擊場景發生,可以進行配置,使得 pod 中的容器以非 root 使用者執行。

vim pod-run-as-non-root.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-run-as-non-root
spec:
  containers:
  - name: main
    image: alpine
    command: ["/bin/sleep", "999999"]
    securityContext:
      runAsNonRoot: true     # 這個容器只允許以非 root 使用者執行

部署這個 pod 之後,它會被成功排程,但是不允許執行:

kubectl  get pod pod-run-as-non-root 
NAME                  READY   STATUS                       RESTARTS   AGE
pod-run-as-non-root   0/1     CreateContainerConfigError   0          85s

使用特權模式執行 pod

有時 pod 需要做它們的宿主節點上能夠做的任何事,例如操作被保護的系統裝置,或使用其他在通常容器中不能使用的核心功能。這種 pod 的一個樣例就是 kube-proxy pod ,修改宿主機的 iptables 來讓 uberne es 中的服務規 生效。
為獲取宿主機核心的完整許可權,該 pod 需要在特權模式下執行。這可以通過將容器的 securityContext 中的 privileged 設定為 true 實現 。(給予容器無限力量)

vim pod-privileged.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-privileged
spec:
  containers:
  - name: main
    image: alpine
    command: ["/bin/sleep", "999999"]
    securityContext:
      privileged: true      # 這個容器將在特權模式下執行

/dev 是特殊目錄,該目錄包含系統中所有裝置對應的裝置檔案,這些檔案不是磁碟上的常規檔案,而是用於與裝置通訊的特殊檔案 。

為容器單獨新增核心功能

一個更加安全的做法是隻給予它使用真正需要的核心功能的許可權。 Kubernetes允許為特定的容器新增核心功能, 或禁用部分核心功能, 以允許對容器進行 更加精細的許可權控制, 限制攻擊者潛在侵入的影響。
例如 一個容器通常不允許修改系統時間(硬體時鐘的時間)。 可以通過在 pod-with-defaults pod 中修改設定時間來驗證:

[root@master anquan]# kubectl  exec -it  pod-as-user-guest  -- date 
Thu Jan 20 10:42:59 UTC 2022
[root@master anquan]# kubectl  exec -it  pod-as-user-guest  -- date +%T -s "12:00:00"
date: can't set date: Operation not permitted
12:00:00
[root@master anquan]# kubectl  exec -it  pod-as-user-guest  -- date 
Thu Jan 20 10:43:25 UTC 2022

如果需要允許容器修改系統時間,可以在容器的 capbilities 裡 add 一項名為 CAP_SYS_TIME 的功能

vim pod-add-settime-capability.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-add-settime-capability
spec:
  containers:
  - name: main
    image: alpine
    command: ["/bin/sleep", "999999"]
    securityContext:
      capabilities:      # 在核心功能 securityContext 中新增或禁用
        add:
        - SYS_TIME   # 在這裡添加了 SYS_TIME 功能

注意: #F44336 Linux核心功能的名稱通常以CAP_開頭。但在podspec中指定核心功能時,必須省略CAP_字首。

[root@master anquan]# kubectl  exec -it pod-add-settime-capability --  date 
Thu Jan 20 10:50:58 UTC 2022
[root@master anquan]# kubectl  exec -it pod-add-settime-capability --  date +%T -s "12:00:00" 
12:00:00
[root@master anquan]# kubectl  exec -it pod-add-settime-capability --  date 
Thu Jan 20 12:00:01 UTC 2022

在容器中禁用核心功能

也可以禁用容器中的核心功能。
例如,預設情況下容器擁有CAP_CHOWN許可權,允許程序修改檔案系統中檔案的所有者。

[root@master anquan]# kubectl  exec pod-privileged  -- chown ftp  /tmp 
[root@master anquan]# kubectl  exec pod-privileged  -- ls -ls /  | grep tmp 
     0 drwxrwxrwt    1 ftp      root             6 Nov 24 09:20 tmp
[root@master anquan]# 

為了阻止容器的此種行為,在容器中 securityContext.capabilities.drop 列表加入選項,以禁用這個修改檔案所有者的核心功能。

vim pod-drop-chown-capability.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-drop-chown-capability
spec:
  containers:
  - name: main
    image: alpine
    command: ["/bin/sleep", "999999"]
    securityContext:
      capabilities:
        drop:       # 在這裡禁止了容器修改檔案的所有者
        - CHOWN

禁用 CHOWN 核心功能後, 不允許在這個 pod 中修改檔案所有者

[root@master anquan]# kubectl  create -f pod-drop-chown-capability.yaml 
pod/pod-drop-chown-capability created
[root@master anquan]# kubectl  exec -it pod-drop-chown-capability -- ls -la / | grep tmp 
drwxrwxrwt    2 root     root             6 Nov 24 09:20 tmp
[root@master anquan]# kubectl  exec -it pod-drop-chown-capability -- chown ftp /tmp 
chown: /tmp: Operation not permitted
command terminated with exit code 1
[root@master anquan]# kubectl  exec -it pod-drop-chown-capability -- ls -la / | grep tmp 
drwxrwxrwt    2 root     root             6 Nov 24 09:20 tmp

阻止對容器根檔案系統的寫入

因為安全原因可能需要阻止容器中的程序對容器的根檔案系統進行寫入,僅允許它們寫入掛載的儲存卷。可以通過阻止容器寫入自己的根檔案系統(應用的可執行程式碼的通常儲存位置)來防止。將容器的 securityContext.readOnlyRootFilesystem 設定為 true 來實現。

vim pod-with-readonly-filesystem.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-with-readonly-filesystem
spec:
  containers:
  - name: main
    image: alpine
    command: ["/bin/sleep", "999999"]
    securityContext:                # 這個容器的根檔案系統不允許寫入
      readOnlyRootFilesystem: true
    volumeMounts:
    - name: my-volume       # 但是向/volume寫入是允許的,
      mountPath: /volume      # 因為這個目錄掛載了一個儲存卷
      readOnly: false
  volumes:
  - name: my-volume
    emptyDir:

這個pod中的容器雖然以root使用者執行, 擁有/目錄的寫許可權, 但在該目錄下寫入一個檔案會失敗,對掛載的卷的寫入是允許的

[root@master anquan]# kubectl exec -it pod-with-readonly-filesystem --  touch /new-file
touch: /new-file: Read-only file system
command terminated with exit code 1

[root@master anquan]# kubectl exec -it pod-with-readonly-filesystem --  touch /volume/new-file
[root@master anquan]# kubectl exec -it pod-with-readonly-filesystem --  ls -la /volume/new-file
-rw-r--r--    1 root     root             0 Jan 21 02:35 /volume/new-file

如果容器的根檔案系統是隻讀的, 你很可能需要為應用會寫入的每一個目錄(如日誌、 磁碟快取等)掛載儲存卷。

設定pod級別的安全上下文
以上的例子都是對單獨的容器設定安全上下文。 這些選項中的一部分也可以從pod級別設定(通過pod.spec.securityContext 屬性)。它們會作為pod中每一個容器的預設安全上下文, 但是會被容器級別的安全上下文覆蓋。

容器使用不同使用者執行時共享儲存卷

使用儲存卷在pod的不同容器中共享資料。可以順利地一個容器中寫入資料,在另一個容器中讀出這些資料。但這只是因為兩個容器都以 root 使用者執行,對儲存卷中的所有檔案擁有全部許可權。
現在假設使用前面介紹的 runAsUser 選項。你可能需要在一個 pod 中用兩個不同的使用者執行兩個容器(可能是兩個第三方的容器,都以它們自己的特定使用者執行程序)。如果這樣的兩個容器通過儲存卷共享檔案,它們不一定能夠讀取或寫入另一個容器的檔案。
因此,Kubernetes 允許為 pod 中所有容器指定 supplemental 組,以允許它們無論以哪個使用者 ID 執行都可以共享檔案 。這可以通過以下兩個屬性設定:

  • fsGroup
  • supplementalGroups
vim pod-with-shared-volume-fsgroup.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-with-shared-volume-fsgroup
spec:
  securityContext:             # fsGroup和supplementalGroups在 pod級別的安全上下文中定義
    fsGroup: 555
    supplementalGroups: [666, 777]
  containers:
  - name: first
    image: alpine
    command: ["/bin/sleep", "999999"]
    securityContext:
      runAsUser: 1111           # 第一個容器使用的使用者ID為1111
    volumeMounts:
    - name: shared-volume        # 兩個容器使用同一儲存卷
      mountPath: /volume
      readOnly: false
  - name: second
    image: alpine
    command: ["/bin/sleep", "999999"]
    securityContext:
      runAsUser: 2222           # 第二個容器使用的使用者ID為2222
    volumeMounts:
    - name: shared-volume        # 兩個容器使用同一儲存卷
      mountPath: /volume
      readOnly: false
  volumes:
  - name: shared-volume
    emptyDir:

檢視第一個容器的使用者ID和組ID

[root@master anquan]# kubectl  exec -it pod-with-shared-volume-fsgroup -c first  -- id 
uid=1111 gid=0(root) groups=555,666,777

id 命令顯示, 這個pod執行在ID為1111 的使用者下, 它的使用者組為0 (root),,但使用者組555、 666、 777也關聯到了該使用者下。
在pod的定義中, 將fsGroup設定成了555, 因此, 儲存卷屬千使用者組ID為 555 的使用者組。

[root@master anquan]# kubectl  exec -it pod-with-shared-volume-fsgroup -c first  -- ls -l / | grep volume
drwxrwsrwx    2 root     555              6 Jan 21 03:05 volume

該容器在這個儲存卷所在目錄中建立的檔案, 所屬的使用者ID為1111 (即該容器執行時使用的使用者ID), 所屬的使用者組ID為555

/ $ echo foo >/volume/foo
/ $ ls -l /volume/
total 4
-rw-r--r--    1 1111     555              4 Jan 21 03:13 foo

這個檔案的所屬使用者情況與通常設定下的新建檔案不同。 在通常情況下, 某一使用者新建立檔案所屬的使用者組ID,與該使用者的所屬使用者組ID相同,在這種情下是0。在這個容器的根檔案系統中建立一個檔案, 可以驗證這一點:

/ $ echo foo >/tmp/foo
/ $ ls -l  /tmp/
total 4
-rw-r--r--    1 1111     root             4 Jan 21 03:16 foo

安全上下文中的 fsGroup 屬性當程序在儲存卷中建立檔案時起作用
而 supplementalGroups 屬性定義了某個使用者所關聯的額外的使用者組

限制pod使用安全相關的特性

部署一個特權模式的 pod ,需要有一種機制阻止使用者使用其中的部分功能。 叢集管理入員可以通過建立 PodSecurityPolicy 資源來限制對以上提到的安全相關的特性的使用。

PodSecurityPolicy資源介紹

PodSecurityPolicy 是一種叢集級別(無名稱空間)的資源,它定義了使用者能否在 pod 中使用各種安全相關的特性。維護 PodSecurityPolicy 資源中配置策略的工作由整合在 API 伺服器中的 PodSecurityPolicy 准入控制外掛完成。
當有人向 API 伺服器傳送 pod 資源時, PodSecurityPolicy 准入控制外掛會將這個 pod 與已經配置的 PodSecurityPolicy 進行校驗。 如果這個 pod 符合叢集中已有安全策略, 它會被接收並存入 etcd; 否則它會立即被拒絕。 這個外掛也會根據安全策略中配置的預設值對 pod 進行修改。
瞭解 PodSecurityPolicy 可以做的事
一個 PodSecurityPolicy 資源可以定義以下事項:

  • 是否允許 pod 使用宿主節點的 PID、 IPC、 網路名稱空間
  • pod 允許繫結的宿主節點埠
  • 容器執行時允許使用的使用者 ID
  • 是否允許擁有特權模式容器的 pod
  • 允許新增哪些核心功能, 預設新增哪些核心功能, 總是禁用哪些核心功能
  • 允許容器使用哪些 SELinux 選項
  • 容器是否允許使用可寫的根檔案系統
  • 允許容器在哪些檔案系統組下執行
  • 允許 pod 使用哪些型別的儲存卷

檢視一個 PodSecurityPolicy 樣例
以下樣例阻止了 pod 使用宿主節點的 PID、 IPC、 網路名稱空間, 執行特權模式的容器, 以及繫結大多數宿主節點的埠(除11 000 ~ 11 000 和13 000 ~ 14 000範圍內的埠)。 它沒有限制容器執行時使用的使用者、 使用者組和SELinux 選項。

PodSecurityPolicy 在 Kubernetes v1.21 版本中被棄用,將在 v1.25 中刪除。

vim pod-security-policy.yaml
apiVersion: extensions/v1beta1
kind: PodSecurityPolicy
metadata:
  name: default
spec:
  hostIPC: false       # 容器不允許使用宿主節點的 IPD PID
  hostPID: false       # 和網路名稱空間
  hostNetwork: false      
  hostPorts:         # 容器只能繫結宿主節點的10000-11000埠(含端點)或13000-14000埠
  - min: 10000
      max: 11000
  - min: 13000
      max: 14000
  privileged: false     # 容器不能在特權模式下執行
  readOnlyRootFilesystem: true  # 容器強制使用只讀的根檔案系統
  runAsUser:           # 容器可以以任意使用者和使用者組執行
    rule: RunAsAny
  fsGroup:
    rule: RunAsAny
  supplementalGroups:
    rule: RunAsAny
  seLinux:           # 它們也可以使用任何SElinux選項
    rule: RunAsAny
  volumes:           # pod可以使用所有型別的儲存卷
  - '*'

隔離pod 的網路

如何通過限制 pod 可以與其他哪些 pod 通訊,來確保 pod 之間的網路安全。
是否可以進行這些配置取決於叢集中使用的容器網路外掛。如果網路外掛支援,可以通過NetworkPolicy 資源配置網路隔離。
一個 NetworkPolicy 會應用在匹配它的標籤選擇器的 pod 上,指明這些允許訪問這些 pod 源地址,或這些 pod 可以訪問的目標地址。這些分別由入向(ingress)和出向(egress)規則指定。這兩種規則都可以匹配由標籤選擇器選出的 pod ,或者一個 namespace 中的所有 pod ,或者通過無類別域間路由( Classless Inter-Domain Routing, CIDR )指定的 IP 地址段。

在一個名稱空間中啟用網路隔離

在預設情況下,某一名稱空間中的 pod 可以被任意來源訪問。首先,需要改變這個設定。需要建立一個 default-deny NetworkPolicy ,它會阻止任何客戶端訪問的 pod 。

vim network-policy-default-deny.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata: 
  name: default-deny 
spec: 
  podSelector:   # 空的標籤選擇器匹配名稱空間中的所有 pod

在任何一個特定的命名 間中建立該 NetworkPolicy 之後,任何客戶端都不能訪問該名稱空間中的 pod 。
注意: 叢集中的 CNI 外掛或其他網路方案需要支援 NetworkPolicy ,否則 NetworkPolicy 將不會影響 pod 之間的可達性。

允許同一名稱空間中的部分 pod 訪問 個服務端 pod

為了允許同一名稱空間中的客戶端 pod 訪問該名稱空間的 pod ,需要指明哪些 pod 可以訪問。
假設在 foo namespace 中有一個 pod 執行 PostgreSQL 資料庫,以及一個使用該資料庫的網頁伺服器 pod,其他 pod 也在這個名稱空間中執行,然而你不允許它們連線資料庫。為了保障網路安全,需要再資料庫 pod 所在的名稱空間中建立一個 NetworkPolicy 資源。

vim network-policy-postgres.yaml 
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: postgres-netpolicy
spec:
  podSelector:    # 這個策略確保了對具有 app=database 標籤的 pod 的訪問安全性
    matchLabels:
      app: database
  ingress:  
  - from:  # 它只允許來自具有 app=webserer 標籤的 pod 的訪問
      - podSelector:  
             matchLabels:
                app: webserver
      ports:  # 允許對這個埠的訪問
       - port: 5432

例子中的 NetworkPoliy 允許具有 app=webserer 標籤的 pod 訪問具有 app=database 的 pod 的訪問,並且僅限訪問 5432 埠。

客戶端 pod 通常通過 Service 而非直接訪問 pod 來訪問伺服器 pod ,但這對結果沒有改變。NetworkPolicy 在通過 Service 訪問時仍然會被執行。

在不同 Kubernetes 名稱空間之間進行網路隔離

來看有另一個多個租戶使用同一 Kubernetes叢集的例子。
每個租戶有多個名稱空間,每個名稱空間中有一個標籤指明它們屬於哪個租戶。例如,有一個租戶Manning, 它的所有名稱空間中都有標籤 tenant:manning 。其中的一個名稱空間中運行了 一個微服務Shopping Cart,它需要允許同一租戶下所有名稱空間的所有 pod 訪問。顯然,其他租戶禁止訪問這個微服務。

vim network-policy-cart.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: shoppingcart-netpolicy
spec:
  podSelector:    # 該策應用於具有 app=shopping-cart 標籤的 pod
    matchLabels:
      app: shopping-cart 
  ingress:
  - from:
      - namespaceSelector: # 只有在具有 tenant=manning 標籤的名稱空間中執行的 pod 可以訪問該微服務
            matchLabels:
              tenant: manning
      ports:
      - port: 80

保證了只有具有 tenant=manning 標籤的名稱空間中執行的 pod 可以訪問Shopping Cart 微服務
如果shopping cart服務的提供者需要允許其他租戶訪間該服務,他們可以建立一個新的NetworkPolicy資源,或者在之前的 Networkpolicy 中新增一條入向規則。

注意: 在多租戶的 Kubernetes 叢集中,通常租戶不能為他們的名稱空間新增標籤(或註釋)。否則,他們可以規避基於namespaceSelector的入向規則。

使用CIDR隔離網路

除了通過在 pod 選擇器或名稱空間選擇器定義哪些 pod 可以訪問 NetworkPolicy 資源中指定的目標 pod, 還可以通過CIDR表示法指定一 個IP段。
例如,為了允許 IP 在192.168.1.1到192. I 68.1.255範圍內的客戶端訪問之前提到的shopping cart的 pod, 可以在入向規則中加入 ingress。

vim network-policy-cidr.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: ipblock-netpolicy
spec:
  podSelector:
    matchLabels:
      app: shopping-cart
  ingress:   # 這條入向規則來自192.168.1.0/24 IP段的客戶端的流量
  - from:
    - ipBlock:
        cidr: 192.168.1.0/24

限制pod的對外訪問流量

已經通過入向規則限制了進入pod的訪問流量。然而,也可以通過出向規則限制pod的對外訪問流量。

vim network-policy-egress.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: egress-net-policy
spec:
  podSelector:     # 這個策略應用於包含app=webserver標籤的pod
    matchLabels:
      app: webserver
  egress:         # 限制 pod 的出網流量
  - to:
    - podSelector:    # webserver的pod只能與有 app=webserve 標籤的 pod 通訊
        matchLabels:
          app: database
    ports:
    - port: 5432

以上的 NetworkPolicy 僅允許具有標籤 app=webserver 的 pod 訪問具有標籤 app=database 的pod, 除此之外不能訪問任何地址(不論是其他pod,還是任何其他的IP, 無論在叢集內部還是外部)。