Kubernetes DNS and Network Policies: Secure Service Communication in Your Cluster

jay75chauhan
5 min readOct 24, 2024

--

Kubernetes, the go-to platform for orchestrating containerized applications, simplifies pod and service communication through an essential component: DNS. However, unrestricted communication between services in a cluster can expose vulnerabilities. This is where Network Policies come into play, giving you fine-grained control over how services interact within the cluster. In this article, we’ll walk through how Kubernetes DNS works, how you can use it to enable service-to-service communication, and how Network Policies enforce security, preventing unauthorized access.

Kubernetes DNS: Simplifying Service Discovery

DNS (Domain Name System) plays a crucial role in Kubernetes by providing name resolution within the cluster. It’s the key to allowing services and pods to communicate with each other seamlessly, using human-readable names instead of hardcoded IP addresses.

CoreDNS: The Heart of Kubernetes DNS

Kubernetes uses CoreDNS as the default DNS server. CoreDNS handles DNS resolution for both services and pods within the cluster. For example, if you create a service named backend, Kubernetes automatically generates a DNS entry for it in the form of:

backend.default.svc.cluster.local

Here’s the breakdown:

  • backend: The name of the service.
  • default: The namespace where the service is running.
  • svc.cluster.local: A domain suffix applied to all services in the cluster.

When a pod needs to interact with the backend service, it can simply use the DNS name backend.default.svc.cluster.local, and CoreDNS will resolve this name to the internal ClusterIP of the backend service.

Example: Frontend and Backend Pod Interaction via DNS

Let’s create a simple example to demonstrate how a frontend pod communicates with a backend service using Kubernetes DNS.

# backend-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: backend
spec:
replicas: 1
selector:
matchLabels:
app: backend
template:
metadata:
labels:
app: backend
spec:
containers:
- name: backend
image: nginx

We’ll expose the backend deployment as a service:

# backend-service.yaml
apiVersion: v1
kind: Service
metadata:
name: backend
spec:
selector:
app: backend
ports:
- protocol: TCP
port: 80
targetPort: 80

Next, we create a frontend pod that interacts with the backend service:

# frontend-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: frontend
spec:
containers:
- name: frontend
image: curlimages/curl
command: ["sleep", "3600"]

Now, let’s test DNS resolution by using nslookup and curl from the frontend pod:

Check DNS Resolution:

kubectl exec -it frontend -- nslookup backend.default.svc.cluster.local

The DNS query will return the ClusterIP of the backend service, which allows the frontend pod to communicate with it.

Make a Request from Frontend to Backend:

kubectl exec -it frontend -- curl backend.default.svc.cluster.local

The frontend pod can now send HTTP requests to the backend service using the DNS name, without needing to know its internal IP address.

Kubernetes Network Policies: Controlling Pod Communication

While Kubernetes DNS enables seamless service discovery, unrestricted communication between pods may not always be desirable. Network Policies allow you to enforce fine-grained control over pod-to-pod communication, acting as a firewall to ensure only permitted traffic is allowed.

By default, all pods in Kubernetes can communicate with each other, but Network Policies let you define rules that:

  • Restrict pod-to-pod communication.
  • Allow or deny ingress (incoming) and egress (outgoing) traffic.
  • Secure communication between services.

Basic Components of a Network Policy

  1. Pod Selector: Specifies the target pods the policy applies to.
  2. Policy Types: Defines whether the policy applies to ingress (incoming) traffic, egress (outgoing), or both.
  3. Ingress/Egress Rules: Specifies the allowed or denied traffic for the selected pods.

Example 1: Deny All Traffic

Let’s start with a very restrictive policy that blocks all ingress and egress traffic to a set of pods.

# deny-all-policy.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-all
namespace: default
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress

This policy denies all incoming and outgoing traffic for all pods in the default namespace. No pod can talk to any other pod or external resource.

Example 2: Allow Frontend to Backend Communication

In a more realistic scenario, we’ll create a network policy that:

  • Allows the frontend pod to communicate with the backend service.
  • Ensures that DNS traffic to CoreDNS is allowed for proper name resolution.
# network-policy.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend-to-backend
namespace: default
spec:
podSelector:
matchLabels:
app: backend
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
egress:
- to:
- podSelector:
matchLabels:
app: frontend
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53

Policy Breakdown:

  • Pod Selector: The policy applies to pods labeled app=backend.
  • Ingress Rule: Only allows traffic from pods labeled app=frontend to reach the backend service.
  • Egress Rule: Allows traffic from the backend pod to both frontend and CoreDNS (for DNS resolution).
  • DNS Rules: Ports 53 (TCP/UDP) are opened for communication with the DNS service.

Testing the Network Policy

Apply the Network Policy:

kubectl apply -f network-policy.yaml

Test Communication from Frontend Pod: The frontend pod should still be able to access the backend service via DNS and send HTTP requests:

kubectl exec -it frontend -- curl backend.default.svc.cluster.local

Testing from Unallowed Pod: If you create another pod (say otherpod) that doesn't match the allowed labels, it will not be able to communicate with the backend service.

Advanced Network Policies

Here are a few more use cases where Network Policies shine:

1. Restricting Egress Traffic:

You can control which external IPs or services a pod can access. For example, allow access to only a specific API or DNS server.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-external-api
namespace: default
spec:
podSelector:
matchLabels:
app: backend
policyTypes:
- Egress
egress:
- to:
- ipBlock:
cidr: 8.8.8.8/32 # Google DNS
ports:
- protocol: UDP
port: 53
- ipBlock:
cidr: 203.0.113.0/24 # External API range

2. Isolating Namespaces:

Use Network Policies to ensure that pods in one namespace can’t communicate with pods in another namespace unless explicitly allowed.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: restrict-cross-namespace
namespace: app-namespace
spec:
podSelector: {}
ingress:
- from:
- namespaceSelector:
matchLabels:
name: app-namespace

Conclusion: DNS + Network Policies = Secure, Efficient Communication

In Kubernetes, DNS enables seamless service discovery, allowing pods to communicate using simple names instead of complex IP addresses. Meanwhile, Network Policies add a vital layer of security by controlling how services communicate, both within the cluster and with external resources.

By mastering both Kubernetes DNS and Network Policies, you can ensure your microservices architecture is scalable, secure, and robust — allowing only authorized communication and protecting your applications from unwanted traffic.

--

--

No responses yet