A flat network is the default
In a fresh EKS cluster, any pod can open a connection to any other pod, in any namespace. The VPC CNI gives each pod a VPC address, and unless you say otherwise, security groups on the nodes allow that traffic. For a team running ten services, this is convenient. When one of them is compromised, it is a problem: the attacker can scan the cluster, reach internal admin ports and probe databases.
This page covers the network segmentation work in our AWS EKS consulting service. It is one of the controls assessed in a CIS EKS Benchmark report, and it complements pod security standards.
What good looks like
- Every namespace has a default deny policy for ingress and, for sensitive namespaces, egress.
- Allowed flows are listed explicitly and match how the application really works.
- The control plane endpoint, nodes and data stores sit behind tight security groups.
- Pods cannot reach the instance metadata service or internal ranges they do not need.
- Policy is code in Git, reviewed with the service it protects.
Two layers, two jobs
| Layer | Tool | Controls |
|---|---|---|
| AWS boundary | Security groups, NACLs, VPC endpoints | Who can reach the API endpoint, nodes, load balancers, databases |
| In-cluster | Kubernetes NetworkPolicy | Which pods can talk to which pods and external ranges |
| Per pod AWS rules | SecurityGroupPolicy (VPC CNI) | Pod level security groups for access to AWS resources |
Mixing up the layers is a common source of confusion. Security groups cannot see pod labels. Network policies cannot see an RDS instance’s own rules. A sound design uses both.
Enforcement: pick an engine
A NetworkPolicy resource is only a declaration. Something must enforce it. Options on EKS:
- Amazon VPC CNI network policy support, enabled on supported plugin and Kubernetes versions. Least extra software, uses eBPF in the node agent. Check feature limits for your version.
- Calico, a long-established option with its own extended policy types.
- Cilium, a full CNI alternative with rich policy and visibility through Hubble, but a bigger change to your networking stack.
We usually recommend the VPC CNI option for teams that want standard Kubernetes policies and minimal moving parts, and Cilium where deep visibility or layer 7 policy is a real requirement. See add-on management for how the CNI itself is kept current.
Default deny and explicit allow
A minimal pattern: deny everything in the namespace, then allow what is needed, including DNS. Without the DNS rule, a deny-all egress policy breaks name resolution immediately.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: payments
spec:
podSelector: {}
policyTypes: ["Ingress", "Egress"]
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-api-from-ingress
namespace: payments
spec:
podSelector:
matchLabels:
app: invoice-api
policyTypes: ["Ingress"]
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: ingress
ports:
- port: 8080
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-dns-egress
namespace: payments
spec:
podSelector: {}
policyTypes: ["Egress"]
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
ports:
- port: 53
protocol: UDP
- port: 53
protocol: TCP
Policies are additive: the final allowed set is the union of every policy selecting a pod. We keep them small, named by intent and stored with the application’s manifests. The network policy glossary entry covers the basics for your wider team.
Security groups that fit EKS
The cluster security group, additional node security groups, load balancer groups and database groups each get a clear purpose. Our rules:
- Allow node to node and node to control plane traffic that the cluster needs, not broad internal ranges.
- Reference security groups instead of CIDR blocks where possible, so rules follow the resources.
- Restrict the public API endpoint by CIDR or make it private.
- Place databases in a group that only admits the application’s group, or a pod-level group where per-pod isolation is justified.
- Use VPC endpoints for AWS services so egress to them does not need the open internet.
Design context for subnets and endpoints is in cluster architecture design.
Rolling out without an outage
Enforcement changes are risky because the failure is often silent. We stage them:
- Capture flows with VPC Flow Logs or Hubble in the target namespace for a representative period.
- Draft policies from observed traffic and review with the service owners.
- Apply in a non-production cluster and run integration tests.
- In production, apply one namespace at a time during a quiet window, with a tested rollback command.
- Check error rates and dropped-connection logs for at least a full business cycle.
Failure modes
- Forgotten DNS egress, breaking resolution.
- Health checks blocked: load balancer and kubelet probes need an allow path.
- Webhook traffic blocked: admission webhooks need ingress from the control plane, a frequent cause of failed deployments.
- Policies that are never enforced because the engine was not enabled.
- Overly broad CIDR allows that quietly undo the isolation.
A worked example: protecting a database
Consider a payments namespace whose API talks to a managed database. At the AWS layer, the database security group admits only the group attached to the application’s nodes or pods, never a wide internal CIDR. Inside the cluster, a default deny egress policy plus a single allow on the database port stops a compromised sibling pod in another namespace from reaching it, and stops the payments pods themselves from calling arbitrary external hosts.
If the database must be reachable by only some pods, not every pod on the node, that is the case for security groups for pods. If any pod on those nodes can be trusted equally, the node-level group with a network policy on top is simpler and usually enough. We pick the simpler option unless a requirement forces the other.
Delivery and handover
You receive policy manifests in Git, security group definitions in Terraform, connectivity test scripts and a short guide for adding a rule when a new service ships. If you run a mesh or want one, our Kubernetes consulting team can advise on service mesh trade-offs. To review your current exposure, contact us.
How to tell it is working
Run a deliberate test: from a pod in one namespace, try to reach a service that it should not. The connection should time out. Review flow logs for denied traffic, and treat unexpected denies as either missing allows or signs of misbehaving software.