使用 Calico 網路原則來控制「標準」叢集上的資料流量

學習如何使用 Calico 政策來允許來自或來自特定 IP 位址的網路流量。

請注意,下列步驟適用於具有 Classic LoadBalancers 的 Classic 群集。

依預設,Kubernetes NodePort、LoadBalancer 及 Ingress 服務可讓您的應用程式能夠在所有公用及專用叢集網路介面上使用。 allow-node-port-dnat 預設 Calico 原則允許從 NodePort、網路負載平衡器 (NLB) 及 Ingress 應用程式負載平衡器 (ALB) 服務送入那些服務所公開之應用程式 Pod 的資料流量。 Kubernetes 會使用目的地網址轉譯 (DNAT) 將服務要求轉遞至正確的 Pod。

不過,基於安全理由,您可能需要只允許從特定來源 IP 位址到網路服務的資料流量。 您可以使用 Calico Pre-DNAT 策略來允許或封鎖來自或前往特定 IP 位址的流量。 DNAT 前原則可防止指定的資料流量到達您的應用程式,因為在 Kubernetes 使用一般 DNAT 將資料流量轉遞至 Pod 之前,已套用這些原則。 當您建立 Calico Pre-DNAT 政策時,您可以選擇允許或封鎖來源 IP 位址。 對於大部分實務範例,容許特定資料流量會提供最安全的配置,因為除了來自已知允許來源 IP 位址的資料流量之外,所有資料流量都會被封鎖。拒絕特定資料流量通常只有在防止來自一小組 IP 位址的攻擊之類的情況下才有用。

在此情境中,您扮演的是公關公司的網路管理者角色,且您會發現一些不尋常的資料流量正在攻擊您的應用程式。 本教學中的課程將引導您建立一個 Web 伺服器應用程式範例,透過使用網路負載平衡器 (NLB) 服務來開放應用程式,並使用 allowlist 和 blocklist Calico 策略來保護應用程式免受不想要的異常流量。

目標

  • 學習藉由建立高階 DNAT 前原則,以封鎖送入所有節點埠的所有資料流量。
  • 學習透過建立低階 Pre-DNAT 政策,允許特定來源 IP 位址存取 NLB 公共 IP 和連接埠。 低階原則會置換高階原則。
  • 學習透過建立低階 Pre-DNAT 策略,阻止特定來源 IP 位址存取 NLB 公共 IP 和連接埠。

適用對象

本指導教學的適用對象是想要管理送至應用程式之網路資料流量的軟體開發人員及網路管理者。

必要條件

使用 NLB 部署應用程式並將其公開

第一課告訴您如何從多個 IP 位址及埠公開您的應用程式,以及公用資料流量是從哪裡進入您的叢集。

開始部署要在整個指導教學中使用的 Web 伺服器應用程式範例。 echoserver Web 伺服器顯示有關從用戶端與叢集建立的連線的資料,並且您可以測試對公關公司叢集的存取。 然後,藉由建立網路負載平衡器 (NLB) 1.0 服務來公開應用程式。 NLB 1.0 服務可讓您的應用程式透過 NLB 服務 IP 位址及工作者節點的節點埠來使用。

在第 1 課結束時,Web 伺服器應用程式透過公共節點連接埠和公共 NLB 暴露在網路上。

  1. 部署 Web 伺服器應用程式範例。 與 Web 伺服器應用程式建立連線時,應用程式會以其在連線中收到的 HTTP 標頭回應。

    kubectl apply -f https://raw.githubusercontent.com/IBM-Cloud/kube-samples/master/deploy-apps-clusters/webserver.yaml
    
  2. 驗證 Web 伺服器應用程式 Pod 的 STATUSRunning

    kubectl get pods -o wide
    

    輸出範例

    NAME                         READY     STATUS    RESTARTS   AGE       IP               NODE
    webserver-855556f688-6dbsn   1/1       Running   0          1m        172.30.xxx.xxx   10.176.48.78
    webserver-855556f688-76rkp   1/1       Running   0          1m        172.30.xxx.xxx   10.176.48.78
    webserver-855556f688-xd849   1/1       Running   0          1m        172.30.xxx.xxx   10.176.48.78
    
  3. 若要在公用網際網路上公開應用程式,請在文字編輯器中建立一個稱為 webserver-lb.yaml 的 NLB 1.0 服務配置檔。

    apiVersion: v1
    kind: Service
    metadata:
      labels:
        run: webserver                               
      name: webserver-lb
    spec:
      type: LoadBalancer
      selector:
        run: webserver
      ports:
      - name: webserver-port
        protocol: TCP
        port: 8080
        targetPort: 8080 # Optional. By default, the `targetPort` is set to match the `port` value unless specified otherwise.
    
  4. 部署 NLB。

    kubectl apply -f filepath/webserver-lb.yaml
    
  5. 驗證是否可以從您的電腦公開存取由 NLB 公開的應用程式。

    1. 取得 NLB 的公用 EXTERNAL-IP 位址。

      kubectl get svc -o wide
      

      輸出範例

      NAME           CLUSTER-IP       EXTERNAL-IP        PORT(S)        AGE       SELECTOR
      webserver-lb   172.21.xxx.xxx   169.xx.xxx.xxx     80:31024/TCP   2m        run=webserver
      
    2. 建立提要文字檔,並將 NLB IP 複製到文字檔。 提要將協助您在稍後的課程中更快速地使用這些值。

    3. 驗證您可公開存取 NLB 的外部 IP。

      curl --connect-timeout 10 <loadbalancer_IP>:80
      

      下列輸出範例確認 NLB 會在 169.1.1.1 公用 NLB IP 位址上公開您的應用程式。 webserver-855556f688-76rkp 應用程式 Pod 收到 curl 請求。

      Hostname: webserver-855556f688-76rkp
      Pod Information:
          -no pod information available-
      Server values:
          server_version=nginx: 1.13.3 - lua: 10008
      Request Information:
          client_address=10.176.XX.XX
          method=GET
          real path=/
          query=
          request_version=1.1
          request_scheme=http
          request_uri=http://169.1.1.1:8080/
      Request Headers:
          accept=*/*
          host=169.1.1.1
          user-agent=curl/7.54.0
      Request Body:
          -no body in request-
      
  6. 驗證是否可以從您的電腦公開存取由節點埠公開的應用程式。 NLB 服務可讓您的應用程式透過 NLB 服務 IP 位址及工作者節點的節點埠來使用。

    1. 取得 NLB 指派給工作者節點的節點埠。 節點埠位於 30000 到 32767 範圍內。

      kubectl get svc -o wide
      

      在下列輸出範例中,節點埠為 31024

      NAME           CLUSTER-IP       EXTERNAL-IP        PORT(S)        AGE       SELECTOR
      webserver-lb   172.21.xxx.xxx   169.xx.xxx.xxx     80:31024/TCP   2m        run=webserver
      
    2. 對於傳統群集,請取得工作者節點的 Public IP 位址。 若為 VPC 叢集,請改為取得 專用 IP 位址。

      ibmcloud ks worker ls --cluster <cluster_name>
      

      輸出範例

      ID                                                 Public IP        Private IP     Machine Type        State    Status   Zone    Version   
      kube-dal10-cr18e61e63c6e94b658596ca93d087eed9-w1   169.xx.xxx.xxx   10.176.48.67   u3c.2x4.encrypted   normal   Ready    dal10   1.35_1513*   
      kube-dal10-cr18e61e63c6e94b658596ca93d087eed9-w2   169.xx.xxx.xxx   10.176.48.79   u3c.2x4.encrypted   normal   Ready    dal10   1.35_1513*   
      kube-dal10-cr18e61e63c6e94b658596ca93d087eed9-w3   169.xx.xxx.xxx   10.176.48.78   u3c.2x4.encrypted   normal   Ready    dal10   1.35_1513*   
      
    3. 將工作者節點及節點埠的公用 IP 複製到您的文字提要,以在稍後課程中使用。

    4. 驗證您可以透過節點埠存取工作者節點的公用 IP 位址。 附註: 因為 VPC 叢集裡的工作者節點沒有公用 IP 位址,所以僅當您連接至專用 VPC 網路 (例如透過 VPN 連線) 時,才能透過 NodePort 存取應用程式。 然後,您可以使用工作節點的私有IP位址和NodePort:<worker_private_IP>:<NodePort>

      curl  --connect-timeout 10 <worker_IP>:<NodePort>
      

      下列輸出範例確認,是透過工作者節點的專用 IP 位址 10.1.1.131024 節點埠,對您的應用程式提出要求。 webserver-855556f688-xd849 應用程式 Pod 收到 Curl 要求:

      Hostname: webserver-855556f688-xd849
      Pod Information:
          -no pod information available-
      Server values:
          server_version=nginx: 1.13.3 - lua: 10008
      Request Information:
          client_address=1.1.1.1
          method=GET
          real path=/
          query=
          request_version=1.1
          request_scheme=http
          request_uri=http://10.1.1.1:8080/
      Request Headers:
          accept=*/*
          host=10.1.1.1:31024
          user-agent=curl/7.60.0
      Request Body:
          -no body in request-
      

此時,會從多個 IP 位址及埠公開您的應用程式。 其中大部分 IP 都在叢集的內部,而且只能透過專用網路存取。 只有公用節點埠及公用 NLB 埠,才會在公用網際網路公開。

接下來,您可以開始建立並套用 Calico 原則來封鎖公用資料流量。

封鎖所有節點連接埠的所有傳入流量

若要保護公關公司的叢集,您必須封鎖對公開您應用程式之 NLB 服務及節點埠兩者的公開存取。 首先,封鎖對節點埠的存取。

在第 2 課結束時,Web 伺服器應用程式僅透過公共 NLB 暴露在網路上。

  1. 在文字編輯器中,建立一個稱為 deny-nodeports.yaml 的高階 DNAT 前原則,來拒絕將 TCP 及 UDP 資料流量從任何來源 IP 送入所有節點埠。

    apiVersion: projectcalico.org/v3
    kind: GlobalNetworkPolicy
    metadata:
      name: deny-nodeports
    spec:
      applyOnForward: true
      preDNAT: true
      ingress:
      - action: Deny
        destination:
          ports:
          - 30000:32767
        protocol: TCP
        source: {}
      - action: Deny
        destination:
          ports:
          - 30000:32767
        protocol: UDP
        source: {}
      selector: ibm.role=='worker_public'
      order: 1100
      types:
      - Ingress
    
  2. 套用原則。

    • Linux:

      calicoctl apply -f filepath/deny-nodeports.yaml
      
    • Windows 及 OS X:

      calicoctl apply -f filepath/deny-nodeports.yaml --config=filepath/calicoctl.cfg
      

    輸出範例

    Successfully applied 1 'GlobalNetworkPolicy' resource(s)
    
  3. 使用來自提要的值,驗證您無法公開存取工作者節點公用 IP 位址及節點埠。

    curl  --connect-timeout 10 <worker_IP>:<NodePort>
    

    連線逾時,因為您建立的 Calico 原則封鎖資料流量送入節點埠。

    curl: (28) Connection timed out after 10016 milliseconds
    
  4. 改變externalTrafficPolicy的LoadBalancer您在上一課中創建的 ClusterLocalLocal 確保當您捲曲外部 IP 時保留系統的來源 IPLoadBalancer在下一步中。

    kubectl patch svc webserver-lb -p '{"spec":{"externalTrafficPolicy":"Local"}}'
    
  5. 使用來自提要的值,驗證您仍然可公開存取 NLB 外部 IP 位址。

    curl --connect-timeout 10 <loadbalancer_IP>:80
    

    輸出範例

    Hostname: webserver-855556f688-76rkp
    Pod Information:
        -no pod information available-
    Server values:
        server_version=nginx: 1.13.3 - lua: 10008
    Request Information:
        client_address=1.1.1.1
        method=GET
        real path=/
        query=
        request_version=1.1
        request_scheme=http
        request_uri=http://<loadbalancer_IP>:8080/
    Request Headers:
        accept=*/*
        host=<loadbalancer_IP>
        user-agent=curl/7.54.0
    Request Body:
        -no body in request-
    

    例如,在輸出的 Request Information 區段中,來源 IP 位址為 client_address=1.1.1.1。 來源 IP 位址是您要用來執行 Curl 之系統的公用 IP。 否則,如果您是透過 Proxy 或 VPN 連接至網際網路,則 Proxy 或 VPN 可能會遮蔽系統的實際 IP 位址。 在任一情況下,NLB 會將您系統的來源 IP 位址看成用戶端 IP 位址。

  6. 將您系統的來源 IP 位址(前一個步驟輸出中的 client_address=1.1.1.1)複製到您的提要,以在稍後課桯中使用。

太好了! 此時,只會從公用 NLB 埠,在公用網際網路上公開您的應用程式。 送入公用節點埠的資料流量會遭到封鎖。 已局部鎖定叢集以阻止不想要的資料流量。

接下來,您可以建立並套用 Calico 政策,以僅允許來自特定來源 IP 的流量。

允許從特定 IP 傳入的流量到 NLB

您現在決定完全鎖定公關公司群集的流量,並只允許您自己電腦的 IP 位址進行存取測試。

首先,除了節點埠之外,您還必須封鎖送入公開應用程式之 NLB 的所有資料流量。 然後,您可以建立允許系統 IP 位址的政策。 在第 3 課結束時,所有到公共節點連接埠和 NLB 的流量都會被封鎖,只有來自您允許系統 IP 的流量才會被允許。

  1. 在文字編輯器中,建立一個稱為 deny-lb-port-80.yaml 的高階 DNAT 前原則,來拒絕從任何來源 IP 送入 NLB IP 位址及埠的所有 TCP 及 UDP 資料流量。 將 <loadbalancer_IP> 改為小抄中的 NLB 公共 IP 位址。

    apiVersion: projectcalico.org/v3
    kind: GlobalNetworkPolicy
    metadata:
      name: deny-lb-port-80
    spec:
      applyOnForward: true
      preDNAT: true
      ingress:
      - action: Deny
        destination:
          nets:
          - <loadbalancer_IP>/32
          ports:
          - 80
        protocol: TCP
        source: {}
      - action: Deny
        destination:
          nets:
          - <loadbalancer_IP>/32
          ports:
          - 80
        protocol: UDP
        source: {}
      selector: ibm.role=='worker_public'
      order: 800
      types:
      - Ingress
    
  2. 套用原則。

    • Linux:

      calicoctl apply -f filepath/deny-lb-port-80.yaml
      
    • Windows 及 OS X:

      calicoctl apply -f filepath/deny-lb-port-80.yaml --config=filepath/calicoctl.cfg
      
  3. 使用來自提要的值,驗證您現在無法存取公用 NLB IP 位址。 連線逾時,因為您建立的 Calico 原則封鎖送入 NLB 的資料流量。

    curl --connect-timeout 10 <loadbalancer_IP>:80
    
  4. 在文字編輯器中,建立一個名為 allowlist.yaml 的低階 Pre-DNAT 策略,以允許從您系統的 IP 到 NLB IP 位址和連接埠的流量。 使用小抄中的值,將 <loadbalancer_IP> 改為 NLB 的公共 IP 位址,將 <client_address> 改為系統來源 IP 的公共 IP 位址。 如果記不住系統 IP,可以執行 curl ifconfig.co

    apiVersion: projectcalico.org/v3
    kind: GlobalNetworkPolicy
    metadata:
      name: allowlist
    spec:
      applyOnForward: true
      preDNAT: true
      ingress:
      - action: Allow
        destination:
          nets:
          - <loadbalancer_IP>/32
          ports:
          - 80
        protocol: TCP
        source:
          nets:
          - <client_address>/32
      selector: ibm.role=='worker_public'
      order: 500
      types:
      - Ingress
    
  5. 套用原則。

    • Linux:

      calicoctl apply -f filepath/allowlist.yaml
      
    • Windows 及 OS X:

      calicoctl apply -f filepath/allowlist.yaml --config=filepath/calicoctl.cfg
      

    您系統的 IP 位址現在已被允許。

  6. 使用來自提要的值,驗證您現在可以存取公用 NLB IP 位址。

    curl --connect-timeout 10 <loadbalancer_IP>:80
    
  7. 如果您可以存取另一個具有不同 IP 位址的系統,請嘗試從該系統存取 NLB。

    curl --connect-timeout 10 <loadbalancer_IP>:80
    

    連線中斷的原因是該系統的 IP 位址不被允許。

此時,所有送入公用節點埠及 NLB 的資料流量都會遭到封鎖。 只允許來自您允許系統 IP 的流量。

拒絕從特定 IP 送入 NLB 的資料流量

在上一課中,您封鎖了所有流量,只允許幾個 IP。 當您想要限制只存取少數受管理的來源 IP 位址時,該情境適用於測試目的。 不過,公關公司具有需要大眾可以廣泛使用的應用程式。 您需要確定允許所有資料流量,但您從少數 IP 位址看到的不尋常資料流量除外。 拒絕清單在這種情況下非常有用,因為它可以幫助您防止來自一小組 IP 位址的攻擊。

在本課程中,封鎖來自您自己系統的來源 IP 位址的資料流量。 在第 4 課結束時,將封鎖流至公用節點埠的所有資料流量,但允許流至公用 NLB 的所有資料流量。 只有來自您特定系統 IP 到 NLB 的流量才會被封鎖。

  1. 清理您在上一課中建立的允許清單政策。

    • Linux:
      calicoctl delete GlobalNetworkPolicy deny-lb-port-80
      
      calicoctl delete GlobalNetworkPolicy allowlist
      
    • Windows 及 OS X:
      calicoctl delete GlobalNetworkPolicy deny-lb-port-80 --config=filepath/calicoctl.cfg
      
      calicoctl delete GlobalNetworkPolicy allowlist --config=filepath/calicoctl.cfg
      

    現在,再次允許從任何來源 IP 送入 NLB IP 位址及埠的所有 TCP 及 UDP 資料流量。

  2. 若要拒絕所有從系統的來源 IP 位址傳送到 NLB IP 位址和連接埠的 TCP 和 UDP 流量,請在文字編輯器中建立一個名為 blocklist.yaml 的低階 pre-DNAT 政策。 使用小抄中的值,將 <loadbalancer_IP> 改為 NLB 的公共 IP 位址,將 <client_address> 改為系統來源 IP 的公共 IP 位址。

    apiVersion: projectcalico.org/v3
    kind: GlobalNetworkPolicy
    metadata:
      name: blocklist
    spec:
      applyOnForward: true
      preDNAT: true
      ingress:
      - action: Deny
        destination:
          nets:
          - <loadbalancer_IP>/32
          ports:
          - 80
        protocol: TCP
        source:
          nets:
          - <client_address>/32
      - action: Deny
        destination:
          nets:
          - <loadbalancer_IP>/32
          ports:
          - 80
        protocol: UDP
        source:
          nets:
          - <client_address>/32
     selector: ibm.role=='worker_public'
     order: 500
     types:
     - Ingress
    
  3. 套用原則。

    • Linux:

      calicoctl apply -f filepath/blocklist.yaml
      
    • Windows 及 OS X:

      calicoctl apply -f filepath/blocklist.yaml --config=filepath/calicoctl.cfg
      

    您系統的 IP 位址現在已被封鎖。

  4. 使用小抄中的值,從系統確認您無法存取 NLB IP,因為您系統的 IP 已被封鎖。

    curl --connect-timeout 10 <loadbalancer_IP>:80
    

    此時,會封鎖所有送入公用節點埠的資料流量,而且允許所有送入公用 NLB 的資料流量。 只有來自您特定系統 IP 到 NLB 的流量才會被封鎖。

做得好! 您使用 Calico Pre-DNAT 策略封鎖來源 IP,成功控制了進入您應用程式的流量。

記載從特定 IP 到 NLB 的已封鎖資料流量

在上一課中,您封鎖了從系統 IP 到 NLB 的流量。 在本課程中,您可以學習如何記載拒絕的資料流量要求。

在這個範例情境中,您所服務的公關公司希望您針對持續被網路政策拒絕的任何異常流量建立記錄追蹤。 為了監控潛在的安全威脅,您設定了記錄,以記錄每次您的封鎖清單政策拒絕嘗試對 NLB IP 執行的動作。

  1. 建立名為 log-denied-packets 的 Calico NetworkPolicy。 此日誌政策使用與 blocklist 政策相同的選擇器,可將此政策新增至 Calico Iptables 規則鏈。 透過使用低階數字,例如 300,可以確保此規則在封鎖清單政策之前加入 Iptables 規則鏈。 來自您 IP 的封包在嘗試匹配 blocklist 政策規則之前會被此政策記錄,並被拒絕。

    apiVersion: projectcalico.org/v3
    kind: GlobalNetworkPolicy
    metadata:
        name: log-denied-packets
     spec:
      applyOnForward: true
      preDNAT: true
      ingress:
      - action: Log
        destination:
          nets:
          - <loadbalancer_IP>/32
          ports:
          - 80
        protocol: TCP
        source:
          nets:
          - <client_address>/32
      - action: Log
        destination:
          nets:
          - <loadbalancer_IP>/32
          ports:
          - 80
        protocol: UDP
        source:
          nets:
          - <client_address>/32
      selector: ibm.role=='worker_public'
      order: 300
      types:
      - Ingress
    
  2. 套用原則。

    • Linux:

      calicoctl apply -f /log-denied-packets.yaml
      
    • Windows 及 OS X:

      calicoctl apply -f /log-denied-packets.yaml --config=<filepath>/calicoctl.cfg
      
  3. 將要求從系統 IP 傳送至 NLB IP,以產生日誌項目。 在拒絕這些要求封包之前,會先行記載。

    curl --connect-timeout 10 <loadbalancer_IP>:80
    
  4. 檢查寫入 /var/log/syslog 路徑的日誌項目。 日誌項目會與下列內容類似。

    Sep 5 14:34:40 <worker_hostname> kernel: [158271.044316] calico-packet: IN=eth1 OUT= MAC=08:00:27:d5:4e:57:0a:00:27:00:00:00:08:00 SRC=192.XXX.XX.X DST=192.XXX.XX.XX LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=52866 DF PROTO=TCP SPT=42962 DPT=22 WINDOW=29200 RES=0x00 SYN URGP=0
    

太好了! 您設定記錄,以便更容易監控被封鎖的流量。

如果您要清理封鎖清單和記錄政策:

  1. 清理封鎖清單政策。
    • Linux:
      calicoctl delete GlobalNetworkPolicy blocklist
      
    • Windows 及 OS X:
      calicoctl delete GlobalNetworkPolicy blocklist --config=filepath/calicoctl.cfg
      
  2. 清除日誌原則。
    • Linux:
      calicoctl delete GlobalNetworkPolicy log-denied-packets
      
    • Windows 及 OS X:
      calicoctl delete GlobalNetworkPolicy log-denied-packets --config=filepath/calicoctl.cfg
      

下一步為何?