网络策略(Network Policy),用于限制 Pod 出入流量,提供 Pod 级别和 Namespace 级别网络访问控制。

已知 flannel 目前并不支持网络策略,即使创建了也并不会应用,其它组件在使用网络策略时还请自行了解以下是否支持。

应用场景

  • 应用程序(Pod)间的访问控制。例如微服务 A ,允许访问微服务 B ,微服务 C 不能访问微服务 A
  • 开发环境命名空间不能访问测试环境命名空间 Pod
  • 当 Pod 暴露到外部时,需要做 Pod 白名单
  • 多租户网络环境隔离(使用项目较多)

Pod 网络隔离

其实是和物理机的网络隔离概念是同理的,分为 入口隔离出口隔离

Pod 网络入口方向隔离

  • 基于 Pod 级网络隔离:只允许特定对象访问 Pod(使用标签定义),允许白名单上的 IP 地址或者 IP 段访问 Pod
  • 基于 Namespace 级别网络隔离:多个命名空间,A 和 B 命名空间 Pod 完全隔离

Pod 网络出口方向隔离

  • 拒绝某个 Namespace 上所有的 Pod 访问外部
  • 基于目的 IP 的网络隔离:只允许 Pod 访问白名单上的 IP 地址或者 IP 段
  • 基于目标端口的网络隔离:只允许 Pod 访问白名单上的端口

应用示例1

需求:将 default 命名空间携带 app=web 标签的 pod 隔离,只允许 default 命名空间携带 run=client1 标签的 pod 访问 80 端口。

首先分析需求,将 default 命名空间携带 app=web 标签的 pod 隔离:意思是要对 app=web 标签的 pod 使用网络策略。只允许 default 命名空间携带 run=client1 标签的 pod 访问 80 端口:意思是携带 run=client1 标签的 pod 可以访问携带 run=web 标签的 pod 的80端口

准备测试环境

# 创建一个nginx pod
kubectl create deployment web --image=nginx
# 创建两个访问基础pod
kubectl run client1 --image=busybox:1.28 --command -- sleep 36000
kubectl run client2 --image=busybox:1.28 --command -- sleep 36000

查看测试环境:label这里使用的就是默认的 label 来做策略,所以不需要单独写 yaml 指定 label

# kubectl get pods --show-labels 
NAME                 READY   STATUS    RESTARTS   AGE     LABELS
client1              1/1     Running   0          1m15s   run=client1
client2              1/1     Running   0          1m10s   run=client2
web-96d5df5c8-sd9th  1/1     Running   0          1m20s   app=web,pod-template-hash=96d5df5c8

以上需求中的标签是默认生成的,改成自己需要的 label 即可。

在不使用网络策略的情况下,查看 web pod 的 ip ,进入 client1 中尝试访问,可以 ping 通,也可以 wget 到页面。client2 也是一样的。

$ kubectl exec -it client1 -- sh
/ # ping 192.168.146.100
PING 192.168.146.100 (192.168.146.100): 56 data bytes
64 bytes from 192.168.146.100: seq=0 ttl=63 time=0.239 ms
64 bytes from 192.168.146.100: seq=1 ttl=63 time=0.133 ms

/ # wget 192.168.146.100
Connecting to 192.168.146.100 (192.168.146.100:80)
index.html           100% |********************************************|   612   0:00:00 ETA
/ # cat index.html 
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

验证网络策略

清楚了需求,再来编写 yaml 文件

$ vim test-np.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: test-np
  namespace: default
spec:
  podSelector:  # 要针对哪些pod实施这个网络策略,根据pod的label选择
    matchLabels:
      app: web
  policyTypes:  # 策略类型,指定策略用于入站、出站流量
  - Ingress    # 入站策略,与前面的ingress区分,不一样
  ingress:  # 入站策略,以下两个策略合起来就是,default命名空间中的
  - from:
    - namespaceSelector: # namespace白名单,以下namespace中的pod可以访问
        matchLabels:
          project: default
    - podSelector:  # pod白名单,具有以下label的pod可以访问
        matchLabels:
          run: client1
    ports:  # 允许访问使用策略的pod的端口号
    - protocol: TCP
      port: 80   # 端口号

使用网络策略

kubectl apply -f test-np.yaml 

查看创建好的策略

$ kubectl get networkpolicies
NAME      POD-SELECTOR   AGE
test-np   app=web        4m4s

限制网络策略已经被应用,按照需求,现在 client1 应该可以访问到 web 的 80 端口的,client2 并访问不到

# client1
$ kubectl exec -it client1 -- sh
/ # ping 192.168.146.100
PING 192.168.146.100 (192.168.146.100): 56 data bytes
^C
--- 192.168.146.100 ping statistics ---
1 packets transmitted, 0 packets received, 100% packet loss
/ # wget 192.168.146.100
Connecting to 192.168.146.100 (192.168.146.100:80)
index.html           100% |********************************************|   612   0:00:00 ETA


# client2
$ kubectl exec -it client2 -- sh
/ # ping 192.168.146.100
PING 192.168.146.100 (192.168.146.100): 56 data bytes
^C
--- 192.168.146.100 ping statistics ---
2 packets transmitted, 0 packets received, 100% packet loss
/ # wget 192.168.146.100   # 很长时间才会报出错误
Connecting to 192.168.146.100 (192.168.146.100:80)
wget: can't connect to remote host (192.168.146.100): Connection timed out

通过以上访问验证,发现 client1 不可以 ping,但可以访问到 web 的 80 端口,而 client2 即 ping 不通,也访问不到 80 端口。已经达到了提出的需求。

应用示例2

为避免影响示例,将示例1的策略删除

kubectl delete -f test-np.yaml

需求:default 命名空间下所有 pod 可以互相访问,也可以访问其它命名空间 pod,但其它命名空间不能访问 default 命名空间 pod

分析需求,正常没有任何策略的情况下,pod 间都可以互相访问,包括不同命名空间也是一样可以访问,也就是只需要做到其它命名空间不能访问 default 命名空间的 pod 即可。入站策略就可以做到了

准备测试环境

依然使用示例1中的 web pod,因为涉及到多个命名空间,将 client1 在 kube-system 命名空间进行创建

kubectl run client1 --image=busybox:1.28 -n kube-system --command -- sleep 36000

在不使用网络策略的情况下,查看 web pod 的 ip ,进入 client1 中尝试访问,可以 ping 通,也可以 wget 到页面

$ kubectl exec -it client1 -n kube-system -- sh
/ # ping 192.168.146.100
PING 192.168.146.100 (192.168.146.100): 56 data bytes
64 bytes from 192.168.146.100: seq=0 ttl=63 time=0.280 ms
^C
--- 192.168.146.100 ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 0.280/0.280/0.280 ms
/ # wget 192.168.146.100
Connecting to 192.168.146.100 (192.168.146.100:80)
index.html           100% |********************************************|   612   0:00:00 ETA

验证网络策略

清楚了需求,再来编写 yaml 文件

spec.podSelector: {} //如果为空,默认为对应命名空间下的所有pod应用该策略

spec.ingress.from.podSelector: {} //如果为空,默认只允许应用策略所在命名空间的pod之间访问,不允许非本命名空间的所有pod访问本命名空间的 pod。也就是需求中的 其它命名空间不能访问 default 命名空间 pod

$ vim test-np2.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: test-np2
  namespace: default
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  ingress:  
  - from:
    - podSelector: {}

使用网络策略

kubectl apply -f test-np2.yaml

查看创建好的策略

$ kubectl get networkpolicies
NAME       POD-SELECTOR   AGE
test-np2   <none>         37s

按照需求,现在 kube-system 命名空间的 client1 是访问不到 web 的。

$ kubectl exec -it client1 -n kube-system -- sh
/ # ping 192.168.146.100
PING 192.168.146.100 (192.168.146.100): 56 data bytes

策略实现原理

当用户创建好 networkpolicy 后,提交到 api,并写入到 etcd 中存储。有了网络策略后,最终的实现是由部署在集群中 CNI 插件来完成的。每个节点的 CNI pod 通过 API 获取到网络策略,并应用在自己节点,使用 iptables 或者 ipvs 来做网络策略。

评论




正在载入...
PoweredHexo
HostedAliyun
DNSAliyun
ThemeVolantis
UV
PV
BY-NC-SA 4.0