K8s出口NetworkPolicy匹配标签时拒绝访问问题排查求助
问题概述
配置了最小权限的Kubernetes网络策略,仅允许带有networking/client: auth-api-postgresdb-migrations标签的迁移Job访问带有networking/client: auth-api-postgresdb标签的PostgreSQL资源:
- PostgreSQL的Ingress策略正常生效
- 迁移Job可直接连接PostgreSQL Pod,但无法通过ClusterIP Service访问
- 移除Egress策略的
podSelector限制后,Service访问恢复正常
现有配置
PostgreSQL Ingress策略
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: auth-api-postgres spec: policyTypes: - Ingress podSelector: matchLabels: networking/client: auth-api-postgresdb ingress: - ports: - protocol: TCP port: 5432 from: - podSelector: matchLabels: networking/client: auth-api-postgresdb-migrations
迁移Job Egress策略
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: auth-api-postgresdb-migrations spec: policyTypes: - Egress podSelector: matchLabels: networking/client: auth-api-postgresdb-migrations egress: - ports: - protocol: TCP port: 5432 to: - podSelector: matchLabels: networking/client: auth-api-postgresdb
命名空间全局策略
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: default-deny spec: podSelector: {} policyTypes: - Ingress - Egress --- apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-dns-access spec: podSelector: matchLabels: {} policyTypes: - Egress egress: - to: - namespaceSelector: matchLabels: kubernetes.io/metadata.name: kube-system podSelector: matchLabels: k8s-app: kube-dns ports: - protocol: UDP port: 53 - protocol: TCP port: 53 --- apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-istio-proxy-access spec: podSelector: matchLabels: {} policyTypes: - Egress egress: - to: - namespaceSelector: matchLabels: kubernetes.io/metadata.name: istio-system podSelector: matchLabels: app: istiod ports: - protocol: TCP port: 15012
资源与错误信息
资源列表
$ k get all -n test -l networking/client=auth-api-postgresdb NAME READY STATUS RESTARTS AGE pod/auth-api-postgresdb-postgresql-0 2/2 Running 0 3m42s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/auth-api-postgresdb-postgresql ClusterIP 172.20.130.101 <none> 5432/TCP 3m42s service/auth-api-postgresdb-postgresql-hl ClusterIP None <none> 5432/TCP 3m42s service/auth-api-postgresdb-postgresql-metrics ClusterIP 172.20.134.229 <none> 9187/TCP 3m42s NAME READY AGE statefulset.apps/auth-api-postgresdb-postgresql 1/1 3m42s
错误日志
... Opening connection to database 'identity' on server 'tcp://auth-api-postgresdb-postgresql:5432' ... Npgsql.NpgsqlException (0x80004005): Failed to connect to 172.20.130.101:5432 ...
问题根源
标准Kubernetes NetworkPolicy的egress.to.podSelector仅匹配最终目标Pod的标签,但通过ClusterIP Service访问时,流量的初始目标IP是Service的ClusterIP,而非Pod IP。多数CNI插件(如kube-proxy的iptables模式)会在转发流量到Pod前检查Egress规则,此时规则仅允许到PostgreSQL Pod的流量,不允许到Service ClusterIP的流量,因此被default-deny策略拦截。
直接连接Pod时,目标IP是Pod IP,符合podSelector规则,所以能正常访问。
解决方案
方案1:使用Headless Service(最符合最小权限)
将迁移Job的数据库连接地址改为Headless Service auth-api-postgresdb-postgresql-hl:5432。Headless Service的DNS解析直接返回Pod IP,流量直接发往Pod,无需经过ClusterIP转发,现有Egress策略的podSelector规则即可匹配,无需修改任何网络策略。
方案2:允许到Service ClusterIP的流量(兼容普通Service)
修改迁移Job的Egress策略,添加对PostgreSQL Service ClusterIP的访问规则:
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: auth-api-postgresdb-migrations spec: policyTypes: - Egress podSelector: matchLabels: networking/client: auth-api-postgresdb-migrations egress: # 允许到PostgreSQL Pod的流量 - ports: - protocol: TCP port: 5432 to: - podSelector: matchLabels: networking/client: auth-api-postgresdb # 允许到PostgreSQL Service ClusterIP的流量 - ports: - protocol: TCP port: 5432 to: - ipBlock: cidr: 172.20.130.101/32 # 替换为你的PostgreSQL Service ClusterIP # 保留DNS访问(继承全局策略,若已覆盖可省略) - to: - namespaceSelector: matchLabels: kubernetes.io/metadata.name: kube-system podSelector: matchLabels: k8s-app: kube-dns ports: - protocol: UDP port: 53 - protocol: TCP port: 53
方案3:允许到集群Service CIDR的流量(更灵活,权限略宽)
如果不想硬编码ClusterIP,可允许到整个集群Service CIDR的5432端口流量(需先通过kubectl cluster-info dump | grep -m 1 service-cluster-ip-range获取Service CIDR):
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: auth-api-postgresdb-migrations spec: policyTypes: - Egress podSelector: matchLabels: networking/client: auth-api-postgresdb-migrations egress: - ports: - protocol: TCP port: 5432 to: - podSelector: matchLabels: networking/client: auth-api-postgresdb - ipBlock: cidr: 172.20.0.0/16 # 替换为你的集群Service CIDR # DNS访问规则 - to: - namespaceSelector: matchLabels: kubernetes.io/metadata.name: kube-system podSelector: matchLabels: k8s-app: kube-dns ports: - protocol: UDP port: 53 - protocol: TCP port: 53
内容的提问来源于stack exchange,提问作者APW

