BIND Zone Security: Views, ACLs, and Query Restrictions

BIND Zone Security: Views, ACLs, and Query Restrictions

A properly secured DNS server is critical infrastructure. An open resolver can be abused for DNS amplification attacks, leak internal network information, or serve as a reconnaissance tool for attackers. This guide covers BIND's security features: Access Control Lists (ACLs), views for split-horizon DNS, and query restrictions to protect your DNS infrastructure.

Understanding the Threat Model

DNS servers face several security challenges:

  • Open resolver abuse: Attackers use your server to amplify DDoS attacks
  • Information disclosure: Internal hostnames and IP addresses leaked to the internet
  • Cache poisoning: Malicious records injected into resolver caches
  • Zone transfer exposure: Unauthorized parties downloading your entire zone
  • Resource exhaustion: Query floods consuming server resources

BIND provides multiple layers of defense against these threats.

Access Control Lists (ACLs)

ACLs define groups of IP addresses that can be referenced throughout your configuration. Define them once, use them everywhere.

Basic ACL Syntax

acl "trusted" {
    localhost;
    localnets;
    192.168.0.0/16;
    10.0.0.0/8;
};

acl "internal-networks" {
    192.168.1.0/24;
    192.168.2.0/24;
    172.16.0.0/12;
};

acl "secondary-servers" {
    192.168.1.10;
    192.168.1.11;
};

Built-in ACL Keywords

BIND provides several predefined ACLs:

  • any - Matches all hosts
  • none - Matches no hosts
  • localhost - Matches IP addresses of all local interfaces
  • localnets - Matches networks directly connected to local interfaces

Negation in ACLs

Use ! to exclude addresses:

acl "external-only" {
    !10.0.0.0/8;
    !172.16.0.0/12;
    !192.168.0.0/16;
    any;
};

Order matters - BIND evaluates rules top to bottom and uses the first match.

Query Restrictions

Restricting Recursion

The most critical security setting. Never allow recursion for the entire internet:

options {
    directory "/var/named";
    
    // Only allow recursion for trusted networks
    recursion yes;
    allow-recursion { trusted; };
    
    // Alternatively, disable recursion entirely for authoritative-only servers
    // recursion no;
};

Restricting Queries

Limit who can query your server:

options {
    // Global query restriction
    allow-query { any; };  // For authoritative servers
    // allow-query { trusted; };  // For internal resolvers
    
    // Restrict cache access
    allow-query-cache { trusted; };
};

Per-Zone Query Restrictions

Apply different policies to different zones:

zone "public.example.com" {
    type primary;
    file "zones/public.example.com.zone";
    allow-query { any; };
};

zone "internal.example.com" {
    type primary;
    file "zones/internal.example.com.zone";
    allow-query { internal-networks; };
};

Zone Transfer Security

Restricting Zone Transfers

Never allow unrestricted zone transfers:

options {
    // Disable by default
    allow-transfer { none; };
};

zone "example.com" {
    type primary;
    file "zones/example.com.zone";
    // Only allow transfers to secondary servers
    allow-transfer { secondary-servers; };
    also-notify { 192.168.1.10; 192.168.1.11; };
};

TSIG-Authenticated Transfers

For maximum security, require TSIG authentication:

key "transfer-key" {
    algorithm hmac-sha256;
    secret "base64-encoded-secret";
};

zone "example.com" {
    type primary;
    file "zones/example.com.zone";
    allow-transfer { key "transfer-key"; };
};

Views for Split-Horizon DNS

Views allow the same zone to return different answers based on client IP address. This is essential for split-horizon DNS where internal and external clients need different responses.

Basic View Configuration

acl "internal" {
    192.168.0.0/16;
    10.0.0.0/8;
    172.16.0.0/12;
    localhost;
};

acl "external" {
    !192.168.0.0/16;
    !10.0.0.0/8;
    !172.16.0.0/12;
    any;
};

view "internal" {
    match-clients { internal; };
    
    // Internal clients get recursion
    recursion yes;
    
    zone "example.com" {
        type primary;
        file "zones/internal/example.com.zone";
    };
    
    zone "." {
        type hint;
        file "named.ca";
    };
};

view "external" {
    match-clients { external; };
    
    // No recursion for external clients
    recursion no;
    
    zone "example.com" {
        type primary;
        file "zones/external/example.com.zone";
    };
};

Internal Zone File

; zones/internal/example.com.zone
$TTL 86400
@   IN  SOA ns1.example.com. admin.example.com. (
        2024010101  ; Serial
        3600        ; Refresh
        1800        ; Retry
        604800      ; Expire
        86400 )     ; Minimum TTL

    IN  NS  ns1.example.com.
    IN  NS  ns2.example.com.
    IN  A   192.168.1.100      ; Internal IP

ns1     IN  A   192.168.1.10
ns2     IN  A   192.168.1.11
www     IN  A   192.168.1.100  ; Internal web server
mail    IN  A   192.168.1.50   ; Internal mail server
db      IN  A   192.168.1.200  ; Database - internal only
ldap    IN  A   192.168.1.201  ; LDAP - internal only

External Zone File

; zones/external/example.com.zone
$TTL 86400
@   IN  SOA ns1.example.com. admin.example.com. (
        2024010101  ; Serial
        3600        ; Refresh
        1800        ; Retry
        604800      ; Expire
        86400 )     ; Minimum TTL

    IN  NS  ns1.example.com.
    IN  NS  ns2.example.com.
    IN  A   203.0.113.100      ; Public IP
    IN  MX  10 mail.example.com.

ns1     IN  A   203.0.113.10
ns2     IN  A   203.0.113.11
www     IN  A   203.0.113.100  ; Public web server
mail    IN  A   203.0.113.50   ; Public mail server
; No db or ldap records - not accessible externally

View Ordering

Views are evaluated in order. Place more specific views first:

view "admin" {
    match-clients { 192.168.1.5; };  // Admin workstation
    // Full access, debugging enabled
};

view "internal" {
    match-clients { internal; };
    // Standard internal access
};

view "external" {
    match-clients { any; };  // Catch-all
    // Restricted external access
};

Rate Limiting

Protect against DNS amplification and query floods:

options {
    rate-limit {
        responses-per-second 10;
        referrals-per-second 5;
        nodata-per-second 5;
        nxdomains-per-second 5;
        errors-per-second 5;
        all-per-second 20;
        window 15;
        slip 2;
        ipv4-prefix-length 24;
        ipv6-prefix-length 56;
    };
};

Key parameters:

  • responses-per-second - Limit identical responses
  • slip - Send truncated responses (forcing TCP) instead of dropping
  • window - Time window for rate calculation
  • ipv4-prefix-length - Group clients by /24 instead of individual IPs

Response Policy

Minimal Responses

Reduce response size to limit amplification:

options {
    minimal-responses yes;
    minimal-any yes;
};

Disable ANY Queries

ANY queries are often used in amplification attacks:

options {
    minimal-any yes;  // Return minimal response
    // Or block entirely with RPZ
};

Logging Security Events

Configure comprehensive security logging:

logging {
    channel security_log {
        file "/var/log/named/security.log" versions 5 size 10m;
        severity info;
        print-time yes;
        print-severity yes;
        print-category yes;
    };
    
    channel query_log {
        file "/var/log/named/queries.log" versions 5 size 50m;
        severity info;
        print-time yes;
    };
    
    category security { security_log; };
    category queries { query_log; };
    category xfer-in { security_log; };
    category xfer-out { security_log; };
    category notify { security_log; };
};

Complete Secure Configuration Example

Here's a comprehensive configuration combining all security features:

// /etc/named.conf

acl "trusted" {
    localhost;
    localnets;
    192.168.0.0/16;
    10.0.0.0/8;
};

acl "secondary-ns" {
    192.168.1.10;
    192.168.1.11;
};

key "transfer-key" {
    algorithm hmac-sha256;
    secret "your-secret-here";
};

options {
    directory "/var/named";
    pid-file "/run/named/named.pid";
    
    // Listen configuration
    listen-on port 53 { any; };
    listen-on-v6 port 53 { any; };
    
    // Security defaults
    recursion no;           // Disabled by default
    allow-query { any; };   // Allow queries
    allow-transfer { none; };  // Deny transfers by default
    allow-update { none; };    // Deny updates by default
    
    // Version hiding
    version "not disclosed";
    hostname "not disclosed";
    server-id "not disclosed";
    
    // Response minimization
    minimal-responses yes;
    minimal-any yes;
    
    // Rate limiting
    rate-limit {
        responses-per-second 10;
        window 15;
        slip 2;
    };
    
    // DNSSEC validation
    dnssec-validation auto;
};

view "internal" {
    match-clients { trusted; };
    
    recursion yes;
    allow-recursion { trusted; };
    
    zone "example.com" {
        type primary;
        file "zones/internal/example.com.zone";
        allow-transfer { key "transfer-key"; };
    };
    
    zone "." {
        type hint;
        file "named.ca";
    };
};

view "external" {
    match-clients { any; };
    
    recursion no;
    
    zone "example.com" {
        type primary;
        file "zones/external/example.com.zone";
        allow-transfer { key "transfer-key"; };
        allow-query { any; };
    };
};

logging {
    channel default_log {
        file "/var/log/named/named.log" versions 5 size 10m;
        severity info;
        print-time yes;
        print-severity yes;
    };
    
    channel security_log {
        file "/var/log/named/security.log" versions 5 size 10m;
        severity info;
        print-time yes;
    };
    
    category default { default_log; };
    category security { security_log; };
    category xfer-in { security_log; };
    category xfer-out { security_log; };
};

Security Checklist

Before putting your BIND server into production:

  1. Recursion: Disabled or restricted to trusted networks only
  2. Zone transfers: Restricted to secondary servers, preferably with TSIG
  3. Version string: Hidden to prevent fingerprinting
  4. Rate limiting: Enabled to prevent amplification abuse
  5. ACLs: Defined and applied consistently
  6. Views: Configured if split-horizon is needed
  7. Logging: Security events logged for auditing
  8. DNSSEC: Validation enabled for resolvers
  9. Updates: Disabled or restricted with TSIG keys
  10. Firewall: Port 53 restricted appropriately

Conclusion

DNS security requires defense in depth. ACLs provide the foundation, views enable split-horizon deployments, and query restrictions prevent abuse. Combined with rate limiting, minimal responses, and proper logging, these features create a robust security posture for your DNS infrastructure.

The next post will cover dynamic DNS updates with TSIG authentication, allowing secure automated record management.

Read more

HAProxy Monitoring with Prometheus: Complete Observability Guide

HAProxy Monitoring with Prometheus: Complete Observability Guide

Monitoring HAProxy is essential for maintaining reliable load balancing infrastructure. Prometheus provides powerful metrics collection, alerting capabilities, and seamless Grafana integration for visualizing HAProxy performance and health. Why Prometheus for HAProxy? Prometheus offers: * Pull-based metrics - Prometheus scrapes HAProxy metrics endpoints * Time-series database - Store historical data for trend analysis

By Patrick de Ruiter