Cấu hình DNSSEC trên BIND9: Hướng dẫn ký zone tự động và quản lý key

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

Vấn đề thực tế: Mối đe dọa thầm lặng từ DNS Cache Poisoning

Trong một đợt chuyển đổi hệ thống mà tôi phụ trách cho một nền tảng thương mại điện tử với 45.000 người dùng hoạt động mỗi ngày, bộ phận hỗ trợ khách hàng bất ngờ nhận được hàng loạt thông báo lỗi sai lệch SSL (SSL mismatch) từ người dùng tại khu vực Đông Nam Á. Các máy chủ gốc (origin server) vẫn hoạt động với mức tải CPU bình thường, access log hoàn toàn sạch sẽ và chứng chỉ Wildcard TLS vẫn còn hiệu lực.

Kẻ tấn công không hề xâm nhập vào các cloud instance của chúng tôi. Thay vào đó, chúng đã đầu độc bộ nhớ cache của các recursive caching resolver tại hai ISP trung chuyển (transit ISP) cấp 2 trong khu vực, thay thế bản ghi A của chúng tôi bằng một địa chỉ IP trỏ tới trang web giả mạo nhằm thu thập thông tin đăng nhập.

DNS tiêu chuẩn hoạt động qua giao thức UDP dạng văn bản thuần (cleartext) mà không có cơ chế xác thực. Khi một recursive resolver yêu cầu phân giải một địa chỉ IP, nó sẽ chấp nhận bất kỳ gói tin nào phản hồi đầu tiên có transaction ID 16-bit và cổng UDP trùng khớp. Kẻ tấn công liên tục gửi dồn dập (flood) các phản hồi giả mạo tới resolver trong lúc quá trình tra cứu đang diễn ra hoàn toàn có thể giành chiến thắng trong cuộc đua đó. Khi đã được chèn vào, câu trả lời giả mạo sẽ nằm lại trong bộ nhớ cache cho đến khi TTL hết hạn—thường là 86.400 giây. Trong suốt 24 giờ đó, người dùng tại khu vực bị ảnh hưởng sẽ truy cập vào trang web lừa đảo mà không hề kích hoạt bất kỳ cảnh báo nào từ hệ thống hạ tầng.

Phân tích nguyên nhân gốc rễ: Vì sao DNS truyền thống thất bại trong việc đảm bảo tính toàn vẹn

DNS được thiết kế vào năm 1983 với mục tiêu ưu tiên tốc độ và giảm thiểu độ trễ giao thức (protocol overhead). Yếu tố bảo mật hoàn toàn không nằm trong bản thiết kế ban đầu. Qua nhiều năm, các kỹ sư mạng đã áp dụng nhiều giải pháp chắp vá mang tính xác suất như ngẫu nhiên hóa cổng nguồn UDP (UDP source-port randomization) để giảm thiểu các cuộc tấn công inject mù kiểu Kaminsky. Tuy nhiên, các rào cản xác suất không thể mang lại sự đảm bảo chắc chắn về mặt mật mã học; những kẻ tấn công kiên trì vẫn có thể brute-force các tổ hợp cổng trên những resolver đang bận rộn.

DNS truyền thống thất bại trước ba bài kiểm tra tính toàn vẹn cơ bản:

  • Không có xác thực nguồn gốc (Origin Authentication): Resolver không thể xác minh gói tin thực sự đến từ authoritative nameserver của bạn hay từ một địa chỉ nguồn giả mạo.
  • Không có bảo vệ tính toàn vẹn (Integrity Protection): Các router trung gian có thể sửa đổi payload trên đường truyền mà không gây ra lỗi checksum.
  • Không có cơ chế chứng minh sự không tồn tại được xác thực (Authenticated Denial of Existence): Resolver không có bằng chứng mật mã nào khi một bản ghi không tồn tại, khiến các phản hồi NXDOMAIN dễ dàng bị giả mạo.

DNS Security Extensions (DNSSEC) khắc phục triệt để các lỗ hổng này bằng mật mã bất đối xứng. Máy chủ authoritative của bạn sẽ ký số lên từng tập hợp bản ghi tài nguyên (RRset) bằng chữ ký số (RRSIG). Sau đó, các resolver sẽ lần theo chuỗi tin cậy (chain of trust) từ root zone của ICANN xuống đến tên miền của bạn để xác thực các key tại từng ranh giới ủy quyền.

So sánh các giải pháp: Script thủ công vs. Inline Signing cũ vs. dnssec-policy hiện đại

BIND9 cung cấp cho quản trị viên ba phương pháp chính để triển khai DNSSEC. Lựa chọn sai phương pháp thường dẫn đến tình trạng chữ ký hết hạn, lỗi rollover key trong âm thầm và gây ra sự cố SERVFAIL trên toàn cầu do lỗi cấu hình nội bộ.

1. Ký thủ công với dnssec-keygen và dnssec-signzone

Trước phiên bản BIND 9.9, quản trị viên phải tự tạo key trên ổ cứng và chạy lệnh dnssec-signzone thông qua cron job. Mỗi lần chỉnh sửa zone đều phải tạo lại các file zone tĩnh dạng .signed và reload lại daemon.

  • Ưu điểm: Dễ kiểm soát hành vi và hoạt động ổn định trong các môi trường ký offline, cô lập.
  • Nhược điểm: Rủi ro vận hành rất cao. Nếu cron job gặp sự cố hoặc thời hạn hiệu lực của chữ ký (thường là 30 ngày) trôi qua mà không được gia hạn, tên miền sẽ ngừng hoạt động trên toàn cầu đối với tất cả các resolver có bật tính năng xác thực.

2. Inline-Signing thế hệ cũ (auto-dnssec maintain)

Được giới thiệu từ BIND 9.9, phương pháp này tách biệt file zone gốc khỏi dữ liệu đã ký bằng cách duy trì các journal động. BIND sẽ tự động ký lại các bản ghi mỗi khi file zone được cập nhật.

  • Ưu điểm: Loại bỏ sự phụ thuộc vào script cron bên ngoài và hỗ trợ cập nhật DNS động qua RFC 2136.
  • Nhược điểm: Quá trình rollover key vẫn phải thực hiện hoàn toàn thủ công. Kỹ sư phải tự sinh, xuất bản, kích hoạt và thu hồi các key KSK và ZSK bằng các cờ lệnh CLI theo một lịch trình thời gian nghiêm ngặt.

3. dnssec-policy tự động hiện đại (BIND 9.16+)

Xuất hiện từ BIND 9.16 và trở thành tiêu chuẩn trong bản 9.18+ LTS, khối dnssec-policy biến BIND thành một công cụ mật mã tự động hóa hoàn toàn. Nó tự sinh key, quản lý trạng thái rollover, tính toán mã băm DS digest và tự động ký lại các RRset trong nội bộ hệ thống.

  • Ưu điểm: Rollover key tự động không cần can thiệp thủ công, hỗ trợ mặc định ECDSA P-256, tự động làm mới chữ ký và giảm thiểu tối đa gánh nặng vận hành.
  • Nhược điểm: Yêu cầu BIND 9.16 trở lên và đòi hỏi phải phân quyền ghi hệ thống tệp chính xác cho daemon trên các thư mục làm việc.

Giải pháp tối ưu: Ký DNSSEC tự động với dnssec-policy trong BIND9

Đối với các hệ thống production hiện đại, mô hình khai báo dnssec-policy là hướng tiếp cận đáng tin cậy nhất. Chúng tôi đang vận hành cấu hình này trên các cụm authoritative chính xử lý khoảng 12.000 truy vấn mỗi giây mà không gặp bất kỳ vướng mắc nào trong khâu bảo trì.

Bước 1: Kiểm tra phiên bản BIND và Cryptographic Engine

Xác nhận rằng máy chủ của bạn đang chạy phiên bản BIND 9.16 LTS hoặc BIND 9.18+ LTS:

named -v
# Mục tiêu: BIND 9.16.x hoặc BIND 9.18.x

Các gói cài đặt tiêu chuẩn trên Ubuntu 22.04/24.04 (bind9) hoặc RHEL 9/AlmaLinux 9 (bind) đều được liên kết sẵn với thư viện mật mã OpenSSL theo mặc định.

Bước 2: Định nghĩa Production DNSSEC Policy

Mở file cấu hình options (/etc/bind/named.conf.options trên Debian/Ubuntu hoặc /etc/named.conf trên Enterprise Linux). Thêm một khối policy riêng biệt. Chúng tôi sử dụng Algorithm 13 (ECDSAP256SHA256) vì chữ ký 64-byte của thuật toán này giúp tối ưu kích thước gói tin, giữ payload phản hồi luôn thấp hơn ngưỡng đệm UDP tiêu chuẩn 1.232 byte để chống phân mảnh gói tin.

dnssec-policy "production-policy" {
    keys {
        ksk key-directory lifetime unlimited algorithm ecdsa256;
        zsk key-directory lifetime 60d algorithm ecdsa256;
    };

    # Thời gian hiệu lực và làm mới chữ ký
    signatures-refresh 5d;
    signatures-validity 14d;
    signatures-validity-dnskey 14d;

    # Độ trễ lan truyền và biên độ TTL
    max-zone-ttl 86400;
    zone-propagation-delay 300;
    parent-ds-ttl 86400;
    parent-propagation-delay 3600;
};

Với cấu hình này, Zone Signing Key (ZSK) sẽ được tự động rollover mỗi 60 ngày. Key Signing Key (KSK) sẽ giữ nguyên cho đến khi bạn chủ động lên lịch chuyển đổi thủ công. BIND sẽ tự động tái tạo và ký lại các bản ghi 5 ngày trước khi khoảng thời gian hiệu lực 14 ngày kết thúc.

Bước 3: Gắn Policy vào Zone của bạn

Mở file định nghĩa zone cục bộ (ví dụ: /etc/bind/named.conf.local). Gắn policy vừa tạo vào tên miền authoritative của bạn:

zone "example.com" {
    type primary;
    file "/var/lib/bind/db.example.com";
    dnssec-policy "production-policy";
    key-directory "/var/lib/bind/keys";
    inline-signing yes;
};

Đảm bảo thư mục lưu trữ và key thuộc quyền sở hữu của service user chạy dịch vụ. BIND cần quyền ghi để tạo các file journal, cơ sở dữ liệu zone đã ký và các private key:

mkdir -p /var/lib/bind/keys
chown -R bind:bind /var/lib/bind/
chmod 770 /var/lib/bind/ /var/lib/bind/keys

Bước 4: Reload BIND và kiểm tra quá trình tạo Key

Kiểm tra cú pháp cấu hình trước khi reload dịch vụ:

named-checkconf
named-checkzone example.com /var/lib/bind/db.example.com

Nếu cả hai lệnh đều không báo lỗi, tiến hành nạp cấu hình mới vào daemon:

rndc reconfig
rndc reload example.com

BIND sẽ tự động tạo các cặp key KSK và ZSK trong /var/lib/bind/keys rồi ký toàn bộ zone. Bạn có thể kiểm tra trạng thái key bằng rndc:

rndc dnssec -status example.com

Bước 5: Xuất bản bản ghi Delegation Signer (DS) tại Registrar

Việc ký cục bộ chỉ xác thực được các bản ghi trong nội bộ máy chủ của bạn. Các resolver bên ngoài vẫn sẽ từ chối truy vấn và trả về mã lỗi SERVFAIL cho đến khi bạn liên kết KSK với zone cha (như .com hoặc .net). Để thiết lập liên kết này, bạn phải xuất bản một bản ghi Delegation Signer (DS) tại nhà đăng ký tên miền (registrar).

Truy vấn máy chủ authoritative nội bộ để lấy bản ghi CDS vừa tạo:

dig @127.0.0.1 example.com CDS +short

Lệnh trên sẽ trả về bốn trường dữ liệu cách nhau bằng dấu cách:

# Key Tag | Thuật toán | Loại Digest | Digest
2371 13 2 E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855

Đăng nhập vào tài khoản tại registrar của bạn (ví dụ: Cloudflare, Namecheap hoặc AWS Route 53 Domains). Điều hướng đến mục cài đặt DNSSEC cho tên miền example.com, chọn Digest Type 2 (SHA-256), Algorithm 13 (ECDSA Curve P-256 with SHA-256) và dán chuỗi digest vào. Trong vòng 1 đến 2 giờ, registry cấp cha sẽ xuất bản bản ghi DS lên hệ thống.

Bước 6: Xác thực chuỗi mật mã đầu-cuối (End-to-End Cryptographic Chain)

Sau khi zone cha hoàn tất cập nhật, hãy kiểm tra chuỗi tin cậy bằng công cụ delv:

delv @8.8.8.8 example.com +rtrace

Kiểm tra phần cuối kết quả trả về để xác nhận trạng thái xác thực đầy đủ:

;; fully validated
example.com. 3600 IN A 192.0.2.1
example.com. 3600 IN RRSIG A 13 2 3600 ...

Xác nhận cờ Authenticated Data trực tiếp bằng lệnh dig:

dig @1.1.1.1 example.com +dnssec

Tìm dòng chứa các cờ tiêu đề (header flags). Cờ ad xuất hiện minh chứng rằng resolver upstream đã xác thực mật mã thành công:

;; flags: qr rd ra ad; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

Kinh nghiệm vận hành thực tế

  • Giới hạn TTL của zone tối đa 86.400 giây: Duy trì TTL của các bản ghi trong khoảng từ 3.600 đến 86.400 giây. Giá trị TTL quá dài sẽ làm chậm quá trình cập nhật bản ghi khẩn cấp và kéo dài thời gian gián đoạn xác thực nếu các key bị lệch đồng bộ.
  • Thiết lập cảnh báo hết hạn từ bên ngoài: Ngay cả các daemon tự động hóa cũng có thể bị crash hoặc gặp lỗi khóa journal. Hãy thiết lập các cảnh báo tự động thông qua Prometheus blackbox exporter hoặc Nagios để cảnh báo nếu thời gian hết hạn chữ ký của zone giảm xuống dưới 7 ngày.
  • Giữ lại các key cũ trên đĩa: Trong quá trình chuyển tiếp ZSK, BIND sẽ giữ lại public key cũ trong suốt giai đoạn thu hồi (retirement phase) để phục vụ xác thực các truy vấn vẫn còn nằm trong cache của resolver upstream. Tuyệt đối không xóa thủ công các file key này.
Share: