首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >一文搞懂Kubernetes网络策略(上)

一文搞懂Kubernetes网络策略(上)

作者头像
zouyee
发布2021-02-01 12:16:44
发布2021-02-01 12:16:44
1.4K0
举报
文章被收录于专栏:Kubernetes GOKubernetes GO

今天zouyee为大家带来《一文搞懂Kubernetes网络策略(上)》,其中《kuberneter调度由浅入深:框架》正在编写中,敬请期待,当前涉及版本均为1.20.+。

一、Network Policy简介

代码语言:javascript
复制
代码语言:javascript
复制
随着微服务架构的日渐盛行,Serverless框架的逐步落地,应用上云后带来了模块间网络调用需求的大规模增长,Kubernetes 自 1.3 引入了 Network Policy,其提供以应用为中心, 基于策略的网络控制,用于隔离应用以减少攻击面。
代码语言:javascript
复制
Pod之间能否通信可通过如下三种组合进行确认:
   1. 其他被允许的 Pods(例如:Pod 无法限制对自身的访问)
   2. 被允许访问的namespace
   3. IP  CIDR(例如:与 Pod 运行所在节点的通信总是被允许的)
    在定义基于 Pod 或namespace的 NetworkPolicy 时,可以使用`标签选择器`来设定哪些流量可以进入或离开 Pod。同时,当创建基于 IP 的 NetworkPolicy 时,可以基于 IP CIDR 来定义策略。
    以下结构体示意图辅助理解,后面章节有具体说明:

版本变迁

Kubernetes版本

Networking API版本

Kubernetes版本

v1.5-v1.6

extension/v1beta1

需要在kube-apiserver启动命令行开启extensions/v1beta1/networkpolicies

v1.7

networking.k8s.io/v1

v1.8

networking.k8s.io/v1

增加Egress及IPBlock特性

二、简要介绍

相关说明

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

Pod 在被某 NetworkPolicy 选中时进入隔离状态。一旦名字空间中有 NetworkPolicy 选择了特定的 Pod,该 Pod 会拒绝该 NetworkPolicy 所不允许的连接。(名字空间下其他未被 NetworkPolicy 所选择的 Pod 会继续接受所有的流量)

网络策略不会冲突。如果任何一个或多个策略选择了一个 Pod, 则该 Pod 受限于这些策略的 入站(Ingress)/出站(Egress)规则的并集。

⚠️在使用 Network Policy 时,网络插件需要支持 Network Policy,如 Calico、Romana、Weave Net 和 Trireme 等,其中Engress为 出口流量,Ingress为 入口流量。

结构体说明

staging/src/k8s.io/api/networking/v1/types.go

代码语言:javascript
复制
下面是 NetworkPolicy 的一个示例,如需完整说明,可参看结构定义文档:
代码语言:javascript
复制
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: network-policy-sample
  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

必需字段:与所有其他的 Kubernetes 对象一样,NetworkPolicy 需要 apiVersion、 kind 和 metadata 字段。

spec:NetworkPolicy 规约中包含了在名字空间中定义特定网络策略所需的所有信息。

podSelector:每个 NetworkPolicy 都包括一个 podSelector,它选择适用该该策略的 Pod。示例中的策略选择带有 “role=db” 标签的 Pod。若podSelector为空的,则选择名字空间下所有 Pod。

policyTypes: 每个 NetworkPolicy 都包含一个 policyTypes 列表,其中包含 Ingress 或 Egress 或(两者亦可)。policyTypes 字段表示给定的策略是应用于 所选 Pod 的入口流量还是来出口流量(两者亦可)。如果 NetworkPolicy 未指定 policyTypes 则默认情况下始终设置 Ingress;如果 NetworkPolicy 有任何出口规则的话则设置 Egress。

ingress: 每个 NetworkPolicy 可包含一个 ingress 规则的白名单列表。每个规则都允许同时匹配 from 和 ports 部分的流量。示例策略中包含一条 简单的规则:它匹配某个特定端口,第一个通过 ipBlock 指定,第二个通过 namespaceSelector 指定,第三个通过 podSelector 指定。

egress: 每个 NetworkPolicy 可包含一个 egress 规则的白名单列表。每个规则都允许匹配 to 和 port 部分的流量。该示例策略包含一条规则, 该规则指定端口上的流量匹配到 10.0.0.0/24 中的任何目的地。

该网络策略总结如下:

1. 隔离 default名字空间下 role=db 的 Pod 。

2. 出口限制:允许符合以下条件的 Pod 连接到 default名字空间下标签为 role=db的所有 Pod 的 6379 TCP 端口:

a) default名字空间下带有 role=frontend 标签的所有 Pod

b) 带有 project=myproject 标签的所有名字空间中的 Pod

c) IP 地址范围为172.17.0.0–172.17.0.255 和 172.17.2.0–172.17.255.255(即除了 172.17.1.0/24 之外的所有 172.17.0.0/16)

3. 入口限制:允许从带有 role=db标签的名字空间下的任何 Pod 到 CIDR 10.0.0.0/24 下 5978 TCP 端口。

简单示例

以 calico 为例看一下 Network Policy 的具体用法。

1) 配置 kubelet 使用 CNI 网络插件(默认已经配置,无需更改)

kubelet --network-plugin=cni --cni-conf-dir=/etc/cni/net.d --cni-bin-dir=/opt/cni/bin ...

2) 安装 calio 网络插件

代码语言:javascript
复制
# 注意修改 CIDR,需要跟 k8s pod-network-cidr 一致,默认为 192.168.0.0/16
# 当前选择的是小于50节点的安装方式,具体安装可查看
# https://docs.projectcalico.org/getting-started/kubernetes/self-managed-onprem/onpremises
kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml

3) 部署应用

部署 nginx 服务

代码语言:javascript
复制
$ kubectl create deployment nginx --image=nginx
deployment "nginx" created
$ kubectl expose deployment nginx --port=80
service "nginx" exposed

测试网络

代码语言:javascript
复制
$ kubectl get svc,pod
NAME                 TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
service/kubernetes   ClusterIP   10.233.0.1      <none>        443/TCP   186d
service/nginx        ClusterIP   10.233.27.142   <none>        80/TCP    2s

NAME                            READY   STATUS              RESTARTS   AGE
pod/nginx-f89759699-kfmbj       1/1     Running             0          62s

$ kubectl run busybox --rm -ti --image=busybox /bin/sh
If you don't see a command prompt, try pressing enter.

/ # wget --spider --timeout=1 nginx
Connecting to nginx (10.233.27.142:80)
remote file exists
/ #

测试网络策略

代码语言:javascript
复制
如果只让那些拥有标签 `access: true` 的 Pod 访问 `nginx` 服务, 那么可以创建一个如下所示的 NetworkPolicy 对象:
代码语言:javascript
复制
$ cat nginx-policy.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: access-nginx
spec:
  podSelector:
    matchLabels:
      app: nginx
  ingress:
  - from:
    - podSelector:
        matchLabels:
          access: "true"

$ kubectl create -f nginx-policy.yaml
networkpolicy "access-nginx" created

# 不带 access=true 标签的 Pod 还是无法访问 nginx 服务
$ kubectl run busybox --rm -ti --image=busybox /bin/sh
If you don't see a command prompt, try pressing enter.

/ # wget --spider --timeout=1 nginx
Connecting to nginx (10.233.27.142:80)
wget: download timed out
/ #

# 而带有 access=true 标签的 Pod 可以访问 nginx 服务
$ kubectl run busybox --rm -ti --labels="access=true" --image=busybox /bin/sh
If you don't see a command prompt, try pressing enter.

/ # wget --spider --timeout=1 nginx
Connecting to nginx (10.233.27.142:80)
/ #

三、应用场景

一般场景

a. 禁止访问指定服务
代码语言:javascript
复制
kubectl run web --image=nginx --labels app=web --expose --port 80
# 未有策略限制时,可以访问
$ kubectl run busybox --rm -ti --image=busybox /bin/sh
If you don't see a command prompt, try pressing enter.
/ # wget -qO- http://web
<!DOCTYPE html>
<html>
<head>

创建网络策略

代码语言:javascript
复制
# cat web-deny-all.yaml
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: web-deny-all
spec:
  podSelector:
    matchLabels:
      app: web
  ingress: []
$ kubectl apply -f web-deny-all.yaml
networkpolicy "web-deny-all" created

访问测试

代码语言:javascript
复制
$ kubectl run busybox --rm -ti --image=busybox /bin/sh
If you don't see a command prompt, try pressing enter.
/ # wget -qO- --timeout=2 http://web
wget: download timed out
b. 限制访问指定服务
代码语言:javascript
复制
kubectl run apiserver --image=nginx --labels app=bookstore,role=api --expose --port 80

创建网络

代码语言:javascript
复制
# cat api-allow.yaml
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: api-allow
spec:
  podSelector:
    matchLabels:
      app: bookstore
      role: api
  ingress:
  - from:
      - podSelector:
          matchLabels:
            app: bookstore
# kubectl apply -f api-allow.yaml
networkpolicy "api-allow" created

访问测试

代码语言:javascript
复制
创建不加label的pod,预期结果,访问被限制
$ kubectl run busybox --rm -ti --image=busybox /bin/sh
If you don't see a command prompt, try pressing enter.
/ # wget -qO- --timeout=2 http://apiserver
wget: download timed out
/ # exit
创建带app=bookstore标签的pod,预期结果,访问被限制
$ kubectl run busybox --rm -ti --image=busybox --labels app=bookstore,role=frontend /bin/sh
If you don't see a command prompt, try pressing enter.
/ # wget -qO- --timeout=2 http://apiserver
<!DOCTYPE html>
<html><head>
/ # exit
c. 放通访问限制
代码语言:javascript
复制
kubectl run apiserver --image=nginx --labels app=bookstore,role=api --expose --port 80

应用a中的网络策略,限制所有流量

代码语言:javascript
复制
# cat web-deny-all.yaml
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: web-deny-all
spec:
  podSelector:
    matchLabels:
      app: web
  ingress: []
$ kubectl apply -f web-deny-all.yaml
networkpolicy "web-deny-all" created

创建网络策略

代码语言:javascript
复制
# cat web-deny-all.yaml
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: web-allow-all
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: web
  ingress:
  - {}
$ kubectl apply -f web-allow-all.yaml
networkpolicy "web-allow-all" created
# 需要注意deny跟allow的细微差别就是[]与{},其中{}代表
- from:
    podSelector: {}
    namespaceSelector: {}

namespace限制

a. 禁止namespace中非白名单流量

创建网络策略

代码语言:javascript
复制
# cat default-deny-all.yaml
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: default-deny-all
  namespace: default
spec:
  podSelector: {}
  ingress: []
# kubectl apply -f default-deny-all.yaml

说明:

  • namespace: default 该策略部署于default
  • podSelector{}指匹配所有pod,因而该策略对default命名空间的所有pod都有效
  • ingress未指定,因而对于所有进入流量都禁止
b. 禁止其他namespace流量
代码语言:javascript
复制
kubectl create namespace secondary
kubectl run web --namespace secondary --image=nginx \
    --labels=app=web --expose --port 80

创建网络策略

代码语言:javascript
复制
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  namespace: secondary
  name: web-deny-other-namespaces
spec:
  podSelector:
    matchLabels:
  ingress:
  - from:
    - podSelector: {}

访问测试

代码语言:javascript
复制
# default命名空间访问
$ kubectl run busybox --rm -ti --image=busybox /bin/sh
If you don't see a command prompt, try pressing enter.
/ # wget -qO- --timeout=2 http://web.secondary
wget: download timed out
/ # exit
# secondary命名空间访问
$ kubectl run busybox --rm -ti --image=busybox --namespace=secondary /bin/sh
If you don't see a command prompt, try pressing enter.
/ # wget -qO- --timeout=2 http://web.secondary
<!DOCTYPE html>
<html>
c. 放通所有namespace流量
代码语言:javascript
复制
kubectl run web --image=nginx --labels app=web --expose --port 80

创建网络策略

代码语言:javascript
复制
# cat web-allow-all-namespaces.yaml
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  namespace: default
  name: web-allow-all-namespaces
spec:
  podSelector:
    matchLabels:
      app: web
  ingress:
  - from:
    - namespaceSelector: {}
# kubectl apply -f web-allow-all-namespaces.yaml
# kubectl create namespace secondary

说明:

  • app: web网络策略应用到该标签pod
  • namespaceSelector: {}匹配所有命名空间

访问测试

代码语言:javascript
复制
# kubectl run busybox --rm -ti --image=busybox --namespace=secondary /bin/sh
If you don't see a command prompt, try pressing enter.
/ # wget -qO- --timeout=2 http://web.secondary
<!DOCTYPE html>
<html>
d. 指定namespace访问服务
代码语言:javascript
复制
# kubectl run web --image=nginx \
    --labels=app=web --expose --port 80
# kubectl create namespace dev
# kubectl label namespace/dev purpose=testing
# kubectl create namespace prod
# kubectl label namespace/prod purpose=production

创建网络策略

代码语言:javascript
复制
# cat web-allow-prod.yaml
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: web-allow-prod
spec:
  podSelector:
    matchLabels:
      app: web
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          purpose: production
# kubectl apply -f web-allow-prod.yaml
e. 允许其他namespace指定pod的流量

⚠️ Kubernetes 1.11后支持podSelectornamespaceSelector的运算符操作,同时需要网络插件支持

代码语言:javascript
复制
# kubectl run web --image=nginx \
    --labels=app=web --expose --port 80
# kubectl create namespace other
# kubectl create namespace other

创建网络策略

代码语言:javascript
复制
# cat web-allow-all-ns-monitoring.yaml
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: web-allow-all-ns-monitoring
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: web
  ingress:
    - from:
      - namespaceSelector:     # 选择namespaces中带有team=operations标签的pod
          matchLabels:
            team: operations  
        podSelector:           # 选择带有type=monitoring标签的pod
          matchLabels:
            type: monitoring
# kubectl apply -f web-allow-all-ns-monitoring.yaml

访问测试

代码语言:javascript
复制
kubectl run busybox --rm -ti --image=busybox  /bin/sh
If you don't see a command prompt, try pressing enter.
/ # wget -qO- --timeout=2 http://web.default
wget: download timed out

(访问限制)
/ # exit

# kubectl run busybox --rm -ti --image=busybox --labels type=monitoring /bin/sh
If you don't see a command prompt, try pressing enter.
/ # wget -qO- --timeout=2 http://web.default
wget: download timed out
(访问限制)
# kubectl run busybox --rm -ti --image=busybox --namespace=other /bin/sh
If you don't see a command prompt, try pressing enter.
/ # wget -qO- --timeout=2 http://web.default
wget: download timed out
(访问限制)
# kubectl run busybox --rm -ti --image=busybox --namespace=other  --labels type=monitoring /bin/sh
If you don't see a command prompt, try pressing enter.
/ # wget -qO- --timeout=2 http://web.default
<!DOCTYPE html>
<html>
<head>
...
(允许访问)

未完,待续

参考资料

1. Kubernetes 官网:https://kubernetes.io/docs/concepts/services-networking/network-policies/

2. Declare Network Policy: https://kubernetes.io/docs/tasks/administer-cluster/declare-network-policy/

3. Securing Kubernetes Cluster Networking: https://ahmet.im/blog/kubernetes-network-policy/

4. fesikyer network policy: https://github.com/feiskyer/kubernetes-handbook/blob/master/concepts/network-policy.md

END

往期 · 精选

1、干货分享 | K8S调度系统由浅入深:简介

2、干货分享 | CloudEvents三部曲:实践篇

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-01-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 DCOS 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • a. 禁止访问指定服务
  • b. 限制访问指定服务
  • c. 放通访问限制
  • a. 禁止namespace中非白名单流量
  • b. 禁止其他namespace流量
  • c. 放通所有namespace流量
  • d. 指定namespace访问服务
  • e. 允许其他namespace指定pod的流量
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档