第 43 篇 k8s之集群网络策略:NetworkPolicy 入门

IT策士 10余年一线大厂经验,专注 IT 思维、架构、职场进阶。我会在各个平台持续发布最新文章,助你少走弯路。


在第 38 篇中,我们用 RBAC 解决了"谁能操作什么资源"的授权问题。但安全防护还有另一条战线:网络层。默认情况下,Kubernetes 集群内的所有 Pod 之间可以自由通信。这带来了一个风险:一旦某个 Pod 被攻破,攻击者就能以它为跳板,访问集群内的所有其他服务。

在 Docker Compose 时代,这种风险相对可控------所有容器都在一台宿主机上,你可以通过绑定特定 IP、配置自定义网络来实现基本隔离。但在 K8s 集群中,Pod 可能分布在多台节点上,你需要的是以应用为粒度的网络防火墙。这就是 NetworkPolicy 的使命。

今天这篇,我们从"零信任"的安全理念讲起,拆解 NetworkPolicy 的核心三要素,然后把它应用到贯穿案例的 Flask + Redis 应用中------让 Redis 只接受 Flask 的访问,拒绝一切其他来源的流量。

一、从"全通"到"零信任":为什么需要 NetworkPolicy?

1.1 K8s 的默认网络模型:扁平全通

K8s 的网络模型有一条基本原则:所有 Pod 之间可以不经过 NAT 直接通信,无论它们是否在同一节点上。这极大简化了微服务间的通信------你不用配置任何路由规则,Flask 就能直接访问 Redis 的 Pod IP。

但这种"全通"模式也带来了安全隐患。假如你的集群中运行着以下 Pod:

  • Flask 应用(处理用户请求,暴露在 Ingress 之后)

  • Redis(存储缓存数据,仅应被 Flask 访问)

  • 后台批处理任务(连接外部 API,不应访问 Redis)

默认情况下,这三个 Pod 之间可以任意互通。 如果 Flask 应用存在安全漏洞(比如 RCE 远程代码执行),攻击者就能通过 Flask Pod 直接连接到 Redis,读取或删除所有缓存数据。

1.2 Docker 网络隔离 vs K8s NetworkPolicy

回顾第 8 篇 Docker 网络入门,我们通过自定义 bridge 网络实现了容器间的隔离------不在同一网络的容器无法互相访问。但这种隔离粒度太粗了:它基于"网络"而非"应用标签"。

NetworkPolicy 提供了更精细的控制:你可以基于 Pod 的标签(Label)和命名空间(Namespace),精确控制哪些 Pod 可以访问哪些 Pod,以及允许哪些端口和协议。这就是"零信任"安全模型在 K8s 中的实现------默认拒绝一切流量,只显式允许必要的通信。

1.3 NetworkPolicy 的前置条件

重要提醒:NetworkPolicy 只是"规则定义",它需要**网络插件(CNI)**来实际执行。不是所有 CNI 插件都支持 NetworkPolicy:

Minikube 默认使用 Flannel,不支持 NetworkPolicy。要让本篇的配置生效,你需要先启用 Calico:

bash 复制代码
# 删除旧集群并重建(Calico 需要从集群创建时配置)
minikube delete
minikube start --cni=calico --driver=docker

二、NetworkPolicy 的核心三要素

NetworkPolicy 通过三个核心字段定义规则:

2.1 podSelector:规则应用给谁?

podSelector 通过标签选择一组 Pod,作为规则的目标 。例如 podSelector: matchLabels: app: redis 表示"对带有 app=redis 标签的 Pod 应用此规则"。

2.2 policyTypes:控制哪个方向的流量?

如果只写 policyTypes: [Ingress],则只控制入站流量,不限制出站流量(出站全放通)。

2.3 ingress/egress:具体规则

规则的 from 字段定义流量来源(入站),to 字段定义流量目的(出站),每个来源/目的可以通过三种方式指定:

规则生效逻辑from 中的多个选择器是 OR 关系 (任一匹配即放行),但选择器内部的多个条件(如 podSelectornamespaceSelector 同时出现)是 AND 关系(必须同时满足)。

三、实战:为 Flask + Redis 配置 NetworkPolicy

现在我们为贯穿案例的 Flask + Redis 应用配置网络隔离策略。核心目标是:

  1. Redis 只能被 Flask Pod 访问(拒绝其他所有 Pod)。

  2. Flask 只能被 Ingress Controller 访问(拒绝直接的 Pod-to-Pod 请求)。

  3. 禁止所有未声明的流量(默认拒绝)。

3.1 场景:只允许 Flask 访问 Redis

先配置 Redis 的安全策略:

bash 复制代码
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: redis-allow-flask-only
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: redis
  policyTypes:
    - Ingress
  ingress:
    - from:
        - podSelector:
            matchLabels:
              app: flask-counter
      ports:
        - protocol: TCP
          port: 6379

规则解读:

  • podSelector: app: redis:本规则应用于 Redis Pod。

  • policyTypes: [Ingress]:控制入站流量。

  • from: podSelector: app: flask-counter :只放行来自 app=flask-counter 标签的 Pod 的流量。

  • ports: 6379:进一步限制只能访问 Redis 的默认端口。

效果 :部署此规则后,任何没有 app=flask-counter 标签的 Pod 都无法连接 Redis。

3.2 验证隔离效果

部署一个测试 Pod 来验证规则是否生效:

bash 复制代码
# 启动一个 alpine 测试 Pod
kubectl run test-pod --image=alpine --rm -it -- sh

# 在测试 Pod 内安装 curl 和 redis
apk add curl redis

# 测试 1:直接访问 Redis(应该被拒绝)
redis-cli -h redis-service -p 6379 PING
# 如果规则生效,连接会超时或拒绝

# 测试 2:访问 Flask(Flask 没有 Ingress 规则,应被拒绝)
curl http://flask-service:5000/health
# 连接超时或拒绝

现在从 Flask Pod 内部访问 Redis(应该成功):

bash 复制代码
kubectl exec deploy/flask-deployment -- redis-cli -h redis-service PING
# PONG

3.3 默认拒绝所有流量

NetworkPolicy 的规则是累加 的------多条规则的效果合并,任一规则的 from 匹配即可放行。如果没有匹配任何 NetworkPolicy,流量默认被放行。要实现"默认拒绝",需要创建一条"拒绝所有"的兜底规则:

bash 复制代码
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: default
spec:
  podSelector: {}
  policyTypes:
    - Ingress

podSelector: {} 表示选择命名空间中所有 Pod ,而空的 ingress 规则意味着没有任何来源被允许。这条规则与 redis-allow-flask-only 等显式规则共同作用------显式规则打开特定通道,兜底规则关闭其他所有入口。

3.4 允许 Ingress Controller 访问 Flask

默认拒绝后,外部的 Ingress Controller 也无法访问 Flask。需要显式放行:

bash 复制代码
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: flask-allow-ingress
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: flask-counter
  policyTypes:
    - Ingress
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: ingress-nginx
      ports:
        - protocol: TCP
          port: 5000

这里使用 namespaceSelector 选择了 ingress-nginx 命名空间中的所有 Pod,允许它们访问 Flask 的 5000 端口。

3.5 完整的安全策略

现在我们的应用安全策略包括:

应用所有策略:

bash 复制代码
kubectl apply -f redis-networkpolicy.yaml
kubectl apply -f flask-networkpolicy.yaml
kubectl apply -f default-deny.yaml

kubectl get networkpolicy
# NAME                    POD-SELECTOR         AGE
# default-deny-all        <none>               30s
# flask-allow-ingress     app=flask-counter    20s
# redis-allow-flask-only  app=redis            10s

四、Egress 规则:控制 Pod 的出站流量

除了入站流量,NetworkPolicy 还可以限制 Pod 的出站流量------Pod 可以访问哪些外部服务。

例如,只允许 Flask Pod 访问 Redis 和 CoreDNS(否则 Pod 无法解析域名):

bash 复制代码
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: flask-egress
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: flask-counter
  policyTypes:
    - Egress
  egress:
    - to:
        - podSelector:
            matchLabels:
              app: redis
      ports:
        - protocol: TCP
          port: 6379
    - to:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: kube-system
        - podSelector:
            matchLabels:
              k8s-app: kube-dns
      ports:
        - protocol: UDP
          port: 53

规则解读:

  • 允许 Flask 访问 Redis 的 6379 端口(TCP)

  • 允许 Flask 访问 kube-system 命名空间中的 CoreDNS(UDP 53),确保 DNS 解析正常工作

  • 其他所有出站流量(如访问外部 API)将被拒绝

五、NetworkPolicy 排错指南

NetworkPolicy 排错的核心是隔离问题范围------确认是 CNI 不支持、标签选择器写错了、还是端口/协议不对:

bash 复制代码
# 1. 检查 CNI 插件是否支持 NetworkPolicy
kubectl get pods -n kube-system | grep -E "calico|cilium|weave"
# 如果有输出,说明支持;如果只看到 flannel,需要更换 CNI

# 2. 查看 NetworkPolicy 规则
kubectl describe networkpolicy <策略名>

# 3. 检查 Pod 标签是否匹配
kubectl get pods --show-labels | grep <关键词>
# 如果 Pod 的实际标签与 NetworkPolicy 的 podSelector 不匹配,规则不会生效

# 4. 用测试 Pod 验证连通性
kubectl run test --image=alpine --rm -it -- sh
apk add curl
curl http://<service-name>:<port>/health --connect-timeout 3
# 根据超时或被拒判断策略是否生效

六、对比 Docker Compose 的网络隔离

Docker Compose 通过不同网络实现粗粒度隔离,而 NetworkPolicy 提供了更灵活、更细粒度的网络防火墙。在 Compose 中要限制某个容器只能被特定容器访问,需要精细规划网络拓扑;在 K8s 中,只需要用标签和选择器声明规则即可。

七、命令速查表

八、本篇总结

  • NetworkPolicy 的定位:K8s 原生的网络防火墙,通过标签和选择器精确控制 Pod 间的流量,实现"零信任"网络模型。但它只是规则定义,实际执行依赖 CNI 插件(Calico、Cilium 等)。

  • 核心三要素podSelector(目标 Pod)、policyTypes(Ingress/Egress)、ingress/egress(具体规则),规则中通过 podSelector、namespaceSelector、ipBlock 三种方式指定流量来源或目的。

  • 实战成果:为 Flask + Redis 应用配置了最小权限的网络策略------Redis 只接受 Flask 的连接,Flask 只接受 Ingress Controller 的流量,并设置默认拒绝兜底规则。

  • 安全最佳实践:生产环境应为每个命名空间配置默认拒绝策略,然后逐项放行必要的流量。这对应了 RBAC 中的"最小权限原则",两者共同构成 K8s 安全的两道防线。

下一篇------第 44 篇:实战:将 Web 应用迁移到 Kubernetes(上),我们将把贯穿案例的 Flask + Redis 计数器应用从 Compose 彻底迁移到 K8s 集群,用 Deployment、Service、ConfigMap、Secret、PVC 等核心对象完成完整的应用部署。

想了解更多还可以去各个平台搜索「IT策士」,一起升级 IT 思维 !

相关推荐
m0_738120721 小时前
渗透测试基础——一文详解CORS跨域劫持漏洞原理与利用
服务器·网络·安全·web安全·网络安全
Jun6261 小时前
QT(6)-UDP数据收发
网络·网络协议·udp
MyFreeIT1 小时前
Docker & MySQL Manual
mysql·docker·容器
醉颜凉1 小时前
Scala Cats Effect纯函数式并发编程:从Fiber模型到生产级应用
大数据·网络·scala
牛奶咖啡131 小时前
k8s容器编排技术实践——k8s应用中机密信息的配置与存储
云原生·kubernetes·k8s中secret资源的创建·k8s的pod使用secret·k8s中configmap创建·k8s中使用configmap·k8s中重要数据的配置与存储
做个文艺程序员10 小时前
第1篇:K8s 核心概念精讲:Pod、Deployment、Service 与 Namespace——Java 开发者快速上手指南
java·云原生·容器·kubernetes·容器编排
一勺菠萝丶10 小时前
Docker Desktop 启动后容器自动启动怎么办?如何关闭容器自启动
运维·docker·容器
ylscode11 小时前
Comodo防火墙曝致命零日漏洞:单个IPv6数据包即可触发Windows蓝屏死机
运维·网络·windows·安全·安全威胁分析