目录
1、NetworkPolicy概述
官方说明:网络策略(NetworkPolicy)是一种关于pod
间及pod
与其他网络端点间所允许的通信规则的规范。
简单来说,NetworkPolicy
就是对pod
进行网络策略控制。用于为Kubernetes
实现更为精细的流量控制,实现租户隔离机制。Kubernetes
使用标准的资源对象NetworkPolicy
供管理员按需定义网络访问控制策略。
2、NetworkPolicy策略模型
使用network policy
资源可以配置pod
的网络,networkPolicy
是namespace scoped
的,他只能影响某个namespace
下的pod
的网络出入站规则。
metadata
描述信息。podSelector
pod选择器,选定的pod
所有的出入站流量要遵循本networkpolicy
的约束。policyTypes
策略类型。包括了Ingress
和Egress
,默认情况下一个policyTypes
的值一定会包含Ingress
,当有egress
规则时,policyTypes
的值中会包含Egress
。ingress
入站,即由其他网络端点发往特定Pod
组的流量 ,通常由流量发出的源站点from
和流量的目标端口所定义 。egress
出站,即由特定的Pod
组发往其他网络端点的流量 ,通常由流量的目标网络端点to
和端口ports
来进行定义 。port
端口,TCP
或UDP
的端口号。to,from
端点,流量目标和流量源相关的组件, 它可以是CIDR
格式的IP
地址块ipBlock
、网络名称空间选择器namespaceSelector
匹配的名称空间, 或Pod
选择器podSelector
匹配的Pod
组。
对官方示例的说明:
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: test-network-policy namespace: default spec: podSelector: matchLabels: role: db policyTypes: - Ingress - Egress ingress: - from: - ipBlock: cidr: 172.17.0.0/16 except: - 172.17.1.0/24 - namespaceSelector: matchLabels: project: myproject - podSelector: matchLabels: role: frontend ports: - protocol: TCP port: 6379 egress: - to: - ipBlock: cidr: 10.0.0.0/24 ports: - protocol: TCP port: 5978
该例子的效果如下:
1、default namespace
下label
包含role=db
的pod
,都会被隔绝,他们只能建立满足networkPolicy
的ingress
和egress
描述的连接。即2-5点:
2、所有属于172.17.0.0/16
网段的ip,除了172.17.1.0/24
中的ip,其他的都可以与上述pod
的6379
端口建立tcp
连接。
3、所有包含label:project=myproject
的namespace
中的pod
可以与上述pod
的6379
端口建立tcp
连接;
4、所有default namespace
下的label
包含role=frontend
的pod
可以与上述pod
的6379
端口建立tcp
连接;
5、允许上述pod
访问网段为10.0.0.0/24
的目的ip
的5978
端口。
3、NetworkPolicy默认策略
默认情况下,如果名称空间中不存在任何策略,则所有进出该名称空间中的Pod的流量都被允许。以下示例用于更改该名称空间中的默认行为。
- 默认拒绝所有入口流量
通过创建选择所有容器但不允许任何进入这些容器的入口流量的NetworkPolicy
来为名称空间创建default
隔离策略。这样可以确保即使容器没有选择其他任何NetworkPolicy
,也仍然可以被隔离。此策略不会更改默认的出口隔离行为。
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: default-deny spec: podSelector: {} policyTypes: - Ingress
- 默认允许所有入口流量
如果要允许所有流量进入某个命名空间中的所有Pod
(即使添加了导致某些Pod
被视为“隔离”的策略),则可以创建一个策略来明确允许该命名空间中的所有流量。
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-all spec: podSelector: {} ingress: - {} policyTypes: - Ingress
- 默认拒绝所有出口流量
通过创建选择所有容器但不允许来自这些容器的任何出口流量的NetworkPolicy
来为名称空间创建default egress
隔离策略。这样可以确保即使没有被其他任何NetworkPolicy
选择的Pod
也不会被允许流出流量。此策略不会更改默认的ingress
隔离行为。
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: default-deny spec: podSelector: {} policyTypes: - Egress
- 默认允许所有出口流量
如果要允许来自命名空间中所有Pod
的所有流量(即使添加了导致某些Pod
被视为“隔离”的策略),则可以创建一个策略,该策略明确允许该命名空间中的所有出口流量。
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-all spec: podSelector: {} egress: - {} policyTypes: - Egress
- 默认拒绝所有入口和所有出口流量
为名称空间创建default
策略,以通过在该名称空间中创建以下NetworkPolicy
来阻止所有入站和出站流量。这样可以确保即使没有被其他任何NetworkPolicy
选择的Pod
也不会被允许进入或流出流量。
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: default-deny spec: podSelector: {} policyTypes: - Ingress - Egress
4、NetworkPolicy的实现
kubernetes
的网络策略功能本身并不支持,依赖其所使用的网络插件实现。因此,仅在使用那些支持网络策略功能的网络插件时才能够配置网络策略,企业内部可以使用简单的flannel
、weave
、kube-router
等,适合公有云的方案则有calico
等。不同的网络实现原理vethpair
、bridge
、macvlan
等并不能统一地支持network policy
。每种解决方案各有其特定的网络策略实现方式,它们的实现或依赖于节点自身的功能,或借助于Hypervisor
的特性,也可能是网络自身的功能 。究其最终的底层实现原理,目前是基于linux iptables
实现,使用类似于nf_conntrack
检查记录网络流量session
从而决定流量是否阻断。
5、使用flannel+canal实现k8s的NetworkPolicy
Flannel
是解决容器网络方案最为普遍和简单的方案,Canal
代表了针对云原生应用程序的最佳网络策略解决方案,旨在让用户轻松的将Calico
和Flannel
网络部署在一起作为统一的网络解决方案,将Calico
的网络策略执行和Flannel
的叠加及非叠加网络连接选项的丰富功能相结合。
在Calico
的官方文档的相应部分中描述到此种方案是:用于策略的Calico
和用于网络的Flannel
相组合。官方文档见:https://docs.projectcalico.org/v3.10/getting-started/kubernetes/installation/flannel
5.1、实验环境说明
实验k8s环境是kubeadm
搭建的1master+2node最新版本1.16.2版本k8s,cni
版本为0.3.1,flannel
版本为0.11.0,flannel
后端是vxlan
模式并且已经开启了Directrouting
。
[root@k8s-master-01 ~]# kubectl version Client Version: version.Info{Major:"1", Minor:"16", GitVersion:"v1.16.2", GitCommit:"c97fe5036ef3df2967d086711e6c0c405941e14b", GitTreeState:"clean", BuildDate:"2019-10-15T19:18:23Z", GoVersion:"go1.12.10", Compiler:"gc", Platform:"linux/amd64"} Server Version: version.Info{Major:"1", Minor:"16", GitVersion:"v1.16.2", GitCommit:"c97fe5036ef3df2967d086711e6c0c405941e14b", GitTreeState:"clean", BuildDate:"2019-10-15T19:09:08Z", GoVersion:"go1.12.10", Compiler:"gc", Platform:"linux/amd64"} [root@k8s-master-01 ~]# kubectl get nodes NAME STATUS ROLES AGE VERSION k8s-master-01 Ready master 4d1h v1.16.2 k8s-node-01 Ready <none> 4d v1.16.2 k8s-node-02 Ready <none> 4d v1.16.2 [root@k8s-master-01 ~]# kubectl get pods -n kube-system NAME READY STATUS RESTARTS AGE coredns-58cc8c89f4-bd6s8 1/1 Running 2 4d1h coredns-58cc8c89f4-bv5rl 1/1 Running 2 4d1h etcd-k8s-master-01 1/1 Running 2 4d1h kube-apiserver-k8s-master-01 1/1 Running 2 4d1h kube-controller-manager-k8s-master-01 1/1 Running 2 4d1h kube-flannel-ds-amd64-grzvh 1/1 Running 1 2d22h kube-flannel-ds-amd64-hrd4h 1/1 Running 1 2d22h kube-flannel-ds-amd64-l8rtk 1/1 Running 1 2d22h kube-proxy-bp98z 1/1 Running 2 4d kube-proxy-kvwgh 1/1 Running 2 4d kube-proxy-n8lj6 1/1 Running 2 4d1h kube-scheduler-k8s-master-01 1/1 Running 2 4d1h
5.2、安装canal
按照官方文档说明安装:https://docs.projectcalico.org/v3.10/getting-started/kubernetes/installation/flannel
部署时canal支持将数据存储于etcd中,支持选择专用的etcd存储,也能够以kubernetes api server作为后端存储,这里选择以后种方式进行。
结合flannel
工作时,Calico
提供的默认配置清单中是以flannel
默认使用的10.244.0.0/16
为Pod
网络,因此,请确保kube-controller-manager
程序在启动时通过--clustr-cidr
选项设置使用了此网络地址,并且--allocate-node-cidrs
的值应设置为true
。在使用kubeadm
安装的此版本集群中,此选项均已配置。
如果集群cidr网络地址不是默认值,需要修改配置再进行部署。
[root@k8s-master-01 canal]# curl https://docs.projectcalico.org/v3.10/manifests/canal.yaml -O [root@k8s-master-01 canal]# kubectl apply -f canal.yaml configmap/canal-config created customresourcedefinition.apiextensions.k8s.io/felixconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamblocks.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/blockaffinities.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamhandles.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamconfigs.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/bgppeers.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/bgpconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ippools.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/hostendpoints.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/clusterinformations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/globalnetworkpolicies.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/globalnetworksets.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/networkpolicies.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/networksets.crd.projectcalico.org created clusterrole.rbac.authorization.k8s.io/calico-node created clusterrole.rbac.authorization.k8s.io/flannel configured clusterrolebinding.rbac.authorization.k8s.io/canal-flannel created clusterrolebinding.rbac.authorization.k8s.io/canal-calico created daemonset.apps/canal created serviceaccount/canal created [root@k8s-master-01 ~]# kubectl get pods -n kube-system -o wide|grep canal canal-rxb97 2/2 Running 0 4h25m 192.168.2.12 k8s-node-02 <none> <none> canal-tdcgf 2/2 Running 0 4h25m 192.168.2.10 k8s-master-01 <none> <none> canal-vll8z 2/2 Running 0 4h25m 192.168.2.11 k8s-node-01 <none> <none>
5.3、应用示例
5.3.1、创建默认服务
运行一组nginx
pod并暴露80端口
[root@k8s-master-01 ~]# kubectl run nginx --image=nginx --replicas=3 --port=80 --expose kubectl run --generator=deployment/apps.v1 is DEPRECATED and will be removed in a future version. Use kubectl run --generator=run-pod/v1 or kubectl create instead. service/nginx created deployment.apps/nginx created [root@k8s-master-01 ~]# kubectl get pods NAME READY STATUS RESTARTS AGE nginx-5578584966-8spqk 1/1 Running 0 15s nginx-5578584966-sjlvc 1/1 Running 0 15s nginx-5578584966-xm4pb 1/1 Running 0 15s [root@k8s-master-01 ~]# kubectl get svc nginx NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE nginx ClusterIP 10.1.8.146 <none> 80/TCP 16s
5.3.2、测试访问
[root@k8s-master-01 ~]# kubectl run busy1 --rm -it --image=busybox /bin/sh kubectl run --generator=deployment/apps.v1 is DEPRECATED and will be removed in a future version. Use kubectl run --generator=run-pod/v1 or kubectl create instead. If you don't see a command prompt, try pressing enter. / # wget --spider --timeout=1 nginx Connecting to nginx (10.1.8.146:80) remote file exists ## 访问成功
5.3.4、创建默认policy
创建默认拒绝所有入站流量的networkpolicy,测试访问
[root@k8s-master-01 networkpolicy]# vim default-deny-ingress.yaml apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: default-deny spec: podSelector: {} policyTypes: - Ingress [root@k8s-master-01 networkpolicy]# kubectl apply -f default-deny-ingress.yaml networkpolicy.networking.k8s.io/default-deny created [root@k8s-master-01 ~]# kubectl run busy1 --rm -it --image=busybox /bin/sh kubectl run --generator=deployment/apps.v1 is DEPRECATED and will be removed in a future version. Use kubectl run --generator=run-pod/v1 or kubectl create instead. If you don't see a command prompt, try pressing enter. / # wget --spider --timeout=1 nginx Connecting to nginx (10.1.8.146:80) wget: download timed out ## 访问失败
5.3.5、创建一个允许带有access=true的Pod访问nginx的网络策略
[root@k8s-master-01 networkpolicy]# vim nginx-policy.yaml kind: NetworkPolicy apiVersion: networking.k8s.io/v1 metadata: name: access-nginx spec: podSelector: matchLabels: run: nginx ingress: - from: - podSelector: matchLabels: access: "true" [root@k8s-master-01 networkpolicy]# kubectl apply -f nginx-policy.yaml networkpolicy.networking.k8s.io/access-nginx created
使用不带access=true标签的pod访问服务
[root@k8s-master-01 ~]# kubectl run busy1 --rm -it --image=busybox /bin/sh kubectl run --generator=deployment/apps.v1 is DEPRECATED and will be removed in a future version. Use kubectl run --generator=run-pod/v1 or kubectl create instead. If you don't see a command prompt, try pressing enter. / # wget --spider --timeout=1 nginx Connecting to nginx (10.1.8.146:80) wget: download timed out ## 访问失败
使用带access=true标签的pod访问服务
[root@k8s-master-01 ~]# kubectl run busy2 --rm -it --labels="access=true" --image=busybox /bin/sh kubectl run --generator=deployment/apps.v1 is DEPRECATED and will be removed in a future version. Use kubectl run --generator=run-pod/v1 or kubectl create instead. If you don't see a command prompt, try pressing enter. / # wget --spider --timeout=1 nginx Connecting to nginx (10.1.8.146:80) remote file exists ## 访问成功
5.4、生产使用场景
5.4.1、禁止访问指定服务
kubectl run web --image=nginx --labels app=web,env=prod --expose --port 80
网络策略
kind: NetworkPolicy apiVersion: networking.k8s.io/v1 metadata: name: web-deny-all spec: podSelector: matchLabels: app: web env: prod
5.4.2、只允许指定pod访问服务
kubectl run apiserver --image=nginx --labels app=bookstore,role=api --expose --port 80
网络策略
kind: NetworkPolicy apiVersion: networking.k8s.io/v1 metadata: name: api-allow spec: podSelector: matchLabels: app: bookstore role: api ingress: - from: - podSelector: matchLabels: app: bookstore
5.4.3、禁止 namespace 中所有 Pod 之间的相互访问
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: default-deny namespace: default spec: podSelector: {}
5.4.4、禁止其他 namespace 访问服务
kubectl create namespace secondary kubectl run web --namespace secondary --image=nginx \ --labels=app=web --expose --port 80
网络策略
kind: NetworkPolicy apiVersion: networking.k8s.io/v1 metadata: namespace: secondary name: web-deny-other-namespaces spec: podSelector: matchLabels: ingress: - from: - podSelector: {}
5.4.5、只允许指定namespace访问服务
kubectl run web --image=nginx \ --labels=app=web --expose --port 80
网络策略
kind: NetworkPolicy apiVersion: networking.k8s.io/v1 metadata: name: web-allow-prod spec: podSelector: matchLabels: app: web ingress: - from: - namespaceSelector: matchLabels: purpose: production
5.4.6、允许外网访问服务
kubectl run web --image=nginx --labels=app=web --port 80 kubectl expose deployment/web --type=LoadBalancer
网络策略
kind: NetworkPolicy apiVersion: networking.k8s.io/v1 metadata: name: web-allow-external spec: podSelector: matchLabels: app: web ingress: - ports: - port: 80 from: []
参考来源:
https://kubernetes.io/zh/docs/concepts/services-networking/network-policies/
https://docs.projectcalico.org/v3.10/getting-started/kubernetes/installation/flannel
https://github.com/ahmetb/kubernetes-network-policy-recipes