Kubernetes NetworkPolicy:打造更安全的容器運行環境

常見的應用可以分爲兩大類:Job和Service。Job比較簡單,就是一個普通的任務,完成之後就退出,一般不需要暴露對外服務的網絡監聽端口。Service是指長期運行的進程,監聽某個網絡端口,其他服務可以通過網絡連過來。生產環境裏,將服務暴露在網絡上存在安全風險:必須限制只有信任的用戶才能訪問服務。我們肯定不希望未授權的用戶能調用某個刪除數據的接口,把DB裏的數據刪光。訪問控制可以在應用層做,客戶端訪問服務時,帶上身份校驗信息,服務端校驗客戶身份,判斷客戶是否有權限完成請求的操作,如果有權限,執行客戶端請求,否則返回一個拒絕信息。訪問控制還可以在網絡層做,只允許受信的網絡段訪問服務。兩種方式各有優劣,應用層可以做到更細粒度的權限控制,但需要開發,並且要求能客戶端/服務器在通信協議上支持鑑權。網絡層鑑權不依賴具體應用,還有一個額外的好處是能防DDoS。今天的主題NetworkPolicy,就是一種網絡層的訪問控制機制。

傳統上,通常使用防火牆實現網絡層的訪問控制,比如iptables rule,部署應用之後,通過iptables設置運行的ip白名單。在使用Kubernetes之後,由於Pod是動態分配到機器上,而且在運行過程中隨時可能遷移到其他機器,顯然不適合繼續使用手工配置iptables的方式。好在Kubernetes考慮到這個需求,提供了Network Policy,通過Network Policy,我們不僅能限制哪些Pod能被哪些來源訪問,甚至還能控制Pod能訪問哪些外部服務。Kubernetes中的Network Policy只定義了規範,並沒有提供實現,而是把實現留給了網絡插件。阿里雲容器服務的Terway支持Network Policy,接下來我們基於Terway介紹幾個使用Network Policy的場景。

創建Terway集羣

首先,我們要創建一個使用Terway的集羣,也就是在創建集羣的時候,網絡插件選Terway。

Screen_Shot_2018_09_14_at_2_38_47_PM

等待一會,集羣創建好。這是我剛剛創建好的集羣,名字就叫terway

Screen_Shot_2018_09_14_at_2_39_35_PM

爲了操作方便,我們直接用命令行的方式,先下載kubeconfig文件,保存到本地的$HOME/.kube/config

場景1: 限制服務只能被帶有特定label的應用訪問

首先部署一個nginx,兩個實例,附帶一個service

~ % kubectl run nginx --image=nginx
deployment.apps "nginx" created
~ % kubectl get pod
NAME                     READY     STATUS    RESTARTS   AGE
nginx-65899c769f-c9s8z   1/1       Running   0          24s
~ % kubectl expose deployment nginx --port=80
service "nginx" exposed
~ % kubectl get svc
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   172.19.0.1      <none>        443/TCP   21h
nginx        ClusterIP   172.19.32.113   <none>        80/TCP    20s

現在,起一個新應用,訪問剛剛創建nginx service

~ % kubectl run busybox --rm -ti --image=busybox /bin/sh

If you don't see a command prompt, try pressing enter.
/ # wget nginx
Connecting to nginx (172.19.32.113:80)
index.html           100% |***************************************************************************************************************************************************|   612  0:00:00 ETA
/ #

看上去沒問題,網絡是通的。接下來我們設置一個Network Policy,只允許帶有label access=true的應用訪問nginx,其他都不行。開一個新終端

~ % cat policy.yaml
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: access-nginx
spec:
  podSelector:
    matchLabels:
      run: nginx
  ingress:
  - from:
    - podSelector:
        matchLabels:
          access: "true"
~ % kubectl apply -f policy.yaml
networkpolicy.networking.k8s.io "access-nginx" created

回到運行busybox的終端,再執行一次wget nginx

/ # wget nginx
Connecting to nginx (172.19.32.113:80)

^C
/ #

可以看到,在設置完Policy之後,之前啓動的busybox已經不能訪問nginx了。我們重新啓動一個帶有label access=true的busybox

~ % kubectl run busybox --rm -ti --labels="access=true" --image=busybox /bin/sh
If you don't see a command prompt, try pressing enter.
/ # wget nginx
Connecting to nginx (172.19.32.113:80)
index.html           100% |***************************************************************************************************************************************************|   612  0:00:00 ETA
/ #

成功!

場景2: 限制能夠訪問暴露了公網SLB服務的來源IP

給上個場景中的nginx再創建一個LoadBalance類型的service,LoadBalance類型的service會創建一個SLB

~ % cat nginx-service.yaml
apiVersion: v1
kind: Service
metadata:
  labels:
    run: nginx
  name: nginx-slb
spec:
  externalTrafficPolicy: Local
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    run: nginx
  type: LoadBalancer
~ % kubectl apply -f nginx-service.yaml
service "nginx-slb" created
~ % kubectl get svc nginx-slb
NAME        TYPE           CLUSTER-IP      EXTERNAL-IP     PORT(S)        AGE
nginx-slb   LoadBalancer   172.19.89.136   47.95.180.200   80:31967/TCP   17s

我們創建了LoadBalance類型的service,SLB的IP是 47.95.180.200,先從本地請求一下試試:

~ % wget 47.95.180.200
--2018-09-14 08:07:23--  http://47.95.180.200/
Connecting to 47.95.180.200:80... ^C
~ %

網絡不通,因爲剛纔我們設置了nginx只允許帶有label access=true的應用訪問,現在是我們從外部訪問Kubernetes,根本不是Pod,更不要說設置label了。怎麼辦?

方案是修改之前創建的Network Policy,增加一個允許訪問的來源IP段。把自己本地的IP地址加到白名單裏去。先拿到自己的IP地址

~ % curl myip.ipip.net
當前 IP:1.2.3.4  來自於:中國 浙江 #我的實際IP不是這個,根據自己的實際情況處理。

然後編輯policy.yaml,把IP地址加進去。有些網絡的出口IP有多個,所以這裏加上了一個/24的段。100.64.0.0/10必須要帶上,SLB健康檢查地址在這個段裏,不加上的話SLB健康檢查會出錯。

~ % cat policy.yaml
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: access-nginx
spec:
  podSelector:
    matchLabels:
      run: nginx
  ingress:
  - from:
    - podSelector:
        matchLabels:
          access: "true"
    - ipBlock:
        cidr: 100.64.0.0/10
    - ipBlock:
        cidr: 1.2.3.0/24
~ % kubectl apply -f policy.yaml
networkpolicy.networking.k8s.io "access-nginx" configured

好了,再訪問一次

~ % wget 47.95.180.200
--2018-09-14 08:15:03--  http://47.95.180.200/
Connecting to 47.95.180.200:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 612 [text/html]
Saving to: 'index.html'

index.html                                       100%[=========================================================================================================>]     612  --.-KB/s    in 0s

2018-09-14 08:15:03 (67.6 MB/s) - 'index.html' saved [612/612]

網絡又通了,完美!

場景3: 限制一個Pod只能訪問www.aliyun.com

除了限制當前應用能被誰訪問,有時候還要限制應用能訪問誰,有時候我們要運行第三方應用,不希望這些應用訪問到不該訪問的網絡。通過Network Policy,也能實現這個需求。

Network Policy只能通過IP地址配置規則,首先我們通過dig獲取www.aliyun.com的地址

~ % dig +short www.aliyun.com
www-jp-de-intl-adns.aliyun.com.
www-jp-de-intl-adns.aliyun.com.gds.alibabadns.com.
v6wagbridge.aliyun.com.
v6wagbridge.aliyun.com.gds.alibabadns.com.
140.205.34.3
106.11.93.21
140.205.32.4
140.205.230.13

這樣就拿到了域名解析到的IP列表。然後編寫如下的Network Policy規則:

~ % cat busybox-policy.yaml
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: busybox-policy
spec:
  podSelector:
    matchLabels:
      run: busybox
  egress:
  - to:
    - ipBlock:
        cidr: 140.205.230.13/32
    - ipBlock:
        cidr: 140.205.34.3/32
    - ipBlock:
        cidr: 106.11.93.21/32
    - ipBlock:
        cidr: 140.205.32.4/32
  - to:
    - ipBlock:
        cidr: 0.0.0.0/0
    ports:
    - protocol: UDP
      port: 53

~ % kubectl apply -f busybox-policy.yaml
networkpolicy.networking.k8s.io "busybox-policy" configured

在這個規則裏,我們配置了egress規則,也就是出網規則,限制應用對外訪問。允許UDP請求,否則沒法做DNS解析。

驗證一下

~ % kubectl run busybox --rm -ti --image=busybox /bin/sh
If you don't see a command prompt, try pressing enter.
/ # wget www.aliyun.com
Connecting to www.aliyun.com (106.11.93.21:80)
Connecting to www.aliyun.com (140.205.230.13:443)
wget: note: TLS certificate validation not implemented
index.html           100% |***************************************************************************************************************************************************|  526k  0:00:00 ETA
/ #
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章