Reputation: 578
I have an application that is deployed using Helm inside an AWS EKS cluster with VPC CNI enabled for Network Policies. That has worked so far using only ingress allowlist policies, but unfortunately a new requirement is that also egress has to be allowlisted.
Despite adding an egress rule to the backend's network policy, it is unable to contact the Redis service (and eventually, wait-for-it fails as it couldn't contact Redis). DNS resolution is not the culprit, that one got fixed after I added an egress policy to all pods allowing egress to TCP/UDP 53 in the kube-system namespace (and thus, I also see that egress allowing works in principle).
Any idea what I am missing? Is there maybe a way to show the pods allowed by a selector rule combination in kubectl describe networkpolicy
similar to how kubectl describe service
shows the currently active endpoints?
The AWS VPC CNI logs of the host where the backend pod's init container show a DENY
for the traffic (as expected):
{"level":"info","ts":"2024-11-13T20:13:43.120Z","logger":"ebpf-client","msg":"Flow Info: ","Src IP":"198.18.0.177","Src Port":37827,"Dest IP":"192.168.28.141","Dest Port":6379,"Proto":"TCP","Verdict":"DENY"}
The source IP is the one of the backend pod:
$ kubectl get pod -o custom-columns=NAME:metadata.name,IP:status.podIP,HOST:status.hostIP|grep -e '198.18.0.177'
backend-branch-develop-84b68c4695-w9r49 198.18.0.177 198.18.3.63
But curiously, the destination IP seems to be wrong - it tries to filter for the service's IP instead of whatever IP the individual Redis pod has:
$ kubectl get pod -o custom-columns=NAME:metadata.name,IP:status.podIP,HOST:status.hostIP|grep -e 'redis-branch-develop'
redis-branch-develop-6c96759874-rzbfk 198.18.7.113 198.18.3.100
$ kubectl get service -o custom-columns=NAME:metadata.name,IP:spec.clusterIP|grep -e '192.168.28.141'
redis-branch-develop 192.168.28.141
$ kubectl get namespace --selector=kubernetes.io/metadata.name=mynamespace
NAME STATUS AGE
mynamespace Active 460d
$ kubectl get pod --selector=app=redis-branch-develop,release-name=branch-develop,software-name=myapp
NAME READY STATUS RESTARTS AGE
redis-branch-develop-6c96759874-rzbfk 1/1 Running 0 3h13m
$ kubectl get pod --selector=app=backend-branch-develop,release-name=branch-develop,software-name=myapp
NAME READY STATUS RESTARTS AGE
backend-branch-develop-84b68c4695-w9r49 0/1 Init:0/3 5 (5m12s ago) 36m
$ kubectl describe service redis-branch-develop
Name: redis-branch-develop
Namespace: mynamespace
Labels: app.kubernetes.io/managed-by=Helm
Annotations: meta.helm.sh/release-name: branch-develop
meta.helm.sh/release-namespace: mynamespace
Selector: app=redis-branch-develop
Type: ClusterIP
IP Family Policy: SingleStack
IP Families: IPv4
IP: 192.168.28.141
IPs: 192.168.28.141
Port: redis 6379/TCP
TargetPort: 6379/TCP
Endpoints: 198.18.7.113:6379
Session Affinity: None
Events: <none>
$ kubectl describe networkpolicy myapp-netpol-allow-backend-branch-develop myapp-netpol-allow-redis-branch-develop myapp-netpol-allowdns-branch-develop myapp-netpol-denyall-branch-develop
Name: myapp-netpol-allow-backend-branch-develop
Namespace: mynamespace
Created on: 2024-11-13 13:11:51 +0100 CET
Labels: app.kubernetes.io/managed-by=Helm
Annotations: meta.helm.sh/release-name: branch-develop
meta.helm.sh/release-namespace: mynamespace
Spec:
PodSelector: app=backend-branch-develop,release-name=branch-develop,software-name=myapp
Allowing ingress traffic:
To Port: 1337/TCP
From:
PodSelector: app.kubernetes.io/component=controller,app.kubernetes.io/name=ingress-nginx
Allowing egress traffic:
To Port: 6379/TCP
To:
NamespaceSelector: kubernetes.io/metadata.name=mynamespace
PodSelector: app=redis-branch-develop,release-name=branch-develop,software-name=myapp
Policy Types: Ingress, Egress
Name: myapp-netpol-allow-redis-branch-develop
Namespace: mynamespace
Created on: 2024-11-13 13:11:51 +0100 CET
Labels: app.kubernetes.io/managed-by=Helm
Annotations: meta.helm.sh/release-name: branch-develop
meta.helm.sh/release-namespace: mynamespace
Spec:
PodSelector: app=redis-branch-develop,release-name=branch-develop,software-name=myapp
Allowing ingress traffic:
To Port: 6379/TCP
From:
NamespaceSelector: kubernetes.io/metadata.name=mynamespace
PodSelector: app=backend-branch-develop,release-name=branch-develop,software-name=myapp
Not affecting egress traffic
Policy Types: Ingress
Name: myapp-netpol-allowdns-branch-develop
Namespace: mynamespace
Created on: 2024-11-13 20:12:15 +0100 CET
Labels: app.kubernetes.io/managed-by=Helm
Annotations: meta.helm.sh/release-name: branch-develop
meta.helm.sh/release-namespace: mynamespace
Spec:
PodSelector: release-name=branch-develop,software-name=myapp
Not affecting ingress traffic
Allowing egress traffic:
To Port: 53/TCP
To Port: 53/UDP
To:
NamespaceSelector: kubernetes.io/metadata.name=kube-system
PodSelector: k8s-app=kube-dns
Policy Types: Egress
Name: myapp-netpol-denyall-branch-develop
Namespace: mynamespace
Created on: 2024-11-13 13:11:51 +0100 CET
Labels: app.kubernetes.io/managed-by=Helm
Annotations: meta.helm.sh/release-name: branch-develop
meta.helm.sh/release-namespace: mynamespace
Spec:
PodSelector: release-name=branch-develop,software-name=myapp
Allowing ingress traffic:
<none> (Selected pods are isolated for ingress connectivity)
Allowing egress traffic:
<none> (Selected pods are isolated for egress connectivity)
Policy Types: Ingress, Egress
Upvotes: 0
Views: 83
Reputation: 1356
You are trying to communicate through the clusterIP service, not the the redis POD, that's why the destination policy seen by network policy is the service POD while it's configured to allow communication for the POD instead. so to solve the issue you have to update the egress policy to include the clusterIP also
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: myapp-netpol-allow-backend-branch-develop
namespace: mynamespace
spec:
podSelector:
matchLabels:
app: backend-branch-develop
release-name: branch-develop
software-name: myapp
policyTypes:
- Egress
egress:
- to:
- podSelector:
matchLabels:
app: redis-branch-develop
release-name: branch-develop
software-name: myapp
namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: mynamespace
ports:
- protocol: TCP
port: 6379
- to:
- ipBlock:
cidr: 192.168.28.141/32
ports:
- protocol: TCP
port: 6379
If you only have an egress rule allowing connections to Redis pods (via PodSelector), traffic routed through the service will be blocked, because the egress rule does not match the service’s ClusterIP, the previous configuration will allow now both, egress to redis pod directly, and egress to the clusterIP as well.
Upvotes: 0