Join our Newsletter — 33% off our NHI Course
Home› Guides› CoreDNS Security: Harden Kubernetes DNS, Plugins and Logging
Guide Cloud & Workload Identity

CoreDNS Security: Harden Kubernetes DNS, Plugins and Logging

← All guides
By NHI Mgmt Group, edited by Lalit Choda Updated 8 November 2026 12 min read
On this page

Every Kubernetes workload finds its databases, APIs and peers through CoreDNS, so whoever can change the Corefile, or answer in its place, can quietly redirect traffic across the whole cluster. This guide explains how to run CoreDNS securely as cluster DNS and as a standalone server. It covers the Corefile and plugin chain, the coredns ConfigMap and the RBAC around it, the CoreDNS service account, the kubernetes plugin's pod record modes, upstream forwarding over TLS, the acl plugin, query logging and metrics, and the detections that show DNS being abused for spoofing or data exfiltration. It is written for platform engineers, Kubernetes administrators and detection engineers. For cluster-wide controls see the Kubernetes Security Guide; this page goes deeper on DNS.

This is an independent guide from NHI Mgmt Group, based on the CoreDNS project's public documentation as of November 2026. It is not sponsored or reviewed by the CoreDNS project. Product features change, so confirm settings against the CoreDNS project's current documentation.

Key takeaways

  • The coredns ConfigMap is a cluster-wide routing table. Write access to configmaps/coredns in kube-system lets a user add a stub domain, rewrite or hosts entry that redirects any name, and the reload plugin applies it within about two minutes. Guard it like cluster-admin.
  • Choose the pod record mode deliberately. The default Kubernetes Corefile uses pods insecure for backward compatibility; CoreDNS warns it can be abused with wildcard TLS certificates. Use pods disabled if nothing needs pod records, or pods verified if something does.
  • Plugin order comes from plugin.cfg, not the Corefile. Execution order is fixed at build time, which is why log sees a query before acl and acl acts before cache, kubernetes and forward.
  • Verify upstreams. forward . /etc/resolv.conf sends external names to the node's resolvers in plain DNS; use tls:// upstreams with tls_servername where the path crosses networks you do not control.
  • Log and measure. The log plugin with class denial error, the errors plugin and Prometheus metrics on port 9153 are enough to spot tunnelling, scanning and configuration tampering when sent to your SIEM.

How identity and access work in CoreDNS

CoreDNS has no user accounts. Its security depends on three identities and one file:

Identity or objectWhat it controlsDefault in KubernetesMain risk if misused
The Corefile (ConfigMap coredns, namespace kube-system)Zones, plugins, upstreams, rewritesEditable by anyone with update rights on that ConfigMapCluster-wide name redirection
CoreDNS service account (coredns)Reads cluster objects to build recordsClusterRole system:coredns: list and watch on endpoints, services, pods, namespaces and endpointslicesRead-only discovery of cluster topology if the token is taken
Clients (pods and nodes)Who may query and recurseAny pod with dnsPolicy: ClusterFirstTunnelling, enumeration, resolver abuse
Upstream resolversAnswers for external names/etc/resolv.conf of the nodeSpoofed external answers on an untrusted path

The upstream deployment manifest gives the service account only list and watch verbs, which is the right shape: CoreDNS needs to read, never write. Keep it that way when Helm charts or managed add-ons are upgraded, and check that no extra RoleBindings grant the coredns account more. The manifest also runs the container with allowPrivilegeEscalation: false, all capabilities dropped except NET_BIND_SERVICE, and readOnlyRootFilesystem: true. See the Kubernetes Service Account Token Guide for token handling.

When CoreDNS runs outside a cluster or talks to a remote API server, the kubernetes plugin authenticates with endpoint plus tls CERT KEY CACERT, or with a kubeconfig that may hold a token. Those files are machine credentials: mount them from a secret store, scope them to read-only access and rotate them.

Admin roles and privileged access

Privilege over cluster DNS is really privilege over three Kubernetes objects. Build roles around them:

  • ConfigMap editors: only the platform team, through GitOps with review. No application team needs update or patch on configmaps/coredns.
  • Deployment editors: rights to change the CoreDNS Deployment allow a new image, extra arguments or a different service account. Restrict deployments in kube-system to the same group.
  • Service and endpoint editors in kube-system: the kube-dns Service ClusterIP is what every pod's /etc/resolv.conf points at. Changing its selector moves cluster DNS to another pod.

Use an admission policy to reject ConfigMap changes that add hosts, rewrite or new forward targets outside an approved list (see the Kubernetes Admission Control Guide), and audit every change through the Kubernetes audit log. For role design see the Kubernetes RBAC Guide.

Integrations, API tokens and service accounts

The Corefile and plugin chain

Server blocks define the zones and port (default 53) a server answers. The CoreDNS manual explains that the order of plugins in the Corefile does not set execution order; plugin.cfg does, and it is fixed when the binary is built. In the standard build, log runs before acl, and acl runs before cache, hosts, kubernetes and forward, so blocked queries are still logged and never reach the cache or an upstream. A query that reaches the end of the chain unanswered returns SERVFAIL. Corefiles can import snippets and substitute environment variables with {$ENV_VAR}; review every imported file because it changes the running configuration.

Security-relevant plugins

PluginSecurity useRecommended setting
kubernetesService and pod recordspods disabled or pods verified; limit with namespaces or labels where a server block serves a subset; scope fallthrough to named zones
aclAllow, block (REFUSED), filter (empty NOERROR) or drop by query type and sourceDefault action is allow, so end lists with an explicit block for net * where you need a closed list
forwardUpstream resolutiontls:// upstreams with tls_servername; max_concurrent to cap load
log and errorsQuery and error recordslog . { class denial error } for steady state
prometheusMetrics on :9153Reachable only by your monitoring namespace
chaosAnswers version.bindLeave out unless needed, so the version is not disclosed
bindInterfaces CoreDNS listens onUse on standalone servers with several interfaces
hosts, rewrite, templateStatic or rewritten answersChange only through review; alert on additions

Pod records and spoofing inside the cluster

With pods insecure, CoreDNS returns an A record for any IP written in pod name form without checking that a pod has that address. The plugin documentation warns this can be abused together with wildcard TLS certificates: a name under the pod zone can be made to resolve to an arbitrary internal address while a wildcard certificate appears valid for it. pods verified answers only when a pod in that namespace holds the IP, at the cost of more memory because CoreDNS watches all pods. Our recommendation: start with pods disabled, check DNS error metrics and application logs in a staging cluster for a week, and move to verified only for workloads that genuinely need pod names. Avoid issuing wildcard certificates for cluster zones.

Other in-cluster spoofing paths are controlled outside CoreDNS. A pod with dnsPolicy: None and a custom dnsConfig, or with hostNetwork, can use a resolver you do not run. Restrict these with admission policy, and use NetworkPolicy so that pods can send UDP and TCP 53 only to the CoreDNS pods, which also stops workloads querying external resolvers directly.

Upstream forwarding

For tls:// upstreams CoreDNS sets a minimum of TLS 1.2. The forward documentation strongly recommends tls_servername (or per-endpoint SNI written as tls://IP%servername), because without it the upstream's identity is not verified. tls CERT KEY CA adds client authentication for private resolvers. Use except to keep internal zones off public resolvers, and leave health checking on, since max_fails 0 treats every upstream as healthy. Pointing the forwarder at your organisation's protective resolver gives cluster workloads the same filtering as the rest of the estate; see the Protective DNS Guide.

Logging and detection

The log plugin writes one line per query in Common Log Format: client IP and port, query ID, type, class, name, protocol, sizes, DNSSEC OK bit, response code, flags and duration. Its class filter accepts success, denial (NXDOMAIN or NODATA), error (SERVFAIL, NOTIMP, REFUSED) and all (the default). Full logging has a performance cost on busy clusters, so many teams log denial error continuously and switch to all during an investigation, or use the dnstap plugin to stream queries to a collector. Ship CoreDNS container logs to your SIEM with the pod's namespace attached so client IPs map back to workloads. See the DNS Logging and Detection Guide.

BehaviourSignalATT&CK
DNS tunnelling or command and controlOne workload sending many long, high-entropy labels or TXT queries to a single external domainT1071.004
Data exfiltration over DNSSustained unique subdomains with large query sizes from one podT1048
Service enumerationBursts of NXDOMAIN for *.svc.cluster.local names, SRV sweeps or reverse lookups across the service CIDRT1046
Redirection through configurationAudit events for update or patch on configmaps/coredns; new forward, hosts or rewrite linesT1557
Resolver overloadRising REFUSED from max_concurrent, SERVFAIL spikes, latency histogram growthT1498

Pair CoreDNS logs with the Kubernetes Audit Log Detection Guide so ConfigMap and Deployment changes are caught at the API server, not only in query patterns.

Metrics that show the controls are working:

  • Number of principals with write access to configmaps/coredns (target: the platform group and GitOps controller only).
  • Percentage of clusters running pods disabled or pods verified.
  • Percentage of namespaces with NetworkPolicy limiting egress port 53 to CoreDNS.
  • Mean time to alert on a Corefile change made outside GitOps.
  • Share of external forwarding sent over verified TLS upstreams.

Hardening baseline

  1. Inventory: for each cluster record the CoreDNS version, image source, Corefile, plugins in use and who can edit the ConfigMap and Deployment. Managed Kubernetes add-ons may own the ConfigMap; follow the provider's documented customisation method.
  2. Lock RBAC: remove broad kube-system write grants, keep system:coredns at list and watch, and manage the Corefile through GitOps.
  3. Set pod records: change pods insecure to pods disabled in staging, watch for resolution errors, then roll out; use verified where required.
  4. Restrict clients: add NetworkPolicy for DNS egress, and on standalone servers use bind and acl with an explicit final block.
  5. Secure upstreams: move to tls:// forwarders with tls_servername where the path is untrusted, and use except for internal zones.
  6. Turn on logging: add log . { class denial error }, keep errors, scrape metrics on 9153 and limit that port to monitoring.
  7. Keep the pod locked down: retain the non-root, read-only, capability-dropped security context from the upstream manifest, and apply CoreDNS security releases promptly following the project's security release process.

Testing and rollback: keep the previous ConfigMap in Git. Test each Corefile change in a staging cluster with a canary pod running lookups for services, external names and reverse records. The reload plugin applies changes without restarts, and the loop plugin halts CoreDNS if it detects a forwarding loop, so watch pod health for a few minutes after each change and revert the commit if lookups fail.

Small and large clusters: a single small cluster gets most of the value from steps 2, 3 and 6. Multi-tenant or regulated clusters should add admission policy on the ConfigMap, DNS egress NetworkPolicy in every namespace, dnstap to a central collector and TLS upstreams to a protective resolver.

Framework mapping

Control areaCoreDNS controlNIST SP 800-53 Rev 5NIST CSF 2.0
Resolver integrityVerified TLS upstreams, pod record modeSC-21PR.PS-01
Name service architectureSeparate internal zones, except, NetworkPolicySC-22PR.PS-01
Least privilegeRBAC on ConfigMap and service accountAC-6PR.AA-05
Configuration controlGitOps, admission policy on CorefileCM-6PR.PS-01
Least functionalityDrop chaos, unused pluginsCM-7PR.PS-01
Monitoringlog, errors, metrics, audit logAU-12, AU-6PR.PS-04, DE.CM-01

Common misconfigurations

  • Keeping pods insecure because it shipped that way: the setting exists for backward compatibility. Most clusters can use disabled; test and switch.
  • Broad edit rights in kube-system: a CI service account or operator with namespace-wide edit can rewrite cluster DNS. Scope it to the objects it manages.
  • Assuming the acl plugin is deny by default: its default action is allow. Finish restrictive lists with a block rule, and remember the source IP is the packet source, which may be a NAT address.
  • TLS upstream without a server name: encryption without identity checks. Set tls_servername or per-endpoint SNI.
  • Metrics port open to all namespaces: port 9153 shows query volumes and upstream details. Allow only the monitoring namespace.
  • No DNS egress policy: pods that can reach any resolver bypass CoreDNS logging and filtering. Add NetworkPolicy for port 53.

Practitioner checklist

  • List who can write the coredns ConfigMap, Deployment and kube-dns Service, and reduce it to the platform team and GitOps.
  • Confirm the coredns service account has only list and watch verbs.
  • Replace pods insecure with pods disabled or pods verified after staging tests.
  • Add NetworkPolicy so pods reach port 53 only on CoreDNS.
  • Use tls:// upstreams with tls_servername on untrusted paths, and except for internal zones.
  • Enable log with class denial error and ship logs with namespace metadata.
  • Alert on Corefile changes from the Kubernetes audit log.
  • Restrict port 9153 to monitoring and drop the chaos plugin unless needed.
  • Keep the hardened pod security context and track CoreDNS releases.

Standards and references

Related NHI Mgmt Group resources: Kubernetes Security Guide · Kubernetes RBAC Guide · Kubernetes Audit Log Detection Guide · DNS Logging and Detection Guide · Kubernetes Service Account Token Guide

Free weekly newsletter

Subscribe to the NHI & AI Identity Journal

The latest on NHI and Agentic AI security – articles, research, breaches, news and events every week.

Bonus 33% off our NHI Course when you subscribe.

NHIMG Editorial Note
Researched and written by the NHI Mgmt Group editorial team using AI tools, under the editorial direction of Lalit Choda. Facts are drawn from the sources listed on this page and checked by our automated quality process. Last updated 8 November 2026. Spotted an error? Use our contact page.
NHI Mgmt Group, the independent authority on Non-Human Identity, IAM and Agentic AI security. nhimg.org