Triển khai DoH và DoT với CoreDNS trên Linux: Bảo mật truy vấn DNS nội bộ chống nghe lén

Networking tutorial - IT technology blog
Networking tutorial - IT technology blog

Bắt đầu nhanh: Khởi tạo CoreDNS mã hóa trong 5 phút

DNS dạng văn bản thuần (plaintext) trên cổng 53 truyền tải mọi truy vấn hoàn toàn không mã hóa. Bất kỳ ai có quyền truy cập vào mạng nội bộ—hoặc một container bị xâm nhập trong VPC—đều có thể nghe lén các truy vấn hoặc chèn bản ghi giả mạo. Việc mã hóa lưu lượng DNS nội bộ sẽ loại bỏ hoàn toàn lỗ hổng này. CoreDNS hỗ trợ sẵn cả DNS over TLS (DoT) lẫn DNS over HTTPS (DoH) mà không cần thêm bất kỳ dependency bên ngoài nào.

Dưới đây là quy trình triển khai đã được kiểm chứng thực tế giúp bạn thiết lập một resolver mã hóa chạy trên Ubuntu 22.04 hoặc Debian 12 chỉ trong vài phút.

1. Tải về và cài đặt CoreDNS

# Tải bản binary Linux amd64 (v1.11.3)
curl -LO https://github.com/coredns/coredns/releases/download/v1.11.3/coredns_1.11.3_linux_amd64.tgz
tar -zxvf coredns_1.11.3_linux_amd64.tgz
sudo mv coredns /usr/local/bin/
sudo chmod +x /usr/local/bin/coredns

# Tạo thư mục chứa cấu hình và chứng chỉ
sudo mkdir -p /etc/coredns /etc/coredns/certs

2. Khởi tạo chứng chỉ TLS cục bộ

Đối với hạ tầng nội bộ, hãy tạo private key RSA và chứng chỉ tự ký (hoặc ký bằng CA nội bộ của tổ chức):

sudo openssl req -x509 -newkey rsa:4096 -nodes \
  -keyout /etc/coredns/certs/dns.key \
  -out /etc/coredns/certs/dns.crt \
  -days 365 -subj "/CN=dns.internal.lan"

3. Cấu hình Corefile

Tạo file /etc/coredns/Corefile để lắng nghe DoT (cổng 853) và DoH (cổng 443), đồng thời chuyển tiếp các truy vấn chưa phân giải tới resolver bảo mật upstream:

# DNS qua TLS (DoT)
tls://.:853 {
    tls /etc/coredns/certs/dns.crt /etc/coredns/certs/dns.key
    forward . 1.1.1.1 8.8.8.8
    cache 300
    errors
    log
}

# DNS qua HTTPS (DoH)
https://.:443 {
    tls /etc/coredns/certs/dns.crt /etc/coredns/certs/dns.key
    forward . 1.1.1.1 8.8.8.8
    cache 300
    errors
    log
}

4. Chạy và kiểm thử máy chủ

# Khởi chạy CoreDNS trực tiếp trên terminal
sudo /usr/local/bin/coredns -conf /etc/coredns/Corefile

Mở một terminal thứ hai và kiểm tra cổng lắng nghe DoT bằng kdig (thuộc gói knot-dnsutils):

kdig @127.0.0.1 -p 853 +tls +tls-ca=/etc/coredns/certs/dns.crt example.com

Phân tích kiến trúc: DoT so với DoH trong môi trường Production

Việc lựa chọn giữa DoT và DoH phụ thuộc hoàn toàn vào vị trí của client và quyền kiểm soát tường lửa mạng.

DoT (RFC 7858) và DoH (RFC 8484)

  • DoT (DNS over TLS) đóng gói trực tiếp định dạng nhị phân chuẩn của DNS vào phiên TLS qua cổng TCP 853. Giao thức này tạo ra rất ít overhead—thường dưới 1KB cho mỗi phiên bắt tay TLS. DoT cực kỳ phù hợp cho lưu lượng giữa các máy chủ (server-to-server), resolver tại node trong Kubernetes và VPN site-to-site. Đội ngũ bảo mật cũng đánh giá cao việc cổng 853 rất dễ giám sát và lọc tại tường lửa biên.
  • DoH (DNS over HTTPS) đóng gói các truy vấn DNS bên trong luồng HTTP/2 hoặc HTTP/3 trên cổng TCP 443. Nó hòa lẫn hoàn toàn vào lưu lượng HTTPS tiêu chuẩn. Điều này khiến DoH trở thành lựa chọn lý tưởng cho laptop của developer thường xuyên di chuyển, các văn phòng chi nhánh và mạng nằm sau proxy bị hạn chế. Đổi lại, DoH tốn thêm một lượng tài nguyên bộ nhớ (~15-20% cao hơn DoT) cùng chi phí xử lý framing của HTTP.

Cách CoreDNS xử lý các truy vấn mã hóa

CoreDNS thực thi các plugin theo thứ tự tuần tự cho mỗi gói tin nhận được:

  1. TLS Termination: CoreDNS xử lý quá trình bắt tay bảo mật bằng chứng chỉ đã được cấu hình.
  2. Phân giải Zone: Các plugin cục bộ như hosts hoặc file sẽ kiểm tra và phân giải các bản ghi tĩnh trước tiên.
  3. In-Memory Cache: Plugin cache chặn các truy vấn lặp lại, trả về kết quả cache hit chỉ dưới 1ms.
  4. Forwarding Upstream: Khi cache miss, truy vấn được chuyển tới plugin forward để chuyển tiếp đến resolver bên ngoài qua các kênh mã hóa.

Trong một cụm chạy 120 bản sao microservice, một instance CoreDNS duy nhất ở trạng thái nhàn rỗi chỉ chiếm 45MB RAM có thể dễ dàng phục vụ 18.000 truy vấn mỗi giây, duy trì độ trễ dưới 3ms cho các bản ghi đã được cache.

Thiết lập Production: Củng cố bảo mật với Systemd Service và Upstream mã hóa

Chạy trực tiếp binary từ terminal chỉ phù hợp khi kiểm thử. Môi trường production đòi hỏi tiến trình phải được cô lập, tự động khởi động lại và mã hóa toàn bộ chặng upstream.

1. Bảo mật truy vấn Upstream với DoT Forwarding

Tuyệt đối không chuyển tiếp truy vấn dạng cleartext tới ISP hoặc resolver upstream. Hãy định tuyến lưu lượng upstream qua DoT với xác thực SNI hostname nghiêm ngặt:

# /etc/coredns/Corefile
tls://.:853 https://.:443 {
    tls /etc/coredns/certs/dns.crt /etc/coredns/certs/dns.key

    # Bản ghi split-horizon cục bộ
    hosts {
        10.10.0.15 db-primary.internal.lan
        10.10.0.16 db-replica.internal.lan
        fallthrough
    }

    # Chuyển tiếp DoT upstream với xác thực hostname qua TLS
    forward . tls://1.1.1.1 tls://1.0.0.1 {
        tls_servername cloudflare-dns.com
        health_check 5s
    }

    cache 3600 {
        success 4096
        denial 1024
    }
    prometheus :9153
    errors
    log
}

2. Cấu hình Systemd Service không dùng quyền Root

Tạo một user hệ thống riêng biệt. Sử dụng Linux capabilities để cho phép binary bind vào cổng 443 và 853 mà không cần cấp quyền root:

sudo useradd -r -d /var/lib/coredns -s /usr/sbin/nologin coredns
sudo chown -R coredns:coredns /etc/coredns
sudo setcap 'cap_net_bind_service=+ep' /usr/local/bin/coredns

Tạo file unit cho systemd service tại /etc/systemd/system/coredns.service:

[Unit]
Description=Máy chủ DNS mã hóa CoreDNS
Documentation=https://coredns.io/manual/toc/
After=network.target

[Service]
Type=simple
User=coredns
Group=coredns
ExecStart=/usr/local/bin/coredns -conf /etc/coredns/Corefile
Restart=on-failure
RestartSec=5s
LimitNOFILE=65536
AmbientCapabilities=CAP_NET_BIND_SERVICE
CapabilityBoundingSet=CAP_NET_BIND_SERVICE

[Install]
WantedBy=multi-user.target

Tải lại cấu hình systemd và kích hoạt daemon:

sudo systemctl daemon-reload
sudo systemctl enable --now coredns
sudo systemctl status coredns

Kiểm thử và khắc phục sự cố

Kiểm tra truy vấn DoH bằng Curl

Gửi truy vấn trực tiếp đến endpoint DoH bằng curl với truy vấn DNS nhị phân đã được mã hóa base64url:

curl -k -H "accept: application/dns-message" \
  --resolve dns.internal.lan:443:127.0.0.1 \
  "https://dns.internal.lan/dns-query?dns=AAABAAABAAAAAAAAA3d3dwdleGFtcGxlA2NvbQAAAQAB" \
  --output - | xxd

Các vấn đề thường gặp

  • Xung đột lắng nghe trên cổng 53: Ubuntu chạy sẵn systemd-resolved tại 127.0.0.53:53. Nếu bạn muốn CoreDNS xử lý cả các truy vấn fallback không mã hóa trên cổng 53, hãy tắt stub listener. Đặt DNSStubListener=no trong /etc/systemd/resolved.conf, tạo symlink trỏ /etc/resolv.conf tới /run/systemd/resolve/resolv.conf, sau đó khởi động lại systemd-resolved.
  • Tự động gia hạn chứng chỉ: CoreDNS tự động theo dõi các file chứng chỉ và reload lại ngay khi có thay đổi. Nếu bạn thiết lập gia hạn tự động bằng Certbot hoặc Vault, chỉ cần trỏ directive tls tới các symlink tương ứng mà không cần khởi động lại service.
  • Trust Store trên máy Client: Các máy client phải tin cậy root CA của bạn thì mới có thể gửi truy vấn tới endpoint DoH/DoT mà không gặp lỗi. Hãy sao chép root CA vào /usr/local/share/ca-certificates/internal-ca.crt và chạy lệnh sudo update-ca-certificates trên từng client Linux.
Share: