Learn Calico - DNS & FQDN Policy
Series/Learn Calico/Episode 11
Episode 11 of 23

Learn Calico - DNS & FQDN Policy

This episode covers DNS and FQDN policy: domain-based egress control for external service integration, combining DNS and IP policies in application policies, and the common pitfalls when using domains.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Introduction

Writing IP-based egress policies for applications that call cloud services is a pain: the IPs change, and you have to keep updating the policy. Episode 11 introduces the solution: FQDN policy — policies that write domains instead of IPs, with Calico translating them into IP rules on the dataplane.

FQDN policy is an ingredient used in almost every production environment, because almost no application talks only to static IPs. In this episode you'll learn to write domain policies, combine them with IP rules, and avoid the DNS pitfalls that make applications time out.

FQDN Policy

The Domain Selector Concept

Domain-based policies are written with the domainSelector field on egress rules. Calico watches the DNS queries made by workloads, then builds IP rules from the resolution results. That's why this policy works best for stable FQDNs.

FQDN-based egress
apiVersion: projectcalico.org/v3
kind: NetworkPolicy
metadata:
  name: api-egress-external
  namespace: payments
spec:
  selector: app == 'api'
  types:
    - Egress
  egress:
    - action: Allow
      protocol: TCP
      destination:
        domainSelector: 'api.external.example.com'
        ports:
          - 443

The domainSelector above allows outbound traffic only to api.external.example.com. Wildcards with * are also supported, for example '*.example.com' for all subdomains.

How It Works Behind the Scenes

When a pod resolves the name api.external.example.com via CoreDNS, Calico captures the result, adds that IP to the set of allowed destinations, then programs the rule on the node:

FQDN policy resolution flow
pod queries DNS -> CoreDNS -> Calico captures the answer
      -> IP rule added to the dataplane -> egress allowed

Because rules are built from query results, make sure the workload actually performs DNS resolution inside the cluster — not a hardcoded IP in the application. If the IP is hardcoded, Calico never learns the domain name.

Combining DNS and IP Policies

One Policy, Two Kinds of Destinations

Applications often need two kinds of outbound access at once: to a static IP (for example, an internal database) and to a domain (for example, an external API). Both can be written in one policy:

Combining IP and FQDN
apiVersion: projectcalico.org/v3
kind: NetworkPolicy
metadata:
  name: api-egress-mix
  namespace: payments
spec:
  selector: app == 'api'
  types:
    - Egress
  egress:
    - action: Allow
      protocol: TCP
      destination:
        nets:
          - 198.51.100.0/24
        ports:
          - 5432
    - action: Allow
      protocol: TCP
      destination:
        domainSelector: '*.payments.example.com'
        ports:
          - 443

The first rule uses nets for the static IP, the second uses domainSelector for the domain. Calico combines them without conflict.

DNS Must Be Allowed First

An egress rule to a domain is only useful if the DNS query itself can be resolved. So make sure there's an allow rule to CoreDNS. The most common pattern:

Allow DNS to CoreDNS
egress:
  - action: Allow
    protocol: UDP
    destination:
      namespaceSelector: k8s-app == 'kube-dns'
      selector: k8s-app == 'kube-dns'
      ports:
        - 53

Without this rule, resolution fails, and an FQDN policy never gets a destination IP.

Common DNS Pitfalls

TTL and Caching

The destination IP can change after the TTL expires. Calico holds the resolution result according to the TTL; if the application keeps using the old IP, connections can fail. The fix isn't to raise the TTL arbitrarily, but to make sure the application re-resolves as usual.

Certificates and SNI

Note that FQDN policy works at the IP/port level — it does not inspect SNI or the host header. Two domains that resolve to the same IP will be subject to the same rule. For L7 control that sees the actual domain name, you need Application Layer Policy — the material of episode 12.

Trailing Dots in Names

Make sure domains don't have a trailing dot (api.example.com. vs api.example.com). This small difference often makes a policy never match.

Applying and Verifying in Practice

Complete Workflow

Start by making sure DNS works, then add the FQDN policy, then verify:

Apply and verify FQDN policy
calicoctl apply -f allow-dns.yaml
calicoctl apply -f api-egress-external.yaml
kubectl exec -n payments deploy/api -- nslookup api.external.example.com
kubectl exec -n payments deploy/api -- curl -sS https://api.external.example.com

kubectl exec ... nslookup confirms resolution succeeds inside the cluster, and curl -sS tests real access to the domain.

Viewing FQDN Rules in the Dataplane

To make sure the domain IPs have entered the dataplane:

Check FQDN rules on a node
kubectl exec -n calico-system ds/calico-node -- iptables -L cali-FWR-IN-3 -n
calicoctl get networkpolicy -n payments -o yaml | grep -A3 domainSelector

Conclusion

Episode 11 equips you with domain-based egress: writing domainSelector, combining DNS and IP rules, and avoiding the TTL, SNI, and name-format pitfalls that silently make policies fail.

Key takeaways:

  • domainSelector enables FQDN-based egress; the * wildcard is supported.
  • Calico captures DNS resolution results to build IP rules.
  • DNS rules (port 53 to CoreDNS) are mandatory before FQDN policy.
  • Combine nets and domainSelector in one policy as needed.
  • FQDN policy works at the IP/port level, not SNI — for L7 wait for episode 12.
  • Avoid trailing dots in domain names and hardcoded IPs in applications.

In the next episode, episode 12, we cover service mesh and app layer — ApplicationLayerPolicy with the Envoy integration, L7 visibility, HTTP action detection, and Calico's position in service mesh traffic.

Learn Calico - DNS & FQDN Policy | Learn Calico