NetworkPolicy 网络策略介绍
基于NetworkPolicy在三层(网络层) 或 四层(传输层)控制拒绝或允许请求流量。
- 允许或拒绝特定的pod请求 目的namespace 中的 目的pod 的 所有或指定端口。
- 允许或拒绝特定的 namespace 请求 目的namespace 中的 所有或特定的pod 所有或指定端口。
- 允许或拒绝特定的 源IP范围 或 IP地址 请求 目的pod 的所有或特定端口。
- 默认的入口和出口的流量都是运行的
- pod不能拒绝自身对自身的访问(包没有经过内核 直接通过127.0.0.1通信了)
五元组
- 源端口
- 源IP
- 目标端口
- 目标IP
- 协议
环境准备
1.kubernetes 二进制环境,calico网络组件, 2个node节点或以上、用于跨节点通信验证。
2.两个namespace,linux和python,分别代表不同项目的Pod。
3.每个namespace 运行多个pod,且pod运行在不同的node主机。
4.测试环境为每个namespace分别运行一个nginx和一个tomcat pod,用于测试不同主机的Pod运行在同一个ns的场景、以及跨ns的访问通信及访问限制。
kubectl create ns linux
kubectl create ns python
kubectl label ns linux nsname=linux
kubectl label ns python nsname=python
kubectl get ns --show-labels=true
step1 linux空间 部署nginx tomcat
linux-nginx.yaml
kind: Deployment
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
metadata:
labels:
app: linux-nginx-deployment-label
name: linux-nginx-deployment
namespace: linux
spec:
replicas: 1
selector:
matchLabels:
app: linux-nginx-selector
template:
metadata:
labels:
app: linux-nginx-selector
spec:
containers:
- name: linux-nginx-container
image: nginx:1.20.2-alpine
#command: ["/apps/tomcat/bin/run_tomcat.sh"]
#imagePullPolicy: IfNotPresent
imagePullPolicy: Always
ports:
- containerPort: 80
protocol: TCP
name: http
- containerPort: 443
protocol: TCP
name: https
env:
- name: "password"
value: "123456"
- name: "age"
value: "18"
# resources:
# limits:
# cpu: 2
# memory: 2Gi
# requests:
# cpu: 500m
# memory: 1Gi
---
kind: Service
apiVersion: v1
metadata:
labels:
app: linux-nginx-service-label
name: linux-nginx-service
namespace: linux
spec:
type: NodePort
ports:
- name: http
port: 80
protocol: TCP
targetPort: 80
nodePort: 30008
- name: https
port: 443
protocol: TCP
targetPort: 443
nodePort: 30443
selector:
app: linux-nginx-selector
linux-tomcat.yaml
kind: Deployment
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
metadata:
labels:
app: linux-tomcat-app1-deployment-label
name: linux-tomcat-app1-deployment
namespace: linux
spec:
replicas: 1
selector:
matchLabels:
app: linux-tomcat-app1-selector
template:
metadata:
labels:
app: linux-tomcat-app1-selector
spec:
containers:
- name: linux-tomcat-app1-container
image: tomcat:7.0.109-jdk8-openjdk
#command: ["/apps/tomcat/bin/run_tomcat.sh"]
#imagePullPolicy: IfNotPresent
imagePullPolicy: Always
ports:
- containerPort: 8080
protocol: TCP
name: http
env:
- name: "password"
value: "123456"
- name: "age"
value: "18"
# resources:
# limits:
# cpu: 2
# memory: 2Gi
# requests:
# cpu: 500m
# memory: 1Gi
---
kind: Service
apiVersion: v1
metadata:
labels:
app: linux-tomcat-app1-service-label
name: linux-tomcat-app1-service
namespace: linux
spec:
type: NodePort
ports:
- name: http
port: 80
protocol: TCP
targetPort: 8080
nodePort: 30006
selector:
app: linux-tomcat-app1-selector
step3 python空间部署 3个pod
python-nginx.yaml
kind: Deployment
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
metadata:
labels:
app: python-nginx-deployment-label
name: python-nginx-deployment
namespace: python
spec:
replicas: 1
selector:
matchLabels:
app: python-nginx-selector
template:
metadata:
labels:
app: python-nginx-selector
project: python
spec:
containers:
- name: python-nginx-container
image: nginx:1.20.2-alpine
#command: ["/apps/tomcat/bin/run_tomcat.sh"]
#imagePullPolicy: IfNotPresent
imagePullPolicy: Always
ports:
- containerPort: 80
protocol: TCP
name: http
- containerPort: 443
protocol: TCP
name: https
env:
- name: "password"
value: "123456"
- name: "age"
value: "18"
# resources:
# limits:
# cpu: 2
# memory: 2Gi
# requests:
# cpu: 500m
# memory: 1Gi
---
kind: Service
apiVersion: v1
metadata:
labels:
app: python-nginx-service-label
name: python-nginx-service
namespace: python
spec:
type: NodePort
ports:
- name: http
port: 80
protocol: TCP
targetPort: 80
nodePort: 30014
- name: https
port: 443
protocol: TCP
targetPort: 443
nodePort: 30453
selector:
app: python-nginx-selector
project: python #一个或多个selector,至少能匹配目标pod的一个标签
python-tomcat.yml
kind: Deployment
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
metadata:
labels:
app: python-tomcat-app1-deployment-label
name: python-tomcat-app1-deployment
namespace: python
spec:
replicas: 1
selector:
matchLabels:
app: python-tomcat-app1-selector
template:
metadata:
labels:
app: python-tomcat-app1-selector
spec:
nodeName: 172.31.7.113
containers:
- name: python-tomcat-app1-container
image: tomcat:7.0.109-jdk8-openjdk
#command: ["/apps/tomcat/bin/run_tomcat.sh"]
#imagePullPolicy: IfNotPresent
imagePullPolicy: Always
ports:
- containerPort: 8080
protocol: TCP
name: http
env:
- name: "password"
value: "123456"
- name: "age"
value: "18"
# resources:
# limits:
# cpu: 2
# memory: 2Gi
# requests:
# cpu: 500m
# memory: 1Gi
---
kind: Service
apiVersion: v1
metadata:
labels:
app: python-tomcat-app1-service-label
name: python-tomcat-app1-service
namespace: python
spec:
type: NodePort
ports:
- name: http
port: 80
protocol: TCP
targetPort: 8080
nodePort: 30015
selector:
app: python-tomcat-app1-selector
testpod-busybox.yaml
kind: Deployment
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
metadata:
labels:
app: testpod-busybox-deployment-label
name: testpod-busybox-deployment
namespace: python
spec:
replicas: 1
selector:
matchLabels:
app: python-nginx-selector
project: python
template:
metadata:
labels:
app: python-nginx-selector
project: python
spec:
containers:
- name: testpod-busybox-container
image: centos:7.9.2009
command:
- sleep
- "50000000"
imagePullPolicy: IfNotPresent
#imagePullPolicy: Always
step3 linux空间 python空间中的 tomcat 各自创建静态文件 用于访问区分
tomcat空间
kubectl exec -it $python-tomcat bash -n python
cd /usr/local/tomcat/webapps;mkdir app
echo "python web app web page" > app/index.jsp
注意替换变量 $python-tomcat 为实际的pod name
linux空间
kubectl exec -it $linux-tomcat bash -n linux
cd /usr/local/tomcat/webapps;mkdir app
echo "linux web app web page" > app/index.jsp
注意替换变量 $linux-tomcat 为实际的pod name
step4 登陆python空间的busybox 测试访问tomcat
kubectl exec -ti testpod-busybox-deployment-85f4ccf67b-m5f7n bash -n python
[root@testpod-busybox-deployment-85f4ccf67b-m5f7n /]# curl 10.200.196.139:8080/app/index.jsp
linux web app web page
[root@testpod-busybox-deployment-85f4ccf67b-m5f7n /]# curl 10.200.196.142:8080/app/index.jsp
python web app web page
busybox访问 linux空间和 python 空间的tomcat都是畅通的
同样在master02节点测试 也是畅通的
证明 各个空间中的pod可以相互访问 畅通无阻, 默认 网络策略不限制
case1 ingress 只允许同namespace访问
策略: 以pod为限制单位、只允同namespace 含有特定标签的 源pod 访问 目标pod 的所有端口:
case1-ingress-podSelector.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: tomcat-access--networkpolicy
namespace: python
spec:
policyTypes:
- Ingress
podSelector:
matchLabels:
app: python-tomcat-app1-selector #对匹配到的目的Pod应用以下规则
ingress: #入栈规则,如果指定目标端口就是匹配全部端口和协议,协议TCP, UDP, or SCTP
- from:
- podSelector:
matchLabels:
#app: python-nginx-selector #如果存在多个matchLabel条件,如果存在多个matchLabel条件,是and的关系,即要同时满足条件A、条件B、条件X
project: "python"
从其他的位置 访问失败了
从nginx的容器中 请求成功了
case2-ingress
ingress-以pod加单个端口为限制单位、只允同namespace含有特定标签的源pod访问目标pod的指定端口
case2-ingress-podSelector-ns-SinglePort.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: tomcat-access--networkpolicy
namespace: python
spec:
policyTypes:
- Ingress
podSelector:
matchLabels:
app: python-tomcat-app1-selector
ingress:
- from:
- podSelector:
matchLabels:
app: python-nginx-selector #指定访问源的匹配条件,如果存在多个matchLabel条件,是and的关系,即要同时满足条件A、条件B、条件X
#project: "python"
ports: #入栈规则,如果指定目标端口就是匹配全部端口和协议,协议TCP, UDP, or SCTP
- protocol: TCP
port: 8888 #允许通过TCP协议访问目标pod的8888端口,但是其它没有允许的端口将全部禁止访问
#port: 80
在python-nginx的容器中 无法访问8080端口了
底层的原理是什么?
在 python-tomcat-app1-selector pod所在的宿主机上 可以看到iptables规则
case3-ingress
ingress-允许同namespace的所有pod访问当前namespace的目标pod多个指定端口
case3-ingress-podSelector-ns-MultiPort.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: tomcat-access-networkpolicy
namespace: python
spec:
policyTypes:
- Ingress
podSelector: #目标pod
matchLabels:
app: python-tomcat-app1-selector
ingress:
- from:
- podSelector: #匹配源pod,matchLabels: {}为不限制源pod即允许所有pod,写法等同于resources(不加就是不限制)
matchLabels: {}
ports: #入栈规则,如果指定目标端口就是匹配全部端口和协议,协议TCP, UDP, or SCTP
- protocol: TCP
port: 8080 #允许通过TCP协议访问目标pod的8080端口,但是其它没有允许的端口将全部禁止访问
#port: 80
- protocol: TCP
port: 3306
- protocol: TCP
port: 6379
验证
跨namespace禁止访问
case4-ingress
ingress-允许同namespace的所有pod访问当前namespace的目标pod所有端口
case4-ingress-podSelector-ns.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: tomcat-access--networkpolicy
namespace: python
spec:
policyTypes:
- Ingress
podSelector: #目标pod
matchLabels: {} # 不填东西 就是匹配所有目标pod
ingress:
- from:
- podSelector: #匹配源pod,matchLabels: {}为不限制源pod即允许所有pod,写法等同于resources(不加就是不限制)
matchLabels: {}
验证
1.其它namespace无法访问目标ns的pod。
2.同namespace的pod可以访问当前namespace中的所有pod的任意端口
case5-ingress
ingress-ipBlock白名单(基于pod的ip地址段进行限制、不受NS限制)
case5-ingress-ipBlock.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: tomcat-access--networkpolicy
namespace: python
spec:
policyTypes:
- Ingress
podSelector: #目标pod
matchLabels:
app: python-tomcat-app1-selector
ingress:
- from:
# - podSelector: #匹配源pod,matchLabels: {}为不限制源pod即允许所有pod,写法等同于resources(不加就是不限制)
# matchLabels: {}
- ipBlock:
cidr: 10.200.0.0/16 #cidr定义的是白名单,代表允许访问的地址范围10.200.0.0/16,没有允许的将禁止访问目标pod
except: # 定义禁止的地址
- 10.200.196.133/32 #在以上范围内禁止访问的源IP地址 10.200.0.0/16 中的10.200.196.133/32 不能进行访问
ports: #入栈规则,如果指定目标端口就是匹配全部端口和协议,协议TCP, UDP, or SCTP
- protocol: TCP
port: 8080 #允许通过TCP协议访问目标pod的8080端口,但是其它没有允许的端口将全部禁止访问
#port: 80
- protocol: TCP
port: 3306
- protocol: TCP
port: 6379
不建议在k8s中进行限制 建议放到前面 CDN WAF进行限制
验证:
1.只要在白名单范围内没有被except指定禁止的源pod IP,都允许访问。
2.在只设置了ipBlock匹配的前提下,其它namespace 中没有在except范围的pod 也可以访问目标pod及linux ns中的pod
只要不在except地址范围内,也可以访问python ns中的pod了
case6-ingress
ingress-namespace Selector-ns选择器:
case6-ingress-namespaceSelector.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: tomcat-access--networkpolicy
namespace: python
spec:
policyTypes:
- Ingress
podSelector: #目标pod
matchLabels: {} #允许访问python namespace 中的所有pod
# app: python-tomcat-app1-selector #可以只允许访问python namespace中指定的pod
ingress:
- from:
- namespaceSelector:
matchLabels:
nsname: linux #只允许指定的namespace访问
- namespaceSelector:
matchLabels:
nsname: python #只允许指定的namespace访问
ports: #入栈规则,如果指定目标端口就是匹配全部端口和协议,协议TCP, UDP, or SCTP
- protocol: TCP
port: 8080 #允许通过TCP协议访问目标pod的8080端口,但是其它没有允许的端口将全部禁止访问
- protocol: TCP
port: 3306
- protocol: TCP
port: 6379
验证:
1.被明确允许的namespace中的pod可以访问目标pod
2.没有明确声明允许的namespace将禁止访问
3.没有明确声明允许的话,即使同一个namespace也禁止访问
4.比如只允许了linux和python两个ns,那么default中的pod将无法访问
case7-Egress
限制出口流量
Egress-podSelector-Pod出口方向目的IP 及 目的端口限制
只允许访问指定的目的地址范围及端口:限制指定的pod可以访指定的ip
限制python-tomcat-app1-selector的pod 只能访问 10.200.0.0/16 和 172.31.7.106/32 的主机
这个规则不能访问外网了
case7-Egress-ipBlock.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: egress-access-networkpolicy
namespace: python
spec:
policyTypes:
- Egress
podSelector: #目标pod选择器
matchLabels: #基于label匹配目标pod
app: python-tomcat-app1-selector #匹配python namespace中app的值为python-tomcat-app1-selector的pod,然后基于egress中的指定网络策略进行出口方向的网络限制
egress:
- to:
- ipBlock:
cidr: 10.200.0.0/16 #允许匹配到的pod出口访问的目的CIDR地址范围
- ipBlock:
cidr: 172.31.7.106/32 #允许匹配到的pod出口访问的目的主机
ports:
- protocol: TCP
port: 80 #允许匹配到的pod访问目的端口为80的访问
- protocol: TCP
port: 53 #允许匹配到的pod访问目的端口为53 即DNS的解析
- protocol: UDP
port: 53 #允许匹配到的pod访问目的端口为53 即DNS的解析
验证:
1.基于Egress白名单,定义ns中匹配成功的pod可以访问ipBlock指定的地址和ports指定的端口。
2.匹配成功的pod访问未明确定义在Egress的白名单的其它IP的请求,将拒绝。
3.没有匹配成功的源pod,主动发起的出口访问请求不受影响
case8-Egress
Egress-podSelector-Pod出口方向目的Pod限制-只允许源pod访问指定的目的pod及端口:
基于podSelector选择器,限制源pod能够访问的目的pod
case8-Egress-PodSelector.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: egress-access-networkpolicy
namespace: python
spec:
policyTypes:
- Egress
podSelector: #目标pod选择器
matchLabels: #基于label匹配目标pod
app: python-nginx-selector #匹配python namespace中app的值为python-tomcat-app1-selector的pod,然后基于egress中的指定网络策略进行出口方向的网络限制
egress:
- to:
- podSelector: #匹配pod,matchLabels: {}为不限制源pod即允许所有pod,写法等同于resources(不加就是不限制)
matchLabels:
app: python-tomcat-app1-selector
ports:
- protocol: TCP
port: 8080 #允许80端口的访问
- protocol: TCP
port: 53 #允许DNS的解析
- protocol: UDP
port: 53
验证:
1.匹配成功的源pod只能访问指定的目的pod的指定端口
2.其它没有允许的出口请求将禁止访问
case9-Egress
限制匹配成功的pod访问指定的namespace
case9-Egress-namespaceSelector.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: egress-access-networkpolicy
namespace: python
spec:
policyTypes:
- Egress
podSelector: #目标pod选择器
matchLabels: #基于label匹配目标pod
app: python-nginx-selector #匹配python namespace中app的值为python-tomcat-app1-selector的pod,然后基于egress中的指定网络策略进行出口方向的网络限制
egress:
- to:
- namespaceSelector:
matchLabels:
nsname: python #指定允许访问的目的namespace
- namespaceSelector:
matchLabels:
nsname: linux #指定允许访问的目的namespace
- namespaceSelector:
matchLabels:
nsname: kube-system #指定允许访问的目的namespace
ports:
- protocol: TCP
port: 80 #允许80端口的访问
- protocol: TCP
port: 8080 #允许8080端口的访问
- protocol: TCP
port: 53 #允许DNS的解析
- protocol: UDP
port: 53
验证
1.匹配成功的源pod可以访问指定的目标namespace。
2.不能访问除指定的namespace以外的其它namespace及外网。
3.比如允许指定的源pod访问linux和python ns中的8080、3306、6379等端口,但是其它ns无法访问