惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园 - 聂微东
Y
Y Combinator Blog
WordPress大学
WordPress大学
L
LangChain Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
A
About on SuperTechFans
小众软件
小众软件
有赞技术团队
有赞技术团队
S
SegmentFault 最新的问题
宝玉的分享
宝玉的分享
Recent Announcements
Recent Announcements
GbyAI
GbyAI
I
InfoQ
The GitHub Blog
The GitHub Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
酷 壳 – CoolShell
酷 壳 – CoolShell
罗磊的独立博客
C
Check Point Blog
V
V2EX
Apple Machine Learning Research
Apple Machine Learning Research
月光博客
月光博客
量子位
雷峰网
雷峰网
Hugging Face - Blog
Hugging Face - Blog

陈少文的网站

巨变与机遇的未来十年 Kubernetes 平台管理软件压力测试方案 使用镜像部署 Hexo 静态页面 终于等到你 - GitHub 镜像仓库服务(ghcr.io) 一起来学 Go --(6)Interface 一起来学 Go --(5)Goroutine 和 Channel 什么是函数式编程 如何在 Kubernetes 集群集成 Kata 柯里化与偏函数 使用 PyGithub 自动创建 Label 软件产品是团队能力的输出 Helm 2 、Helm 3 比较 IoT 变现 Kubernetes 中的 DNS 服务 国内的 Helm 镜像源 Harbor 使用自签证书支持 Https 访问 DevOps 工具链之 Prow 如何使用 kfctl 安装 Kubeflow VS Code 无法下载 Go 插件的工具包 工程师更应具有服务精神 你不知道的 Docker 使用技巧 使用 Docker 运行 Tensorflow 论中国 什么是左移 如何清空 Git 仓库全部历史记录 一禅小和尚 有风吹过厨房 时间的玫瑰 如何在 CentOS 安装 GPU 驱动 开发 Tips(19)
Kubernetes 之网络隔离(内附十多种使用场景)
微信公众号 · 2021-05-18 · via 陈少文的网站

Please enable Javascript to view the contents

1. Kubernetes 中的网络隔离

Kuberntes 自 1.3 引入了 Network Policy(网络策略) ,通过 ipBlock、podSelector、namespaceSelector 定义实体,控制其 From(Ingress)、To(Egress)的流量行为。

但 Kubernetes 只是定义了网络策略,具体实现依赖网络插件。目前,Calico、Cilium、Weave Net 等网络插件都支持网络隔离功能。

不同的 Kubernetes 版本对网络隔离支持的程度不一样。1.3~1.6 需要在 kube-apiserver 中开启 extensions/v1beta1/networkpolicies ,1.7 之后可以直接使用,1.8 新增了 Egress 、IPBlock 支持。

如果没有配置任何网络策略,默认情况下流量行为将没有任何限制。

2. 网络隔离对象的字段属性

下面是官方文档中的示例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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

为了更直观地看到网络策略的组成,我画了一张示意图:

一个 NetworkPolicy 包含四个部分:

  • 需要控制的 Pods
  • 策略类型,Ingress、Egress 可选
  • Ingress 策略,包括 Entity 和端口、协议定义
  • Egress 策略,包括 Entity 和端口、协议定义

其中的 Entity 有三种类型可选,ipBlock 指定一个 IP 范围,namespaceSelector 指定匹配的命名空间,podSelector 指定匹配的 Pods 。

如果针对同一个实体,定义了多个 NetworkPolicy,那么命中其中一项即可通行。

3. 网络隔离示例

在 Ingress 和 Egress 的配置过程中会遇到两个特殊对象 []{}。如果是 [],那么表示不指向任何实体,通常用于禁用流量;而 {} 表示全部实体,通常用于放行流量。

另外一个值得注意的地方是,列表表示或的关系。

1
2
3
4
5
6
egress:
  - ports:
      - port: 443
        protocol: TCP
  - to:
      - namespaceSelector: {}

表示允许全部的 443 端口 TCP 流量,同时允许全部命名空间的任意端口流量。

1
2
3
4
5
6
egress:
  - ports:
      - port: 443
        protocol: TCP
    to:
      - namespaceSelector: {}

表示允许指向全部命名空间的 443 端口 TCP 流量。

3.1 拒绝访问 Pod 的全部流量

  • 创建负载
1
kubectl run --generator=run-pod/v1 web --image=nginx --labels app=web --expose --port 80
  • 运行一个临时的 Pod 测试网络

验证默认情况下,Kubernetes 对流量没有进行限制。

1
2
3
4
5
6
7
kubectl run --generator=run-pod/v1 --rm -i -t --image=alpine test-$RANDOM -- sh

/ # wget -qO- http://web
<!DOCTYPE html>
<html>
<head>
...
  • 创建网络策略

包含 app=web 标签的 Pods 将拒绝全部访问流量。Ingress 为 [] 的含义是匹配的实体为空。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
cat <<EOF | kubectl apply -f -
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: web-deny-all
spec:
  podSelector:
    matchLabels:
      app: web
  ingress: []
EOF
  • 测试网络策略
1
2
3
4
kubectl run --generator=run-pod/v1 --rm -i -t --image=alpine test-$RANDOM -- sh

/ # wget -qO- --timeout=2 http://web
wget: download timed out
  • 清理环境
1
2
3
kubectl delete pod web
kubectl delete service web
kubectl delete networkpolicy web-deny-all

3.2 仅允许指定的 Pods 访问应用

  • 创建负载
1
kubectl run --generator=run-pod/v1 apiserver --image=nginx --labels app=bookstore,role=api --expose --port 80
  • 创建网络策略

仅允许包含标签 app=bookstore 的 Pods 访问应用。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
cat <<EOF | kubectl apply -f -
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: api-allow
spec:
  podSelector:
    matchLabels:
      app: bookstore
      role: api
  ingress:
  - from:
      - podSelector:
          matchLabels:
            app: bookstore
EOF
  • 测试网络策略
1
2
3
4
kubectl run --generator=run-pod/v1 test-$RANDOM --rm -i -t --image=alpine -- sh

/ # wget -qO- --timeout=2 http://apiserver
wget: download timed out
1
2
3
4
kubectl run --generator=run-pod/v1 test-$RANDOM --rm -i -t --image=alpine --labels app=bookstore,role=frontend -- sh
/ # wget -qO- --timeout=2 http://apiserver
<!DOCTYPE html>
<html><head>
  • 清理环境
1
2
3
kubectl delete pod apiserver
kubectl delete service apiserver
kubectl delete networkpolicy api-allow

3.3 允许访问 Pod 的全部流量

  • 创建负载
1
kubectl run --generator=run-pod/v1 web --image=nginx --labels=app=web --expose --port 80
  • 创建网络策略

Ingress 设置为 {} 空的含义是允许全部来源。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
cat <<EOF | kubectl apply -f -
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: web-allow-all
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: web
  ingress:
  - {}
EOF
  • 测试网络策略
1
2
3
4
5
kubectl run --generator=run-pod/v1 test-$RANDOM --rm -i -t --image=alpine -- sh

/ # wget -qO- --timeout=2 http://web
<!DOCTYPE html>
<html><head>
  • 清理环境
1
2
kubectl delete pod,service web
kubectl delete networkpolicy web-allow-all

3.4 拒绝其他命名空间的访问流量

  • 创建负载
1
kubectl run --generator=run-pod/v1 web --namespace default --image=nginx --labels=app=web --expose --port 80
  • 创建网络策略

仅允许 default 命名空间内的 Pods 相互访问,不允许其他命名空间的 Pods 访问。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
cat <<EOF | kubectl apply -f -
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  namespace: default
  name: deny-from-other-namespaces
spec:
  podSelector:
    matchLabels:
  ingress:
  - from:
    - podSelector: {}
EOF
  • 测试网络策略
1
2
3
4
5
kubectl create namespace foo
kubectl run --generator=run-pod/v1 test-$RANDOM --namespace=foo --rm -i -t --image=alpine -- sh

/ # wget -qO- --timeout=2 http://web.default
wget: download timed out
1
2
3
4
5
kubectl run --generator=run-pod/v1 test-$RANDOM --namespace=default --rm -i -t --image=alpine -- sh

/ # wget -qO- --timeout=2 http://web.default
<!DOCTYPE html>
<html>
  • 清理环境
1
2
3
4
kubectl delete pod web
kubectl delete service web
kubectl delete networkpolicy deny-from-other-namespaces
kubectl delete namespace foo

3.5 允许全部命名空间访问指定的 Pods

  • 创建负载
1
kubectl run --generator=run-pod/v1 web --image=nginx --namespace default --labels=app=web --expose --port 80
  • 创建网络策略

仅允许 default 命名空间下,标签为 app=web 的 Pod 被访问。default 下的其他 Pod 不允许被访问。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
cat <<EOF | kubectl apply -f -
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  namespace: default
  name: web-allow-all-namespaces
spec:
  podSelector:
    matchLabels:
      app: web
  ingress:
  - from:
    - namespaceSelector: {}
EOF
  • 测试网络策略
1
2
3
4
5
6
7
kubectl create namespace secondary
kubectl run --generator=run-pod/v1 test-$RANDOM --namespace=secondary --rm -i -t --image=alpine -- sh

/ # wget -qO- --timeout=2 http://web.default
<!DOCTYPE html>
<html>
<head>
  • 清理环境
1
2
3
4
kubectl delete pod web -n default
kubectl delete service web -n default
kubectl delete networkpolicy web-allow-all-namespaces -n default
kubectl delete namespace secondary

3.6 允许指定命名空间访问指定的 Pods

  • 创建负载
1
kubectl run --generator=run-pod/v1 web --image=nginx --labels=app=web --expose --port 80
  • 创建测试命名空间
1
2
3
4
kubectl create namespace dev
kubectl label namespace/dev purpose=testing
kubectl create namespace prod
kubectl label namespace/prod purpose=production
  • 创建网络策略

仅允许命名空间包含标签 purpose=production 的 Pod 访问指定的应用,其他应用不允许访问。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
cat <<EOF | kubectl apply -f -
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: web-allow-prod
spec:
  podSelector:
    matchLabels:
      app: web
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          purpose: production
EOF
  • 测试网络策略
1
2
3
4
kubectl run --generator=run-pod/v1 test-$RANDOM --namespace=dev --rm -i -t --image=alpine -- sh

/ # wget -qO- --timeout=2 http://web.default
wget: download timed out
1
2
3
4
5
6
kubectl run --generator=run-pod/v1 test-$RANDOM --namespace=prod --rm -i -t --image=alpine -- sh

/ # wget -qO- --timeout=2 http://web.default
<!DOCTYPE html>
<html>
<head>
  • 清理环境
1
2
3
4
kubectl delete networkpolicy web-allow-prod
kubectl delete pod web
kubectl delete service web
kubectl delete namespace {prod,dev}

3.7 仅允许指定空间中的指定 Pod 访问应用

此功能需要 Kubernetes 1.11 及以上版本。

  • 创建负载
1
kubectl run --generator=run-pod/v1 web --image=nginx --labels=app=web --expose --port 80
  • 创建命名空间
1
2
kubectl create namespace other
kubectl label namespace/other team=operations
  • 创建网络策略

命名空间和 Pods 需要同时满足要求时,才可以访问指定的应用。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
cat <<EOF | kubectl apply -f -
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: web-allow-all-ns-monitoring
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: web
  ingress:
    - from:
      - namespaceSelector:     # chooses all pods in namespaces labelled with team=operations
          matchLabels:
            team: operations
        podSelector:           # chooses pods with type=monitoring
          matchLabels:
            type: monitoring
EOF
  • 测试网络策略
1
2
3
4
kubectl run --generator=run-pod/v1 test-$RANDOM --rm -i -t --image=alpine -- sh

/ # wget -qO- --timeout=2 http://web.default
wget: download timed out
1
2
3
4
kubectl run --generator=run-pod/v1 test-$RANDOM --labels type=monitoring --rm -i -t --image=alpine -- sh

/ # wget -qO- --timeout=2 http://web.default
wget: download timed out
1
2
3
4
kubectl run --generator=run-pod/v1 test-$RANDOM --namespace=other --rm -i -t --image=alpine -- sh

/ # wget -qO- --timeout=2 http://web.default
wget: download timed out
1
2
3
4
5
6
kubectl run --generator=run-pod/v1 test-$RANDOM --namespace=other --labels type=monitoring --rm -i -t --image=alpine -- sh

/ # wget -qO- --timeout=2 http://web.default
<!DOCTYPE html>
<html>
<head>
  • 清理环境
1
2
3
4
kubectl delete networkpolicy web-allow-all-ns-monitoring
kubectl delete namespace other
kubectl delete pod web
kubectl delete service web

3.8 仅允许访问 Pods 的指定端口

  • 创建负载
1
kubectl run --generator=run-pod/v1 apiserver --image=ahmet/app-on-two-ports --labels=app=apiserver

这个应用将在 8000 端口返回 Hello 响应,而在 5000 端口返回监控数据。下面将 Pod 暴露到 Service 上:

1
kubectl create service clusterip apiserver --tcp 8001:8000 --tcp 5001:5000
  • 创建网络策略

仅允许包含标签 role=monitoring 的 Pod 访问应用的 5000 端口。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
cat <<EOF | kubectl apply -f -
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: api-allow-5000
spec:
  podSelector:
    matchLabels:
      app: apiserver
  ingress:
  - ports:
    - port: 5000
    from:
    - podSelector:
        matchLabels:
          role: monitoring
EOF
  • 测试网络策略
1
2
3
4
5
6
7
kubectl run --generator=run-pod/v1 test-$RANDOM --rm -i -t --image=alpine -- sh

/ # wget -qO- --timeout=2 http://apiserver:8001
wget: download timed out

/ # wget -qO- --timeout=2 http://apiserver:5001/metrics
wget: download timed out
1
2
3
4
5
6
7
8
9
kubectl run --generator=run-pod/v1 test-$RANDOM --labels=role=monitoring --rm -i -t --image=alpine -- sh

/ # wget -qO- --timeout=2 http://apiserver:8001
wget: download timed out

/ # wget -qO- --timeout=2 http://apiserver:5001/metrics
http.requests=1
go.goroutines=5
go.cpus=4
  • 清理环境
1
2
3
kubectl delete pod apiserver
kubectl delete service apiserver
kubectl delete networkpolicy api-allow-5000

3.9 使用多个选择器指定访问来源

  • 创建负载
1
kubectl run --generator=run-pod/v1 db --image=redis:4 --port 6379 --expose --labels app=bookstore,role=db
  • 创建网络策略

可以同时配置多个允许的来源,只需要其中一个匹配即可访问。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
cat <<EOF | kubectl apply -f -
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: redis-allow-services
spec:
  podSelector:
    matchLabels:
      app: bookstore
      role: db
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: bookstore
          role: search
    - podSelector:
        matchLabels:
          app: bookstore
          role: api
    - podSelector:
        matchLabels:
          app: inventory
          role: web
EOF
  • 测试网络策略
1
2
3
4
5
6
kubectl run --generator=run-pod/v1 test-$RANDOM --labels=app=inventory,role=web --rm -i -t --image=alpine -- sh

/ # nc -v -w 2 db 6379
db (10.59.242.200:6379) open

(works)
1
2
3
4
5
6
kubectl run --generator=run-pod/v1 test-$RANDOM --labels=app=other --rm -i -t --image=alpine -- sh

/ # nc -v -w 2 db 6379
nc: db (10.59.252.83:6379): Operation timed out

(traffic blocked)
  • 清理空间
1
2
3
kubectl delete pod db
kubectl delete service db
kubectl delete networkpolicy redis-allow-services

3.10 禁止 Pod 的出口流量

  • 创建负载
1
kubectl run --generator=run-pod/v1 web --image=nginx --port 80 --expose --labels app=web
  • 创建网络策略

禁止包含标签 app=foo 的 Pod 任何出口流量。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
cat <<EOF | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: foo-deny-egress
spec:
  podSelector:
    matchLabels:
      app: foo
  policyTypes:
  - Egress
  egress: []
EOF
  • 测试网络策略
1
2
3
4
5
6
7
kubectl run --generator=run-pod/v1 --rm --restart=Never --image=alpine -i -t -l app=foo test -- ash

/ # wget -qO- --timeout 1 http://web:80/
wget: bad address 'web:80'

/ # wget -qO- --timeout 1 http://www.example.com/
wget: bad address 'www.example.com'
  • 清理环境
1
2
kubectl delete pod,service web
kubectl delete networkpolicy foo-deny-egress

3.11 拒绝外部出口流量

  • 创建负载
1
kubectl run --generator=run-pod/v1 web --image=nginx --port 80 --expose --labels app=web
  • 创建网络策略

允许包含标签 app=foo 的 Pods 访问全部 53 端口的服务,同时允许访问全部命名空间的应用。这里的 ports 和 to 是或的关系。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
cat <<EOF | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: foo-deny-external-egress
spec:
  podSelector:
    matchLabels:
      app: foo
  policyTypes:
  - Egress
  egress:
  - ports:
    - port: 53
      protocol: UDP
    - port: 53
      protocol: TCP
  - to:
    - namespaceSelector: {}
EOF
  • 测试网络策略
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
kubectl run --generator=run-pod/v1 --rm --restart=Never --image=alpine -i -t -l app=foo test -- ash

/ # wget -O- --timeout 1 http://web:80
Connecting to web (10.59.245.232:80)
<!DOCTYPE html>
<html>

/ # wget -O- --timeout 1 http://www.example.com
Connecting to www.example.com (93.184.216.34:80)
wget: download timed out
  • 清理环境
1
2
kubectl delete pod,service web
kubectl delete networkpolicy foo-deny-external-egress

4. 参考


微信公众号