IBM Cloud Docs
使用 Calico 网络策略来控制经典集群上的流量

使用 Calico 网络策略来控制经典集群上的流量

了解如何使用 Calico 策略允许来自和前往特定IP地址的网络流量。

请注意,以下步骤适用于具有经典 LoadBalancers的经典集群。

缺省情况下,Kubernetes NodePort、LoadBalancer 和 Ingress 服务能使应用程序在所有公共和专用集群网络接口上都可用。 allow-node-port-dnat 缺省 Calico 策略允许来自 NodePort、网络负载均衡器 (NLB) 和 Ingress 应用程序负载均衡器 (ALB) 服务的入局流量流至这些服务公开的应用程序 pod。 Kubernetes 会使用目标网络地址转换 (DNAT) 将服务请求转发到正确的 pod。

但是,出于安全原因,您可能需要仅允许来自特定源 IP 地址的流量流至联网服务。 您可以使用 Calico 预先 DNAT 策略来允许或阻止来自或前往特定 IP 地址的流量。 DNAT 前策略会阻止指定流量到达应用程序,因为会在 Kubernetes 使用常规 DNAT 将流量转发到 pod 之前应用这些策略。 创建 Calico 预DNAT策略时,您可以选择允许或阻止源IP地址。 对于大多数场景,允许特定流量提供最安全的配置,因为除了来自已知,允许的源 IP 地址的流量外,所有流量都被阻塞。拒绝特定流量通常仅在防止来自一小组 IP 地址的攻击之类的场景中有用。

在此场景中,您扮演的是公关公司的网络管理员角色,并且您注意到应用程序遇到一些异常流量。 本教程将指导您创建一个示例Web服务器应用程序,使用网络负载均衡器(NLB)服务公开该应用程序,并通过允许列表和阻止列表 Calico 策略保护应用程序免受异常流量的干扰。

目标

  • 了解如何通过创建高位 DNAT 前策略,阻止流至所有节点端口的所有入局流量。
  • 通过创建低阶预 DNAT 策略,允许特定源 IP 地址访问 NLB 公共 IP 和端口。 低位策略会覆盖高位策略。
  • 通过创建低阶预 DNAT 策略,阻止特定源 IP 地址访问 NLB 公共 IP 和端口。

受众

本教程适用于希望管理应用程序的网络流量的软件开发者和网络管理员。

先决条件

部署应用程序并通过NLB将其公开

第一课说明如何从多个 IP 地址和端口公开应用程序,以及公共流量进入集群的位置。

首先,部署要在整个教程中使用的样本 Web 服务器应用程序。 echoserver Web 服务器显示有关从客户机与集群建立的连接的数据,并且您可以测试对公关公司集群的访问。 然后,通过创建网络负载均衡器 (NLB) 1.0 服务来公开应用程序。 NLB 1.0 服务通过 NLB 服务 IP 地址和工作程序节点的节点端口使应用程序可用。

第 1 课结束时,网络服务器应用程序已通过公共节点端口和公共 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 的 STATUS 是否为 Running

    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接收到卷曲请求。

      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. 对于经典集群,获取工作节点的公共IP地址。 对于 VPC 集群,请改为获取 专用 IP 地址。

      ibmcloud oc 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.32_1513*   
      kube-dal10-cr18e61e63c6e94b658596ca93d087eed9-w2   169.xx.xxx.xxx   10.176.48.79   u3c.2x4.encrypted   normal   Ready    dal10   1.32_1513*   
      kube-dal10-cr18e61e63c6e94b658596ca93d087eed9-w3   169.xx.xxx.xxx   10.176.48.78   u3c.2x4.encrypted   normal   Ready    dal10   1.32_1513*   
      
    3. 将工作程序节点的公共 IP 以及节点端口复制到文本备忘单中,以便在后面的课程中使用。

    4. 验证是否可以通过节点端口访问工作程序节点的公共 IP 地址。 : 由于 VPC 集群中的工作程序节点没有公共 IP 地址,因此仅当您已连接到专用 VPC 网络 (例如,通过 VPN 连接) 时,才能通过 NodePort 访问应用程序。 然后,您可以使用 Worker 节点的私有 IP 地址和 NodePort: <worker_private_IP>:<NodePort>

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

      以下输出示例确认对应用程序的请求通过工作程序节点的专用 IP 地址 10.1.1.1 和节点端口 31024 传入。 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 中大部分都是集群内部 IP,只能通过专用网络进行访问。 只有公共节点端口和公共 NLB 端口会公开到公用因特网。

接下来,您可以开始创建并应用 Calico 策略来阻止公共流量。

阻止所有节点端口的所有传入流量

要保护公关公司的集群,必须阻止对公开应用程序的 NLB 服务和节点端口的公共访问。 首先是阻止对节点端口的访问。

在第 2 课结束时,网络服务器应用程序仅通过公共 NLB 暴露于互联网。

  1. 在文本编辑器中,创建名为 deny-nodeports.yaml 的高位 DNAT 前策略,以拒绝来自任何源 IP 的入局 TCP 和 UDP 流量流至所有节点端口。

    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. 将上一课中创建的 LoadBalancer 的 externalTrafficPolicy 从 Cluster 更改为 LocalLocal 可确保在下一步卷曲 LoadBalancer 的外部 IP 时保留系统的源 IP。

    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。 反之,如果通过代理或 VPN 连接到因特网,代理或 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 的所有入局 TCP 和 UDP 流量流至 NLB IP 地址和端口。 用备忘单上的NLB公共IP地址替换 <loadbalancer_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 的低优先级预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 地址的异常流量外,您需要确保允许其他所有流量。 在这种情况下,denylist很有用,因为它可以帮助您防止来自一小部分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 的所有入局 TCP 和 UDP 流量流至 NLB IP 地址和端口。

  2. 要拒绝所有从系统源IP地址到NLB IP地址和端口的TCP和UDP流量,请在文本编辑器中创建一个名为 blocklist.yaml 的低优先级预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 预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
      

后续步骤?