BIG-IP Next for Kubernetes CNFs - DNS walkthrough

Introduction

F5 enables advanced DNS implementations across different deployments, whether it’s hardware, Virtual Functions and F5 Distributed Cloud. Also, in Kubernetes environment through the F5BigDnsApp Custom Resource Definition (CRD), allowing declarative configuration of DNS listeners, pools, monitors, and profiles directly in-cluster.

Deploying DNS services like Express, Cache, and DoH within the Kubernetes cluster using BIG-IP Next for Kubernetes CNF DNS saves external traffic by resolving queries locally (reducing egress to upstream resolvers by up to 80% with caching) and enhances security through in-cluster isolation, mTLS enforcement, and protocol encryption like DoH, preventing plaintext DNS exposure over cluster boundaries.

This article provides a walkthrough for DNS Express, DNS Cache, and DNS-over-HTTPS (DoH) on top of Red Hat OpenShift. 

Prerequisites

[cloud-user@ocp-provisioner f5-cne-2.1.0]$ kubectl get nodes
NAME                      STATUS   ROLES                         AGE      VERSION
master-1.ocp.f5-udf.com   Ready    control-plane,master,worker   2y221d   v1.29.8+f10c92d
master-2.ocp.f5-udf.com   Ready    control-plane,master,worker   2y221d   v1.29.8+f10c92d
master-3.ocp.f5-udf.com   Ready    control-plane,master,worker   2y221d   v1.29.8+f10c92d
worker-1.ocp.f5-udf.com   Ready    worker                        2y221d   v1.29.8+f10c92d
worker-2.ocp.f5-udf.com   Ready    worker                        2y221d   v1.29.8+f10c92d
[cloud-user@ocp-provisioner f5-cne-2.1.0]$ kubectl get pods -n cne-core
NAME                                          READY   STATUS     RESTARTS       AGE
f5-cert-manager-656b6db84f-dmv78              2/2     Running    10 (15h ago)   19d
f5-cert-manager-cainjector-5cd9454d6c-sc8q2   1/1     Running    21 (15h ago)   19d
f5-cert-manager-webhook-6d87b5797b-954v6      1/1     Running    4              19d
f5-dssm-db-0                                  3/3     Running    13 (18h ago)   15d
f5-dssm-db-1                                  3/3     Running    0              18h
f5-dssm-db-2                                  3/3     Running    4 (18h ago)    42h
f5-dssm-sentinel-0                            3/3     Running    0              14h
f5-dssm-sentinel-1                            3/3     Running    10 (18h ago)   5d8h
f5-dssm-sentinel-2                            3/3     Running    0              18h
f5-rabbit-64c984d4c6-xn2z4                    2/2     Running    8              19d
f5-spk-cwc-77d487f955-j5pp4                   2/2     Running    9              19d
[cloud-user@ocp-provisioner f5-cne-2.1.0]$ kubectl get pods -n cnf-fw-01
NAME                                   READY   STATUS    RESTARTS      AGE
f5-afm-76c7d76fff-5gdhx                2/2     Running   2             42h
f5-downloader-657b7fc749-vxm8l         2/2     Running   0             26h
f5-dwbld-d858c485b-6xfq8               2/2     Running   2             26h
f5-ipsd-79f97fdb9c-zfqxk               2/2     Running   2             26h
f5-tmm-6f799f8f49-lfhnd                5/5     Running   0             18h
f5-zxfrd-d9db549c4-6r4wz               2/2     Running   2 (18h ago)   26h
f5ingress-f5ingress-7bcc94b9c8-zhldm   5/5     Running   6             26h
otel-collector-75cd944bcc-xnwth        1/1     Running   1             42h

 

DNS Express Walkthrough

DNS Express configures BIG-IP to authoritatively answer queries for a zone by pulling it via AXFR/IXFR from an upstream server, with optional TSIG auth keeping zone data in-cluster for low-latency authoritative resolution.

Step 1: Create a F5BigDnsZone CR for zone transfer (e.g., example.com from upstream 10.1.1.12).

# cat 10-cr-dnsxzone.yaml
apiVersion: k8s.f5net.com/v1
kind: F5BigDnsZone
metadata:
  name: example.com
spec:
  dnsxAllowNotifyFrom: ["10.1.1.12"]
  dnsxServer:
    address: "10.1.1.12"
    port: 53
  dnsxEnabled: true
  dnsxNotifyAction: consume
  dnsxVerifyNotifyTsig: false

#kubectl apply -f 10-cr-dnsxzone.yaml -n cnf-fw-01

 

Step 2: Deploy F5BigDnsApp CR with DNS Express enabled

# cat 11-cr-dnsx-app-udp.yaml
apiVersion: "k8s.f5net.com/v1"
kind: F5BigDnsApp
metadata:
  name: "dnsx-app-listener"
  namespace: "cnf-fw-01"
spec:
  destination:
   address: "10.1.30.100"
   port: 53
  ipProtocol: "udp"
  snat:
   type: "automap"
  dns:
   dnsExpressEnabled: true
  logProfile: "cnf-log-profile"

# kubectl apply -f 11-cr-dnsx-app-udp.yaml -n cnf-fw-01

Step 3: Validate: Query from our client pod & tmm statistics 

dig @10.1.30.100 www.example.com

; <<>> DiG 9.18.30-0ubuntu0.20.04.2-Ubuntu <<>> @10.1.30.100 www.example.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 43865
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 2
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;www.example.com.               IN      A

;; ANSWER SECTION:
www.example.com.        604800  IN      A       192.168.1.11

;; AUTHORITY SECTION:
example.com.            604800  IN      NS      ns.example.com.

;; ADDITIONAL SECTION:
ns.example.com.         604800  IN      A       192.168.1.10

;; Query time: 0 msec
;; SERVER: 10.1.30.100#53(10.1.30.100) (UDP)
;; WHEN: Thu Jan 22 11:10:24 UTC 2026
;; MSG SIZE  rcvd: 93


kubectl exec -it deploy/f5-tmm -c debug -n cnf-fw-01  -- bash
/tmctl -id blade tmmdns_zone_stat name=example.com
name        dnsx_queries dnsx_responses dnsx_xfr_msgs dnsx_notifies_recv
----------- ------------ -------------- ------------- ------------------
example.com            2              2             0                  0

 

DNS Cache Walkthrough

DNS Cache reduces latency by storing responses non-authoritatively, referenced via a separate cache CR in the DNS profile, cutting repeated upstream queries and external bandwidth use.

Step 1: Create a DNS Cache CR F5BigDnsCache

# cat 13-cr-dnscache.yaml
apiVersion: "k8s.f5net.com/v1"
kind: F5BigDnsCache
metadata:
  name: "cnf-dnscache"
spec:
  cacheType: resolver
  resolver:
    useIpv4: true
    useTcp: false
    useIpv6: false
    forwardZones:
      - forwardZone: "example.com"
        nameServers:
          - ipAddress: 10.1.1.12
            port: 53
      - forwardZone: "."
        nameServers:
          - ipAddress: 8.8.8.8
            port: 53
# kubectl apply -f 13-cr-dnscache.yaml -n cnf-fw-01

 

Step 2: Deploy F5BigDnsApp CR with DNS Cache enabled

# cat 11-cr-dnsx-app-udp.yaml
apiVersion: "k8s.f5net.com/v1"
kind: F5BigDnsApp
metadata:
  name: "dnsx-app-listener"
  namespace: "cnf-fw-01"
spec:
  destination:
   address: "10.1.30.100"
   port: 53
  ipProtocol: "udp"
  snat:
   type: "automap"
  dns:
   dnsCache: "cnf-dnscache"
  logProfile: "cnf-log-profile"

# kubectl apply -f 11-cr-dnsx-app-udp.yaml -n cnf-fw-01 

Step 3: Validate: Query from our client pod 

dig @10.1.30.100 www.example.com

; <<>> DiG 9.18.30-0ubuntu0.20.04.2-Ubuntu <<>> @10.1.30.100 www.example.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 18302
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;www.example.com.               IN      A

;; ANSWER SECTION:
www.example.com.        19076   IN      A       192.168.1.11

;; Query time: 4 msec
;; SERVER: 10.1.30.100#53(10.1.30.100) (UDP)
;; WHEN: Thu Jan 22 11:04:45 UTC 2026
;; MSG SIZE  rcvd: 60

 

DoH Walkthrough

DoH exposes DNS over HTTPS (port 443) for encrypted queries, using BIG-IP's protocol inspection and UDP profiles, securing in-cluster DNS from eavesdropping and MITM attacks.

Step 1: Ensure TLS secret exists and HTTP profiles exist 

# cat 14-tls-clientsslsettings.yaml
apiVersion: k8s.f5net.com/v1
kind: F5BigClientsslSetting
metadata:
  name: "cnf-clientssl-profile"
  namespace: "cnf-fw-01"
spec:
  enableTls13: true
  enableRenegotiation: false
  renegotiationMode: "require"

#  cat 15-http-profiles.yaml
apiVersion: "k8s.f5net.com/v1"
kind: F5BigHttp2Setting
metadata:
  name: http2-profile
spec:
  activationModes: "alpn"
  concurrentStreamsPerConnection: 10
  connectionIdleTimeout: 300
  frameSize: 2048
  insertHeader: false
  insertHeaderName: "X-HTTP2"
  receiveWindow: 32
  writeSize: 16384
  headerTableSize: 4096
  enforceTlsRequirements: true
---
apiVersion: "k8s.f5net.com/v1"
kind: F5BigHttpSetting
metadata:
  name: http-profile
spec:
  oneConnect: false
  responseChunking: "sustain"
  lwsMaxColumn: 80


# kubectl apply -f 14-tls-clientsslsettings.yaml -n cnf-fw-01
# kubectl apply -f 15-http-profiles.yaml -n cnf-fw-01

Step 2: Create DNSApp for DoH service 

# cat 16-DNSApp-doh.yaml
apiVersion: "k8s.f5net.com/v1"
kind: F5BigDnsApp
metadata:
  name: "cnf-dohapp"
  namespace: "cnf-fw-01"
spec:
  ipProtocol: "udp"
  dohProtocol: "udp"
  destination:
   address: "10.1.20.100"
   port: 443
  snat:
   type: "automap"
  dns:
    dnsExpressEnabled: false
    dnsCache: "cnf-dnscache"
  clientSslSettings: "clientssl-profile"
  pool:
    members:
      - address: "10.1.10.50"
  monitors:
    dns:
      enabled: true
      queryName: "www.example.com"
      queryType: "a"
      recv: "192.168.1.11"

# kubectl apply -f 16-DNSApp-doh.yaml -n cnf-fw-01

Step 3: Testing from our client pod 

ubuntu@client:~$ dig @10.1.20.100 -p 443  +https +notls-ca www.google.com

; <<>> DiG 9.18.30-0ubuntu0.20.04.2-Ubuntu <<>> @10.1.20.100 -p 443 +https +notls-ca www.google.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 4935
;; flags: qr rd ra; QUERY: 1, ANSWER: 6, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;www.google.com.                        IN      A

;; ANSWER SECTION:
www.google.com.         69      IN      A       142.251.188.103
www.google.com.         69      IN      A       142.251.188.147
www.google.com.         69      IN      A       142.251.188.106
www.google.com.         69      IN      A       142.251.188.105
www.google.com.         69      IN      A       142.251.188.99
www.google.com.         69      IN      A       142.251.188.104

;; Query time: 8 msec
;; SERVER: 10.1.20.100#443(10.1.20.100) (HTTPS)
;; WHEN: Thu Jan 22 11:27:05 UTC 2026
;; MSG SIZE  rcvd: 139

ubuntu@client:~$ dig @10.1.20.100 -p 443  +https +notls-ca www.example.com

; <<>> DiG 9.18.30-0ubuntu0.20.04.2-Ubuntu <<>> @10.1.20.100 -p 443 +https +notls-ca www.example.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 20401
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;www.example.com.               IN      A

;; ANSWER SECTION:
www.example.com.        17723   IN      A       192.168.1.11

;; Query time: 4 msec
;; SERVER: 10.1.20.100#443(10.1.20.100) (HTTPS)
;; WHEN: Thu Jan 22 11:27:18 UTC 2026
;; MSG SIZE  rcvd: 60

Conclusion

BIG-IP Next DNS CRs transform Kubernetes into a production-grade DNS platform, delivering authoritative resolution, caching efficiency, and encrypted DoH, all while optimizing external traffic costs and hardening security boundaries for cloud-native deployments.

 

Related Content

Published Jan 26, 2026
Version 1.0
No CommentsBe the first to comment