Network Policy
当我们部署Pod时,不同名称空间下的Pod可以同名,比如名称空间A下的xiong-nginx与名称空间B下的xiong-nginx,它们受k8s集群上同一个Pod plugin管理,它们只是名称空间隔离名称,而不隔离通信,这就意味着这种跨组织的通信安全或通信隔离将无从保障,而为了实现通信隔离,k8s引入了一个标准资源来允许用户获取一个名称空间之后,在自己所在名称空间来定义这个跨名称空间的Pod和Pod之间如何通信,以及名称空间内的Pod之间怎么通信, 这是一种标准的k8s资源:NetworkPolicy, 与传统的手写iptables或ipvs等访问策略不同,并且NetworkPolicy定义与其它资源类型没有什么区别;
这是一种标准的k8s资源:NetworkPolicy, 与传统的手写iptables或ipvs等访问策略不同,并且NetworkPolicy定义与其它资源类型没有什么区别;
比如Ingress, 在Ingress Contoller中的程序可以运行为Nginx、haproxy,在不同程序中它的配置文件是不一样的,因此为了避免用户在学习Ingress Controller应用程序的配置文件格式,k8s引入了一种标准资源就叫Ingress,我们直接使用Ingress格式定义Ingress规则之后,它就能够将其对应为应用程序的配置文件;
NetworkPolicy也是这样的,它允许我们就按照NetworkPolicy内部的逻辑来定义如何管控Pod间通信,而后由Kubernetes负责将其转为对应节点的iptables或者其他规则,我们可以定义指定名称空间的Pod决不允许任何其他名称空间的Pod访问即可,只要把这个策略一应用,而后Kubernetes就会负责将其转换,并对这一组Pod进行分组以及给它施加访问控制机制,这是真正在网络层控制了访问控制机制,因此网络策略能够将我们所期望实现的网络访问控制功能转换为对应的访问控制机制所能实现的规则;
Kubernetes大多数还是部署在Linux主机上的,如果我们的Kubernetes能够运行在Unix、FreeBSD或者OpenBSD之上,OpenBSD是内核级的访问控制不是iptables,它有自己的访问控制逻辑,所以不同的操作系统,在内核级完成流量访问控制控制逻辑不尽相同,那么NetworkPolicy就能够根据你的系统的机制和支持的网络访问控制逻辑,转换成对应操作系统级的规则,所以它也是一种一对多的实现逻辑,当然这种机制无非是由Kubernetes将底层操作系统的不同给隐藏起来,从而提供一个统一的中间层,仅此而已;
基础工作逻辑
网络策略的生效,一般而言是对某一名称空间中的Pod施加访问控制(一组\一个\或全部),如果说我们没有指明pod或者使用标签选择器,那默认就是这个名称空间中的全部Pod;
在k8s中它的NetworkPolicy对于名称空间当中的Pod访问控制大体上分为几种:
-
第一种:自己访问别人
自己访问别人规则可以定义为egress(出站),egress代表流量的出站访问,
-
第二种:别人访问自己;
而定义别人访问自己的规则可以定义为ingress(入站), ingress代表流量的入站方向
访问标识
Pod访问控制
- 名称空间中所有Pod
- 名称空间中能够被Pod Selector选择器能匹配到的一部分Pod;
- 直接使用IP标识或者来自于哪些网段的;
标识策略
- egress使用的to来标识,to表示出站报文,通常表示我们主动访问别人,还可以使用ports标识要访问对端服务器的哪个端口的服务;
- ingress使用的是from来标识,from表示入站报文,在from这里也可以使用ports标识允许自己哪个端口被访问;
策略说明
查看策略信息:
]# kubectl explain networkpolicy
Egress: # Pod访问远端, 需要定义目标地址端口, 出站规则
ports: # 目标端口
port: # 端口
protocol: # 协议
to : # 如果全定义取交集, 一般来说只定义一个, 目标地址
ipBlock: # ip地址段|块
cidr: # 允许的子网
except: # 排除不包含该地址
namespaceSelector: # 名称空间选择器
podSelector: # 控制pod之间通信
Ingress: # 远程访问客户端 Pod, 定义自身地址与端口,入站规则
from:
podSelector: # 定义是哪个pod
policyTypes: # 定义哪个规则生效,Egress | Ingress 可被同时定义, 不定义就是 两个都生效
示例
前提: 两个名称空间: dev、qa, 配置两个名称空间之间的策略,因为Flannel是不具备网络策略功能的,如果要使用Flannel做网络策略那么还需要在Kubernetes集群之中加入一个网络策略插件calico;
前置yaml
]# kubectl create ns dev
]# kubectl create ns qa
]# kubectl get ns
NAME STATUS AGE
dev Active 3s
qa Active 1s
]# cat dev_canal.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-dev # my-qa
namespace: dev # 复制一下yaml 修改namespace
labels:
app: my-dev
spec:
replicas: 2
selector:
matchLabels:
app: my-dev-pod
template:
metadata:
name: my-dev
labels:
app: my-dev-pod
spec:
containers:
- name: my-dev
image: ikubernetes/myapp:v1
imagePullPolicy: IfNotPresent
]# kubectl get pods -n dev
NAME READY STATUS RESTARTS AGE
my-dev-9bd949df-l22pz 1/1 Running 0 104s
my-dev-9bd949df-phwz5 1/1 Running 0 104s
]# kubectl get pods -n qa
NAME READY STATUS RESTARTS AGE
my-qa-776ff8c68-l5ddp 1/1 Running 0 33s
my-qa-776ff8c68-q89tz 1/1 Running 0 33s
默认规则
如果只定义 Ingress, 而 policyTypes 定义了Egress, Ingress
那么生效的就是Egress的默认规则
拒绝\允许
]# cat netpol-dev.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: my-netpol-dev
namespace: dev # 与名称空间无关, 限制还是得根据 标签、地址段来进行限定
spec:
podSelector:
matchLabels:
app: my-dev-pod # 选择对应的pod
policyTypes:
- Ingress # 当Ingress 入站策略啥都不定义时,默认就是拒绝全部
- Engress # 当Engress 出站策略啥都不定义时,默认就是不能访问外网了
允许入站
-
允许全部
spec: ingress: - {} # 在spec段时添加 ingress: {} 啥都不定义的情况下就是全部允许
-
允许某个段访问 dev 名称空间
]# cat netpol-dev.yaml apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: my-netpol-dev namespace: dev spec: podSelector: matchLabels: app: my-dev-pod ingress: - from: - ipBlock: cidr: "10.244.1.0/24" except: - 10.244.1.3/32 policyTypes: - Ingress # 测试 qa两个Pod my-qa-776ff8c68-mnz87 1/1 Running 0 3s 10.244.2.3 slave2 my-qa-776ff8c68-nw8r5 1/1 Running 0 30s 10.244.1.6 slave1 # 当只允许1.0网段时,2.0网段过去都是拒绝的状态 ]# kubectl exec -it my-qa-776ff8c68-mnz87 -n qa -- /bin/sh / # wget -O - 10.244.1.2 / # wget -O - 10.244.2.2 Connecting to 10.244.1.2 (10.244.1.2:80) wget: can't connect to remote host (10.244.1.2): Operation timed out # 允许 1.0网段 ]# kubectl exec -it my-qa-776ff8c68-nw8r5 -n qa -- /bin/sh / # wget -O - 10.244.1.2 / # wget -O - 10.244.2.2 Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
Egress 出站策略与 Ingress类型差不多, 定义就得根据需求来划分了。
Calico
Calico官网, 支持BGP的方式来沟建Pod网络,通过BGP路由协议学习,能使得到每一节点生成到另一节点Pod之间的路由信息,支持动态修改路由。 同时也支持IPIP,Calico是一个三层隧道,如果期望在calico中实现隧道方式应用,那么应该设置为IPIP的方式。
当Calico做为网络插件服务时Calico网段: 192.168.0.0/16网段,每一个节点也会被分配成一个子网网络
部署安装说明
- 必须支持配置 CNI网络插件 --network-plugin=cni
- kube-proxy 必须使用 iptables模式
- kube-proxy 必须不能使用 --masquerade-all 模式, 其暂时还不支持ipvs
安装canal
- 安装时启动如下选项:
--cluster-cidr=
and--allocate-node-cidrs=true
- 下载flannel网络插件
curl https://docs.projectcalico.org/manifests/canal.yaml -O
- 使用pod cidr
10.244.0.0/16
, 如果是就跳过,不是就需要在yaml文件里修改 flannel network - 安装 calico:
kubectl apply -f canal.yaml
- 如果想用 TLS应用协议,就必须要启动 应用层协议
此时得到的架构如下