Calico 网络策略

发布时间 2023-08-30 18:18:03作者: 小吉猫

Calico 的网络策略

Calico支持GlobalNetworkPolicy和NetworkPolicy两种资源,前者用于定义集群全局网络策略,而后者大致可看作Kubernetes NetworkPolicy的一个超集。
Calico 网络策略提供了比 Kubernetes 更丰富的策略功能,包括:策略排序/优先级、拒绝规则和更灵活的匹配规则。虽然 Kubernetes 网络策略仅适用于 Pod,但 Calico 网络策略可以应用于多种类型的端点,包括 Pod、VM 和主机接口。最后,当与 Istio 服务网格一起使用时,Calico 网络策略支持保护应用程序第 5-7 层匹配标准和加密身份。
策略会立即应用于任何新连接。但是,对于已打开的现有连接,策略更改仅在重新建立连接后才会生效。这意味着任何正在进行的会话可能不会立即反映策略更改,直到再次启动为止。

Calico NetworkPolicy 特点

▪ 策略可以应用于任何类型的端点:pod/容器、虚拟机和/或主机接口
▪ 策略可以定义适用于入口、出口或两者的规则
▪ 政策规则支持:
  ▪ 操作:允许、拒绝、记录、通过
  ▪ 源和目的地匹配标准:
    ▪ 端口:编号、范围内的端口和 Kubernetes 命名端口
    ▪ 协议:TCP、UDP、ICMP、SCTP、UDPlite、ICMPv6、协议号 (1-255)
    ▪ HTTP 属性(如果使用 Istio 服务网格)
    ▪ ICMP 属性
    ▪ IP版本(IPv4、IPv6)
    ▪ IP 或 CIDR
    ▪ Endpoint 选择器(使用标签表达式来选择 Pod、VM、主机接口和/或网络集)
    ▪ 名称空间选择器
    ▪ Service account 选择器
▪ 可选的数据包处理控制:禁用连接跟踪、在 DNAT 之前应用、应用于转发流量和/或本地终止流量

Calico 的网络策略概念

Endpoints

Calico 网络策略适用于端点。在 Kubernetes 中,每个 pod 都是一个 Calico 端点。但是,Calico 可以支持其他类型的端点。Calico 端点有两种类型:工作负载端点(例如 Kubernetes Pod 或 OpenStack VM)和主机端点(主机上的一个接口或一组接口)。

Namespaced and global network policies

Calico network policy 是一个名称空间资源,适用于该名称空间中的 pod/容器/VM。
apiVersion: projectcalico.org/v3
kind: NetworkPolicy
metadata:
  name: allow-tcp-6379
  namespace: production
Calico global network policy 是一种非名称空间资源,可以应用于独立于名称空间的任何类型的端点(Pod、VM、主机接口)。

Ingress and egress

每个网络策略规则适用于入口或出口流量。从端点(Pod、VM、主机接口)的角度来看,入口是端点的传入流量,出口是端点的传出流量。在 Calico 网络策略中,您可以独立创建入口和出口规则(出口、入口或两者)。

您可以使用types字段指定策略是否应用于入口、出口或两者。如果您不使用 types 字段,Calico 默认为以下值。
存在 Ingress 规则吗? 存在 Egress 规则吗? Value
No No Ingress
Yes No Ingress
No Yes Egress
Yes Yes Ingress, Egress

网络流量行为:拒绝和允许

Kubernetes 网络策略规范定义了以下行为:
  ▪ 如果没有网络策略应用于 Pod,则允许进出该 Pod 的所有流量。
  ▪ 如果一个或多个网络策略应用于包含入口规则的 Pod,则仅允许这些策略明确允许的入口流量。
  ▪ 如果一个或多个网络策略应用于包含出口规则的 Pod,则仅允许这些策略明确允许的出口流量。
为了与 Kubernetes 兼容,Calico 网络策略对 Kubernetes Pod 遵循相同的行为。对于其他端点类型(VM、主机接口),Calico 网络策略默认为拒绝。也就是说,即使没有网络策略应用于端点,也仅允许网络策略明确允许的流量。

Calico NetworkPolicy 资源清单

apiVersion: projectcalico.org/v3                 # 资源隶属的API群组及版本号
kind: NetworkPolicy                              # 资源类型的名称
metadata:                                        # 资源元数据
  name <string>                                  # 资源名称标识
  namespace <string>                             # NetworkPolicy是名称空间级别的资源,默认值: "default"
spec:                                            # 期望的状态
  order: 0.0                                     # 策略叠加时的应用次序,数字越小越先应用,冲突时,后者会覆盖前者.策略应用目标为非指定名称空间中的所有端点
  selector: role == 'database'                   # 选择应用此策略的端点。 默认值:all()
  types:                                         # Ingress表示生效ingress字段;Egress表示生效egress字段,同时提供表示二者均有效
    - Ingress
    - Egress
  ingress:                                       # 入站流量源端点对象列表,即白名单.
    - action: Allow                              # 匹配此规则时执行的操作。可选值:Allow, Deny, Log, Pass
      metadata:                                  # 规则资源元数据
        annotations:
          from: frontend
          to: database
      protocol: TCP                              # 传输层协议名称,可选值:TCP, UDP, ICMP, ICMPv6, SCTP, UDPLite, 1-255
      notProtocol:                              # Negative protocol match。可选值:TCP, UDP, ICMP, ICMPv6, SCTP, UDPLite, 1-255
      icmp:                                     # ICMP 匹配标准
        type:8  Ping request
        code:
      notICMP:                                  # Negative match on ICMP.
        type:8  Ping request
        code:
      ipVersion:                                # IP 版本匹配, 可选值:4,6
      source:                                    # 源匹配参数
        selector: role == 'frontend'             # 选定端点上的正则匹配。如果还定义了namespaceSelector,则应用该选项的端点集仅限于选定名称空间中的端点。
        notSelector:
        nets:                                   # 将数据包与任何列出的 CIDR 中的 IP 进行匹配。
        notNets:
        namespaceSelector:                      # Positive match on selected namespaces. If specified, only workload endpoints in the selected Kubernetes namespaces are matched. Matches namespaces based on the labels that have been applied to the namespaces. Defines the scope that selectors will apply to, if not defined then selectors apply to the NetworkPolicy's namespace. Match a specific namespace by name using the projectcalico.org/name label. Select the non-namespaced resources like GlobalNetworkSet(s), host endpoints to which this policy applies by using global() selector.
        ports:                                  # Positive match on the specified ports	 
          - 8080                                 # int
          - '1234:5678'                          # start:end ,示例:6040:6050
          - 'named-port'                         # 命名端口,在一个或多个端点的端口列表中定义
        notPorts:                               # Negative match on the specified ports	
        serviceAccounts:                        # Match endpoints running under service accounts. If a namespaceSelector is also defined, the set of service accounts this applies to is limited to the service accounts in the selected namespaces.
          names:                                # 按名称匹配服务帐户
          selector:                             # 按标签匹配服务帐户
        services:                               # Match the specified service(s). If specified on egress rule destinations, no other selection criteria can be set. If specified on ingress rule sources, only positive or negative matches on ports can be specified.
          name:<string>                         # 服务的名称。                    
          namespace:<string>                    # 服务所在的命名空间
      destination:                               # 目标匹配参数
        selector: role == 'frontend'
        notSelector:
        nets:                                   # 将数据包与任何列出的 CIDR 中的 IP 进行匹配。
        notNets:
        namespaceSelector:                      # Positive match on selected namespaces. If specified, only workload endpoints in the selected Kubernetes namespaces are matched. Matches namespaces based on the labels that have been applied to the namespaces. Defines the scope that selectors will apply to, if not defined then selectors apply to the NetworkPolicy's namespace. Match a specific namespace by name using the projectcalico.org/name label. Select the non-namespaced resources like GlobalNetworkSet(s), host endpoints to which this policy applies by using global() selector.
        ports:                                  # Positive match on the specified ports	 
          - 8080                                 # int
          - '1234:5678'                          # start:end ,示例:6040:6050
          - 'named-port'                         # 命名端口,在一个或多个端点的端口列表中定义
        notPorts:                               # Negative match on the specified ports	
        serviceAccounts:                        # Match endpoints running under service accounts. If a namespaceSelector is also defined, the set of service accounts this applies to is limited to the service accounts in the selected namespaces.
          names:                                # 按名称匹配服务帐户
          selector:                             # 按标签匹配服务帐户
        services:                               # Match the specified service(s). If specified on egress rule destinations, no other selection criteria can be set. If specified on ingress rule sources, only positive or negative matches on ports can be specified.
          name:<string>                         # 服务的名称。                    
          namespace:<string>                    # 服务所在的命名空间
      http:                                     # 匹配HTTP请求参数。必须启用应用层策略才能使用此字段。
        methods: ['GET', 'PUT']
        paths:
          - exact: '/projects/calico'
          - prefix: '/users'
  egress:                                        # 出站流量目标端点对象列表,即白名单.
    - action: Allow
      ...
  serviceAccountSelector:                       # 选择应用此策略的服务帐户。使用projectcalico.org/name 标签按名称选择特定服务帐户。默认值:all()

控制namespace中端点的流量策略示例

相同的namespace

以下示例中,允许production 名称空间中带有color == 'blue'标签的所有 Pod 连接到 production 名称空间下的带有 color == 'red' 标签的所有 Pod 的 6379 TCP 端口。
apiVersion: projectcalico.org/v3
kind: NetworkPolicy
metadata:
  name: allow-tcp-6379
  namespace: production
spec:
  selector: color == 'red'
  ingress:
    - action: Allow
      protocol: TCP
      source:
        selector: color == 'blue'
      destination:
        ports:
          - 6379

不同的namespace

以下示例中,允许带有标签 shape == 'circle' 名称空间中带有color == 'blue'标签的所有 Pod 连接到 production 名称空间下的带有 color == 'red' 标签的所有 Pod 的 6379 TCP 端口。
apiVersion: projectcalico.org/v3
kind: NetworkPolicy
metadata:
  name: allow-tcp-6379
  namespace: production
spec:
  selector: color == 'red'
  ingress:
    - action: Allow
      protocol: TCP
      source:
        selector: color == 'blue'
        namespaceSelector: shape == 'circle'
      destination:
        ports:
          - 6379

Calico GlobalNetworkPolicy 策略示例

以下示例中,拒绝带有color == 'blue'标签的所有 Pod 连接到带有 color == 'red' 标签的所有 Pod TCP 的流量。
apiVersion: projectcalico.org/v3
kind: GlobalNetworkPolicy
metadata:
  name: deny-blue
spec:
  selector: color == 'red'
  ingress:
    - action: Deny
      protocol: TCP
      source:
        selector: color == 'blue'

使用 IP 地址或 CIDR的网络策略示例

以下示例中,允许production 名称空间中带有color == 'red'标签且Pod IP地址在1.2.3.0/24内的所有 Pod的流量允许传出。 
apiVersion: projectcalico.org/v3
kind: NetworkPolicy
metadata:
  name: allow-egress-external
  namespace: production
spec:
  selector: color == 'red'
  types:
    - Egress
  egress:
    - action: Allow
      destination:
        nets:
          - 1.2.3.0/24

按照特定顺序应用网络策略

以下示例中,策略叠加时的应用次序,数字越小越先应用,冲突时,后者会覆盖前者. order: 10策略优先。
apiVersion: projectcalico.org/v3
kind: GlobalNetworkPolicy
metadata:
  name: drop-other-ingress
spec:
  order: 20
  #...deny policy rules here...
apiVersion: projectcalico.org/v3
kind: GlobalNetworkPolicy
metadata:
  name: allow-cluster-internal-ingress
spec:
  order: 10
  #...allow policy rules here...

生成特定流量的日志示例

在以下示例中,应用程序的传入 TCP 流量被拒绝,并且每次连接尝试都会记录到系统日志中。
apiVersion: projectcalico.org/v3
kind: NetworkPolicy
Metadata:
  name: allow-tcp-6379
  namespace: production
Spec:
  selector: role == 'database'
  types:
    - Ingress
    - Egress
  ingress:
    - action: Log
      protocol: TCP
      source:
        selector: role == 'frontend'
    - action: Deny
      protocol: TCP
      source:
        selector: role == 'frontend'

访问特定名称空间中svc策略示例

出口流量

在以下示例中,对于名称空间 my-app 中的所有 pod,允许访问 default 命名空间中的 kubernetes 服务。
apiVersion: projectcalico.org/v3
kind: NetworkPolicy
metadata:
  name: allow-api-access
  namespace: my-app
spec:
  selector: all()
  egress:
    - action: Allow
      destination:
        services:
          name: kubernetes
          namespace: default

入口流量

在以下示例中,对于名称空间 backend 中的所有 Pod TCP协议的 80端口,允许来自 frontend 名称空间中的 frontend-service 服务的入口流量。这允许 frontend-service 服务的所有 pod 向 backend 名称空间中的所有 pod 的80端口发送流量。
apiVersion: projectcalico.org/v3
kind: NetworkPolicy
metadata:
  name: allow-frontend-service-access
  namespace: backend
spec:
  selector: all()
  ingress:
    - action: Allow
      protocol: TCP
      source:
        services:
          name: frontend-service
          namespace: frontend
      destination:
        ports: [80]

serviceAccount 网络策略示例

按 ServiceAccount 名称限制流量

在以下示例中,允许来自其服务帐户 api-service 或 user-auth-service 匹配的任何工作负载的入口流量。
apiVersion: projectcalico.org/v3
kind: NetworkPolicy
metadata:
  name: demo-calico
  namespace: prod-engineering
spec:
  ingress:
    - action: Allow
      source:
        serviceAccounts:
          names:
            - api-service
            - user-auth-service
  selector: 'app == "db"'

按 ServiceAccount 标签选择器限制流量

在以下示例中,允许来自其带有标签选择器 app == web-frontend 的服务帐户匹配的任何工作负载的入口流量。
apiVersion: projectcalico.org/v3
kind: NetworkPolicy
metadata:
  name: allow-web-frontend
  namespace: prod-engineering
spec:
  ingress:
    - action: Allow
      source:
        serviceAccounts:
          selector: 'app == "web-frontend"'
  selector: 'app == "db"'

参考文档

https://docs.tigera.io/calico/latest/network-policy/