欢迎光临
我们一直在努力

第 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:

# 删除旧集群并重建(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 关系(任一匹配即放行),但选择器内部的多个条件(如 podSelector 和 namespaceSelector 同时出现)是 AND 关系(必须同时满足)。

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

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

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

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

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

  • 3.1 场景:只允许 Flask 访问 Redis

    先配置 Redis 的安全策略:

    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 来验证规则是否生效:

    # 启动一个 alpine 测试 Pod
    kubectl run test-pod –image=alpine –rm -itsh

    # 在测试 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(应该成功):

    kubectl exec deploy/flask-deployment — redis-cli -h redis-service PING
    # PONG

    3.3 默认拒绝所有流量

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

    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。需要显式放行:

    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 完整的安全策略

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

    应用所有策略:

    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 无法解析域名):

    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 不支持、标签选择器写错了、还是端口/协议不对:

    # 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 -itsh
    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 思维 !

    赞(0)
    未经允许不得转载:171主机测评 » 第 43 篇 k8s之集群网络策略:NetworkPolicy 入门
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址