k8s

NetworkPolicy

介绍

应用部署到集群后,如果你希望在IP地址或端口层面(OSI 第3层或第4层)控制网络流量,则你可以考虑为集群中特定应用使用 Kubernetes 网络策略(NetworkPolicy)。

3层或者4层是依托于内核能力来实现的,它会解析3层或者4层数据包的包头,并做对应的iptables配置。

NetworkPolicy通过网络插件来实现。要使用NetworkPolicy,你必须使用支持 NetworkPolicy 的网络解决方案。创建一个 NetworkPolicy 资源对象而没有控制器来使它生效的话,是没有任何作用的。目前支持的插件有calico和cilium。

隔离和非隔离的 Pod

默认情况下,Pod 是非隔离的,它们接受任何来源的流量。

Pod 在被某 NetworkPolicy 选中时进入被隔离状态。一旦namespace中有 NetworkPolicy 选择了特定的Pod,该 Pod 会拒绝该 NetworkPolicy 所不允许的连接。

网络策略不会冲突,它们是累积的。如果任何一个或多个策略选择了一个 Pod,则该 Pod 受限于这些策略的入站(Ingress)/出站(Egress)规则的并集。因此评估的顺序并不会影响策略的结果。

NetworkPolicy定义了一个pod的入站和出站防火墙规则。为了允许两个 Pods 之间的网络数据流,源端 Pod 上的出站(Egress)规则和目标端 Pod 上的入站(Ingress)规则都需要允许该流量。如果源端的出站(Egress)规则或目标端的入站 (Ingress)规则拒绝该流量,则流量將被拒绝。

安全策略属性

  • spec: NetworkPolicy 规约中包含了在一个名字空间中定义特定网络策略所需的所有信息。
  • podSelector:
    • 每个 NetworkPolicy 都包括一个 podSelector, 它对该策略所适用的一组 Pod 进行选择。
    • 空的 podSelector 选择名字空问下的所有 Pod。
  • policyTypes:
    • 每个 NetworkPolicy 都包含一个 policyTypes 列表,其中包含 Ingress 或 Egress或两者兼具。
    • 如果 NetworkPolicy 未指定 policyTypes 则默认情况下始终设置 Ingress;
    • 如果 NetworkPolicy 有任何出口规则的话则设置 Egress。
  • Ingress:
    • 每个 NetworkPolicy 可包含一个 Ingress 规则的白名单列表。
    • 每个规则都允许同时匹配 from 和 ports 部分的流量。
  • Egress:
    • 每个 NetworkPolicy 可包含一个 Egress规则的白名单列表。
    • 每个规则都允许匹配 to 和 port 部分的流量。

NetworkPolicy 默认策略

默认拒绝所有入站流量

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
spec:
    podSelector: {}
    policyTypes:
    - Ingress

默认允许所有入站流量

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-all-ingress
spec:
    podSelector: {}
    ingress:
    - {}
    policyTypes:
    - Ingress

默认允许所有出站流量

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-all-egress
spec:
    podSelector: {}
    egress:
    - {}
    policyTypes:
    - Egress

默认拒绝所有入口和所有出站流量

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
spec:
    podSelector: {}
    policyTypes:
    - Ingress
    - Egress

一个例子

file

calico的NetworkPolicy

NetworkPolicy 是命名空间级别资源。规则应用于与标签选择器匹配的 endpoint 的集合。
calico在原生对象的基础上对ingress/egrss做了一些扩展,可以定义具体的流量规则。

GlobalNetworkPolicy

GlobalNetworkPolicy 与 NetworkPolicy 功能一样,是整个集群级别的资源。
GlobalNetworkPolicy 会在集群中所有 Namespace 生效,并且能限制主机(HostEndpoint),即可以限制pod和主机之间的通信。

实例

  1. 创建calico-demo ns,并创建nginx pod。
    cat serverpod.yaml
    apiVersion: v1
    kind: Namespace
    metadata:
    name: calico-demo
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
    namespace: calico-demo
    name: calico-demo
    labels:
    app: calico-demo
    spec:
    replicas: 1
    selector:
    matchLabels:
      app: calico-demo
    template:
    metadata:
      labels:
        app: calico-demo
        access: "true"
    spec:
      containers:
        - name: calico-demo
          image: nginx
          ports:
            - containerPort: 80

  2. 在default和calico-demo中创建toolbox客户端(centos),等会测试连接nginx服务端。
    cat toolbox.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
    #  namespace: default
    name: toolbox
    spec:
    replicas: 1
    selector:
    matchLabels:
      app: toolbox
    template:
    metadata:
      labels:
        app: toolbox
        access: "true"
    spec:
      containers:
        - name: toolbox
          image: centos
          command:
            - tail
            - -f
            - /dev/null
    k get po -A -o wide| grep -E 'toolbox|calico-demo'

  3. 分别连接toolbox,测试ping和curl,都是通的。
    k exec -it toolbox-68f79dd5f8-zxzmd -- bash
    ping 10.100.104.34
    curl 10.100.104.34
    k exec -it toolbox-68f79dd5f8-vc25n -n calico-demo -- bash
    ping 10.100.104.34
    curl 10.100.104.34


  4. 创建默认NetworkPolicy,拒绝所有ingress。
    cat networkpolicy.yaml
    kind: NetworkPolicy
    apiVersion: networking.k8s.io/v1
    metadata:
    name: default-deny
    namespace: calico-demo
    spec:
    podSelector: {}
    k apply -f networkpolicy.yaml

    file

  5. 再次测试ping和curl,都不通了,说明防火墙规则生效。

  6. 创建GlobalNetworkPolicy,允许icmp协议。(注意:如果你是一边用wordpress写博客,一边做实验,一定要在apply之前保存草稿,因为apply后wordpress会无法访问!!!55555)
    cat allow-icmp-incluster.yaml
    apiVersion: projectcalico.org/v3
    kind: GlobalNetworkPolicy
    metadata:
    name: allow-ping-in-cluster
    spec:
    selector: all()
    types:
    - Ingress
    ingress:
    - action: Allow
      protocol: ICMP
      source:
        selector: all()
      icmp:
        type: 8 # Ping request
    - action: Allow
      protocol: ICMPv6
      source:
        selector: all()
      icmp:
        type: 128 # Ping request
    k get gnp

  7. 测试ping,两个都通了。

  8. 创建NetworkPolicy,允许default中http80的访问。
    cat access-calico-demo.yaml
    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
    name: allow-http
    namespace: calico-demo
    spec:
    podSelector: {}
    ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: default
      ports:
        - protocol: TCP
          port: 80
  9. 再次测试curl。
    calico-demo不通。

    default通。

calico防火墙规则

在calico-system中的calico-node有NetworkPolicy的控制器,它会监听当前节点上的NetworkPolicy,并在主机上完成防火墙配置。

查看calico防火墙规则

iptables-save  | grep cali
# 生成一个cali-INPUT的chain
:cali-INPUT - [0:0]
# 所有入站的流量都要转到cali-INPUT中
-A INPUT -m comment --comment "cali:Cz_u1IQiXIMmKD4c" -j cali-INPUT
# -i cali+ 正则匹配,指的是所有cali开头的网卡执行后面的规则-g cali-wl-to-host
-A cali-INPUT -i cali+ -m comment --comment "cali:VbO71h2UT7k5EQSJ" -g cali-wl-to-host
# 接收到流量请求后首先看connection tracking table连接表,如果这个连接是之前已经建立的,就放行accept
-A cali-tw-cali1bb11b52805 -m comment --comment "cali:piclZH4STH-kg8zX" -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
# 如果是新的连接就拒绝drop掉
-A cali-tw-cali1bb11b52805 -m comment --comment "cali:NA_KTHLVme9i6l69" -m conntrack --ctstate INVALID -j DROP
# 如果启用了NetworkPolicy,那么calico会把所有的数据包打上0x0/0x20000的标
-A cali-tw-cali8846877f208 -m comment --comment "cali:13XI1h8ZwKJTm9ot" -m comment --comment "Start of policies" -j MARK --set-xmark 0x0/0x20000
# 匹配0x0/0x20000的标,有就丢弃drop,这就是为什么开启NetworkPolicy后网络不通了的原因。
-A cali-tw-cali8846877f208 -m comment --comment "cali:eqqgCJs2qk0AO0ab" -m comment --comment "Drop if no policies passed packet" -m mark --mark 0x0/0x20000 -j DROP

file

开启icmp的GlobalNetworkPolicy后,防火墙规则如下:

# 所有打了0x0/0x20000标的都转到cali-pi-_1GuvcY/2yw4bHzL8wH
-A cali-tw-cali23a582ef038-m comment --comment "cali:nuuVD6tedS2uGLLB" -m mark --mark 0x0/0x20000 -j cali-pri-_4yi5_iSUAwsU8zMHTk
# 查看协议是否是icmp,如果是的话,就给数据包打上0x10000/0x10000的标
-A cali-pi-_1GuvcY/2yw4bHzL8wH -p icmp -m comment --comment "cali:--CtA5SGB7G86H8e" -m set --match-set cali40s:5y5I3VdRZfDU01O--XXAPx2 src -m icmp --icmp-type 8 -j MARK --set-xmark 0x10000/0x10000
# 如果数据包的标是0x10000/0x10000,就之间return掉,就不往下走了,不会匹配到上面的20000 drop,ping就通了。
-A cali-pi-_1GuvcY/2yw4bHzL8wH- -m comment --comment "cali:1SlOswLbnXZNBbt9" -m mark --mark Ox10000/0x10000 -j RETURN

总结

这个实例中只是单一的icmp协议,实际的NetworkPolicy iptables会很复杂,可以来自不同的源,使用不同的协议,访问不通的端口。

如果需要排查网络层的时候,第一是看iptables规则,filter表;第二是使用tcpdump看数据包的流向;第三如果数据包被丢弃了,系统的dmesg中也可以看到。

实际使用的话,一般是创建一个默认规则拒绝所有,然后再针对性的开墙,保证应用的安全。

分类: k8s
0 0 投票数
文章评分
订阅评论
提醒
guest

0 评论
最旧
最新 最多投票
内联反馈
查看所有评论

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部
0
希望看到您的想法,请您发表评论x