Tìm hiểu về UEFI HTTP(S) Boot với QEMU và OVMF: Từ cơ bản đến bảo mật
Bài viết này khám phá quy trình thiết lập khởi động qua mạng bằng giao thức HTTP và HTTPS thông qua UEFI trên môi trường QEMU/OVMF. Tác giả chia sẻ các kinh nghiệm giải quyết vấn đề về thiết bị tạo số ngẫu nhiên, tối ưu hóa tốc độ khởi động và khắc phục lỗi liên quan đến chứng chỉ bảo mật trong EDK II.
Trong nhiều năm qua, giải pháp mặc định để khởi động qua mạng (network boot) là PXE, dựa trên giao thức DHCP và TFTP. Tuy nhiên, việc cấu hình PXE không hề đơn giản, khả năng mở rộng cao (high availability) khó đạt được và vấn đề bảo mật luôn là nỗi lo ngại do TFTP là giao thức văn bản rõ ràng (clear-text) và không chữ ký.
Web hiện đại đã tiêu chuẩn hóa HTTPS với chứng chỉ TLS để xác thực máy chủ, đảm bảo tính toàn vẹn và bảo mật. Các thiết lập có tính sẵn sàng cao đối với HTTPS đã được giải quyết triệt để. Hơn nữa, lớp mã hóa cho phép thực hiện khởi động qua Internet mà không sợ bị tấn công trung gian (man-in-the-middle) – một mối đe dọa rất dễ xảy ra với TFTP.
Tin vui là hầu hết các hệ thống dựa trên UEFI hiện đại đều hỗ trợ khởi động qua HTTP(S). Trong bài viết này, chúng ta sẽ cùng thực hiện khởi động biến thể snponly của netboot.xyz trực tiếp từ trang web chính thức thông qua QEMU và OVMF.
Yêu cầu và thiết lập ban đầu
Tất cả các thử nghiệm dưới đây được thực hiện trên Ubuntu 26.04 với các gói QEMU 1:10.2.1+ds-1ubuntu3 và OVMF 2025.11-3ubuntu7. Chúng ta sẽ bắt đầu với trường hợp đơn giản nhất: HTTP Boot được khám phá qua DHCP.
Mục tiêu là thiết lập tối giản để dễ dàng tích hợp vào môi trường của bạn. Chúng ta sẽ sử dụng máy ảo QEMU không root với mạng SLIRP dựa trên userland và không cần thiết bị lưu trữ bổ sung. Toàn bộ hệ thống sẽ chạy trên bộ nhớ.
Câu lệnh QEMU khởi đầu trông như sau:
qemu-system-x86_64 \
-drive if=pflash,format=raw,readonly=on,file=/usr/share/OVMF/OVMF_CODE_4M.fd \
-nic user,bootfile=http://boot.netboot.xyz/ipxe/netboot.xyz-snponly.efi \
-nographic
Tuy nhiên, lệnh này sẽ thất bại với lỗi No bootable option or device was found.
Thiết bị sinh số ngẫu nhiên (RNG) là bắt buộc
Nguyên nhân là do stack mạng trong OVMF yêu cầu một thiết bị sinh số ngẫu nhiên (Random Number Generator) để hoạt động. Khi suy nghĩ kỹ, điều này là hiển nhiên vì hầu hết các lớp của stack mạng đều yêu cầu tính ngẫu nhiên, từ việc tránh va chạm Ethernet đến TLS và DHCP.
Chúng ta có thể kích hoạt tính năng này rất dễ dàng bằng cách thêm cờ sau vào dòng lệnh QEMU:
-device virtio-rng-pci
Sau khi thêm thiết bị này, quá trình khởi động sẽ thành công, nhưng thời gian chờ khá lâu (khoảng 1 phút 15 giây) do hệ thống thử nhiều phương thức khác nhau trước khi tìm ra đúng cách.
Tối ưu hóa tốc độ khởi động
Việc chờ đợi một phút chỉ để thực hiện một lần thử khởi động là quá lâu. Stack mạng UEFI thực hiện các bước tuần tự:
- IPv4 PXE: Hoạt động nhưng URL HTTP không hợp lệ (mong đợi TFTP).
- IPv6 PXE: Không hoạt động vì không cấu hình IPv6.
- IPv4 HTTP: Cuối cùng mới hoạt động.
May mắn là QEMU có cách truyền tùy chọn cho firmware bằng cờ -fw_cfg. Chúng ta có thể tắt hỗ trợ PXE cũ để tiết kiệm thời gian:
qemu-system-x86_64 \
-device virtio-rng-pci \
-drive if=pflash,format=raw,readonly=on,file=/usr/share/OVMF/OVMF_CODE_4M.fd \
-nic user,bootfile=http://boot.netboot.xyz/ipxe/netboot.xyz-snponly.efi \
-fw_cfg name=opt/org.tianocore/IPv4PXESupport,string=no \
-fw_cfg name=opt/org.tianocore/IPv6PXESupport,string=no \
-nographic
Với cấu hình này, máy ảo sẽ khởi động vào netboot.xyz chỉ trong khoảng 5 giây.
Sử dụng biến UEFI thay vì DHCP
Phương pháp trên hoạt động tốt nhưng khó chuyển sang phần cứng thực. Trên phần cứng thực, chúng ta không có các công cụ tinh chỉnh runtime của OVMF, thay vào đó là các biến UEFI.
Chúng ta có thể sử dụng công cụ virt-fw-vars để tiêm "Next Boot URI" trực tiếp vào lưu trữ biến OVMF_VARS:
# Cài đặt công cụ firmware
sudo apt install python3-virt-firmware
# Tiêm "Boot entry" vào biến store mới
virt-fw-vars --input /usr/share/OVMF/OVMF_VARS_4M.fd --set-boot-uri http://boot.netboot.xyz/ipxe/netboot.xyz-snponly.efi --output ./OVMF_VARS_4M.fd
# Khởi động VM
qemu-system-x86_64 \
-device virtio-rng-pci \
-drive if=pflash,format=raw,readonly=on,file=/usr/share/OVMF/OVMF_CODE_4M.fd \
-drive if=pflash,format=raw,file=./OVMF_VARS_4M.fd \
-nic user \
-nographic
Thử thách với HTTPS Boot
Có vẻ như chỉ cần thay đổi http:// thành https:// là xong? Thực tế không hề đơn giản. Nếu bạn thử, bạn sẽ gặp lỗi "Could not retrieve NBP file size" hoặc "Unexpected network error".
Để tìm hiểu nguyên nhân, chúng ta cần biên dịch lại OVMF ở chế độ DEBUG (vì bản RELEASE mặc định của Ubuntu không ghi log). Sau khi bật debug và kiểm tra log, lỗi hiện ra rõ ràng:
TLS Certificate is not found on the system!
OVMF không đi kèm danh sách chứng chỉ CA (Certificate Authority) như các trình duyệt web. Chúng ta cần cung cấp danh sách tin cậy này. Một cách dễ dàng là chuyển đổi bundle chứng chỉ của hệ thống sang định dạng phù hợp cho OVMF bằng p11-kit:
p11-kit extract --format=edk2-cacerts --filter=ca-anchors --overwrite --purpose=server-auth cacerts.bin
Sau đó, truyền file này cho QEMU:
-fw_cfg name=etc/edk2/https/cacerts,file=cacerts.bin
Vấn đề về cấp độ bảo mật (Security Level) của OpenSSL
Ngay cả khi đã có chứng chỉ, việc khởi động HTTPS vẫn có thể thất bại với lỗi trong log:
TlsDoHandshake X509_verify_result: 66 (EE certificate key too weak)
Đây là điểm mấu chốt. EDK II (dự án nền tảng của OVMF) sử dụng thư viện OpenSSL. Gần đây, EDK II đã nâng cấp Security Level mặc định lên cấp 3. Điều này yêu cầu khóa RSA dài hơn 2048 bit. Tuy nhiên, chứng chỉ hiện tại của https://boot.netboot.xyz/ sử dụng khóa RSA 2048 bit, chỉ tương thích với Security Level 2.
Trong khi Ubuntu và Firefox vẫn chấp nhận khóa này (do dùng mức bảo mật mặc định thấp hơn), firmware UEFI lại từ chối vì tiêu chuẩn an toàn khắt khe hơn. Để giải quyết vấn đề này trong môi trường thử nghiệm, chúng ta có thể vá mã nguồn EDK II để hạ cấp Security Level xuống 2, hoặc yêu cầu phía máy chủ nâng cấp chứng chỉ.
Sau khi vá firmware, quá trình khởi động HTTPS thành công:
>>Start HTTP Boot over IPv4....
URI: https://boot.netboot.xyz/ipxe/netboot.xyz-snponly.efi
Downloading...100%
BdsDxe: loading Boot0099 "netboot netboot.xyz-snponly.efi" from Uri(...)
iPXE initialising devices...
Tổng kết và cú pháp đầy đủ
Dưới đây là tóm tắt cấu hình tối thiểu để khởi động UEFI HTTPS Boot thành công:
HTTPS Boot - Sử dụng UEFI VARS:
# 1. Tiêm Boot URI vào biến store
virt-fw-vars --input /usr/share/OVMF/OVMF_VARS_4M.fd --set-boot-uri https://boot.netboot.xyz/ipxe/netboot.xyz-snponly.efi --output ./OVMF_VARS_4M.fd
# 2. Chuyển đổi chứng chỉ CA sang định dạng OVMF
p11-kit extract --format=edk2-cacerts --filter=ca-anchors --overwrite --purpose=server-auth cacerts.bin
# 3. Khởi động VM
qemu-system-x86_64 \
-device virtio-rng-pci \
-drive if=pflash,format=raw,readonly=on,file=/usr/share/OVMF/OVMF_CODE_4M.fd \
-drive if=pflash,format=raw,file=./OVMF_VARS_4M.fd \
-nic user \
-fw_cfg name=etc/edk2/https/cacerts,file=cacerts.bin \
-nographic
Lưu ý quan trọng:
- RNG là bắt buộc: Luôn luôn cần thiết bị sinh số ngẫu nhiên (
virtio-rng-pcihoặc-cpu host). - Chứng chỉ CA: OVMF không có sẵn danh sách CA, bạn phải cung cấp thông qua
fw_cfghoặc biến UEFI. - Security Level: Đảm bảo chứng chỉ máy chủ đáp ứng yêu cầu Security Level 3 của EDK II (hoặc vá firmware nếu là môi trường lab).
UEFI HTTPS Boot là một bước tiến lớn so với PXE/TFTP truyền thống, mang lại khả năng mở rộng cao và bảo mật tốt hơn, cho phép khởi động các thành phần quan trọng từ cloud hoặc vị trí từ xa một cách an toàn.
