F5 Cloud-Native Functions For Secure DNS
This is an addition to a series of articles that introduce new features implemented in F5's BIG-IP Next Cloud-Native Functions.
Why Security Matters
Securing your Kubernetes workloads is difficult due to the numerous risk factors involved with deploying and exposing your apps. While CNCF discusses some best practices we can follow, other entry points into your network infrastructure such as DNS requires much more specialized hardening.
How F5 can help
As mentioned in a previous article, F5 CNFs can extend Kubernetes with more capabilities and even provide protection for your cloud-native DNS infrastructure by enabling DDoS and Intrusion Prevention System (IPS) capabilities. These features can be turned on at the same layer as your DNS cache, traffic optimization and NAT functions so you can increase performance without sacrificing security.
Technical Overview
The two features you can use to achieve this are the DDoS and IPS Policies that give you many parameters for protecting DNS traffic. These are custom resource definitions (CRDs) deployed using the Kubernetes API. This means there is native integration with K8s and also the ability to seamlessly plug into your automation or CI/CD toolset of choice.
The below policies will protect against external attacks involving malformed DNS packets that do not comply with RFC standards or that match against known attack signatures. We have enabled default mitigation for those vectors that have no place in your network, which implements best practices and simplifies configuration.
Notice that below examples are showing default thresholds but actual values will depend on things like capacity of the backend systems, transport links, and baseline traffic volume. The values represent thresholds per TMM pod.
DDoS Policy CR
Below is an example DDoS policy that can be referenced and enabled in your DNS listener custom resource.
apiVersion: "k8s.f5net.com/v1"
kind: F5BigDdosPolicy
metadata:
name: dns-ddos-01
spec:
hslPublisher: "publisher1"
vectors:
floodVectors:
commonConfigVectors:
- vectorType: ip-frag-flood
state: detection-only
- vectorType: icmpv4-flood
state: detection-only
perSourceIpDetectionEps: 1000
perSourceIpLimitEps: 10000
- vectorType: tcp-psh-flood
state: detection-only
perSourceIpDetectionEps: 100000
perSourceIpLimitEps: 100000
- vectorType: tcp-rst-flood
state: detection-only
perSourceIpDetectionEps: 100000
perSourceIpLimitEps: 100000
- vectorType: udp-flood
state: detection-only
perSourceIpDetectionEps: 40000
perSourceIpLimitEps: 100000
dnsFloodVectors:
commonConfigVectors:
- vectorType: dns-a-query
state: mitigation
detectionThresholdEps: 1
rateLimit: 50000
detectionThresholdEps: 1250
rateLimit: 2500
- vectorType: dns-aaaa-query
state: mitigation
detectionThresholdEps: 1250
rateLimit: 2500
- vectorType: dns-any-query
state: mitigation
detectionThresholdEps: 100
rateLimit: 200
- vectorType: dns-axfr-query
state: mitigation
detectionThresholdEps: 50
rateLimit: 100
- vectorType: dns-cname-query
state: mitigation
detectionThresholdEps: 100
rateLimit: 200
- vectorType: dns-ixfr-query
state: mitigation
detectionThresholdEps: 50
rateLimit: 100
- vectorType: dns-mx-query
state: mitigation
detectionThresholdEps: 50
rateLimit: 100
- vectorType: dns-ns-query
state: mitigation
detectionThresholdEps: 100
rateLimit: 200
- vectorType: dns-other-query
state: mitigation
detectionThresholdEps: 50
rateLimit: 100
- vectorType: dns-ptr-query
state: mitigation
detectionThresholdEps: 400
rateLimit: 800
- vectorType: dns-soa-query
state: mitigation
detectionThresholdEps: 50
rateLimit: 100
- vectorType: dns-srv-query
state: mitigation
detectionThresholdEps: 400
rateLimit: 800
- vectorType: dns-txt-query
state: mitigation
detectionThresholdEps: 400
rateLimit: 800
specificConfigVectors:
dnsNxdomainQuery:
state: mitigation
detectionThresholdEps: 400
rateLimit: 800
ipV6FloodVectors:
commonConfigVectors:
- vectorType: ipv6-frag-flood
state: detection-only
- vectorType: icmpv6-flood
state: detection-only
perSourceIpDetectionEps: 1000
perSourceIpLimitEps: 10000
specificConfigVectors:
extHdrTooLarge:
state: detection-only
perSourceIpDetectionEps: 100
perSourceIpLimitEps: 1000
lowHopCnt:
state: detection-only
tooManyExtHdrs:
state: detection-only
withExtHdrFrames:
state: detection-only
perSourceIpDetectionEps: 1000
perSourceIpLimitEps: 10000
dnsErrorVectors:
commonConfigVectors:
- vectorType: dns-malformed
detectionThresholdEps: 40
- vectorType: dns-qdcount-limit
detectionThresholdEps: 40
When this policy is applied to a listener that is processing DNS traffic, you will be protected from attacks that trigger these vectors.
To test, we can use a tool called scapy to craft malicious packets.
send(IP(dst="100.100.200.150")/UDP(dport=53)/DNS(id=50713,rd=1,opcode=-1,qdcount=1,ancount=0,qd=DNSQR(qname="fake1.terry.f5.com",qclass="IN",qtype="A")),count=5000,inter=0.0001)
You'll be able to see that this malformed DNS packet gets detected and dropped because we mitigate against these attacks by default.
IPS Policy CR
Below is an example IPS policy that can be used to ensure your DNS traffic is in compliance with standards and policies that define good and bad queries. Other listener types (context secure) also support referencing this type of policy:
apiVersion: "k8s.f5net.com/v1"
kind: F5BigIpsPolicy
metadata:
name: "dns-ips-01"
spec:
services:
- name: dns
ports:
- "53"
compliances:
- name: dns_disallowed_query_type
value: "IQUERY"
action: reject
- name: dns_disallowed_resource_records
value: "A6 DLV GID MAILA MAILB MB MD MF MG MR NULL NXT SINK TALINK UID UINFO UNSPEC ISDN ATMA X25"
action: reject
- name: dns_domains_blacklist
value: "fake1.terry.f5.com"
action: reject
- name: dns_experimental_resource_records
value: "AFSDB APL ISDN LOC MB MG MINFO MR NULL RP RT X25"
action: reject
- name: dns_malformed_pdu
action: reject
- name: dns_maximum_reply_length
value: "4096"
action: reject
- name: dns_maximum_request_length
value: "520"
action: reject
- name: dns_obsolete_resource_records
value: "KEY MAILA MD MF"
action: reject
- name: dns_unknown_resource_record_type
logging: disabled
signatures:
- name: dns_blacklist_dns_reverse_lookup_response_for_known_malware_domain_spheral_ru_win_trojan_glupteba
action: reject
- name: dns_dns_query_amplification_attempt
action: drop
- name: dns_malformed_dns_query_with_http_content
action: drop
- name: dns_named_authors_attempt
action: drop
- name: dns_named_authors_attempt_1
action: drop
- name: dns_named_version_attempt
action: drop
- name: dns_named_version_attempt_1
action: drop
- name: dns_os_linux_os_linux_x86_linux_overflow_attempt
action: drop
- name: dns_os_linux_os_linux_x86_linux_overflow_attempt_1
action: drop
- name: dns_os_linux_os_linux_x86_linux_overflow_attempt_admv2
action: drop
- name: dns_os_other_os_other_x86_freebsd_overflow_attempt
action: drop
- name: dns_os_solaris_exploit_sparc_overflow_attempt
action: drop
- name: dns_server_other_bind_buffer_overflow_named_tsig_overflow_attempt
action: drop
- name: dns_server_other_bind_buffer_overflow_named_tsig_overflow_attempt_1
action: drop
- name: dns_server_other_bind_buffer_overflow_via_nxt_records
action: drop
- name: dns_server_other_bind_buffer_overflow_via_nxt_records_named_overflow_adm
action: drop
- name: dns_server_other_bind_buffer_overflow_via_nxt_records_named_overflow_admrocks
action: drop
- name: dns_server_other_bind_named_overflow_attempt
action: drop
- name: dns_spoof_query_response_ptr_with_ttl_of_1_min_and_no_authority
action: drop
- name: dns_spoof_query_response_with_ttl_of_1_min_and_no_authority
action: drop
- name: dns_tcp_inverse_query
action: drop
To test a non-compliant scenario, below scapy script can be run to send over a packet with an opcode of 1, signifying IQUERY or a method of performing inverse DNS lookups.
send(IP(dst="100.100.200.150")/UDP(dport=53)/DNS(id=RandShort(), opcode=1, rd=1, qdcount=1, ancount=0, nscount=0, arcount=0,qd=DNSQR(qname="fake1.terry.f5.com", qtype=1, qclass="IN")))
The packet will be detected and you should see the protocol inspections stats and logs like below:
IPS: on_flags/264: Found '10010' match (file '/builds/d3347dec/0/dpi/ips-lib/src/ips_service_dns.cpp:264')
IPS: ips_insp_callback/807: COMPL CHECK MATCH: id=10010, ctx='IQUERY', action=REJECT, support_id = 0000ff520000271a
These are just a couple of simple examples showing how easy it is to enable security for your DNS infrastructure using the same engine that powers this protection in all F5 hardware and software.
Didn't know such interation was possible, I must have missed your previous post 🙂
Thanks for sharing! This will very likely turn useful soon- shsinghEmployee
Nice one Terence_Kam !
In BIG-IP, there is the ability to have a "DNS Security" profile attached to a DNS profile on the Virtual Server. ref: https://my.f5.com/manage/s/article/K18522641 and https://techdocs.f5.com/en-us/bigip-15-1-0/big-ip-network-firewall-policies-and-implementations/afm-protocol-security/dns-protocol-security/about-dns-protocol-filtering/filtering-dns-traffic-with-a-dns-security-profile.html
I couldn't find a reference for it in the F5BigDnsCache reference documents - is this why you are using the IPS profile instead?
The reason for asking being typically in BIG-IP the protocol profile (like DNS) can have a lot of the protocol validation and security done as part of parsing the packet for further processing, and IPS are typically used for more "bump-in-the-wire" pass-through traffic BIG-IP (such as AFM in forwarding mode).
- Terence_KamEmployee
shsingh Thanks for your comment. Yes, you're right, the IPS profile is being soft referenced because that is being decoupled into its own CRD. Some benefits include being able to enhance or fix these components independently so the delivery of new code can happen much quicker. It also provides logical separation . You'll find this to be true for other functionality like FW ACLs, NAT Policies, High Speed Logging profile, etc. when looking at another type of listener called F5BigContextSecure where you'd have the forwarding type listeners. This listener also can reference a protocolInspectionProfile name.