Bảo mật Linux hiện đại: Củng cố quá trình khởi động với Unified Kernel Images (UKI)

Security tutorial - IT technology blog
Security tutorial - IT technology blog

Chuyển dịch sang Unified Kernel Images: Tại sao bảo mật khởi động lại quan trọng

Quá trình khởi động Linux truyền thống giống như một cuộc chạy tiếp sức với quá nhiều lượt bàn giao. Firmware (UEFI) chuyển quyền điều khiển cho một bootloader như GRUB, sau đó bootloader này sẽ nạp kernel và RAM disk ban đầu (initrd) từ các tệp riêng biệt trên đĩa cứng.

Tính mô-đun này mang lại sự linh hoạt tuyệt vời, nhưng nó cũng mở ra cánh cửa cho những kẻ tấn công. Nếu một kẻ xấu có được quyền truy cập root, chúng có thể thay thế initrd của bạn bằng một phiên bản đã bị can thiệp. Initrd độc hại này có thể đánh cắp mật khẩu mã hóa đĩa LUKS của bạn ngay cả trước khi bạn thấy màn hình đăng nhập.

Tôi đã rút ra bài học này một cách xương máu sau khi một máy chủ tôi quản lý hứng chịu hơn 4.000 lần thử đăng nhập SSH thất bại chỉ trong một giờ. Dù tôi đã chặn được các cuộc tấn công mạng, tôi nhận ra rằng: củng cố mạng chỉ là một nửa cuộc chiến. Nếu quá trình khởi động của hệ điều hành bên dưới không được xác thực, mọi lớp bảo mật phía trên đều được xây dựng trên nền cát lún. Nhận thức này đã dẫn tôi đến việc áp dụng Unified Kernel Images (UKI).

UKI là một file thực thi EFI duy nhất, khép kín. Nó kết hợp Linux kernel, initrd, kernel command line và một đoạn UEFI stub nhỏ vào một tệp duy nhất. Thay vì quản lý nửa tá chữ ký, bạn chỉ cần ký một file binary duy nhất. Firmware UEFI của bạn sẽ xác thực chữ ký này, đảm bảo lõi hệ thống của bạn luôn ở trạng thái nguyên bản như ý muốn.

Thiết lập môi trường

Bạn sẽ cần một vài công cụ chuyên dụng để xây dựng và ký các image này. Hầu hết các bản phân phối hiện đại, bao gồm Arch, Fedora và Debian (Sid/Trixie), đều cung cấp chúng trong kho lưu trữ tiêu chuẩn. Chúng ta sẽ sử dụng systemd-ukify, công cụ đã trở thành tiêu chuẩn thực tế để lắp ráp các image này.

Trên các hệ thống dựa trên Debian, cài đặt các phụ thuộc bằng apt:

sudo apt update
sudo apt install systemd-boot binutils sbsigntools python3-pefile

Dành cho người dùng Arch Linux:

sudo pacman -S systemd ukify sbsigntools

Gói sbsigntools là thành phần quan trọng nhất ở đây. Nó cung cấp các tiện ích cần thiết để áp dụng các chữ ký mã hóa mà cơ chế Secure Boot của bo mạch chủ yêu cầu để tin tưởng file binary.

Bước 1: Tạo khóa Secure Boot của riêng bạn

Việc chỉ dựa vào các khóa Microsoft được cài đặt sẵn đồng nghĩa với việc tin tưởng vào một bên thứ ba cho gốc tin cậy (root of trust) của phần cứng. Để nắm quyền kiểm soát hoàn toàn, bạn nên tạo Machine Owner Keys (MOK) của riêng mình. Trong hướng dẫn này, chúng ta sẽ tạo một cặp khóa RSA 2048-bit dành riêng cho việc ký UKI.

# Tạo thư mục riêng cho các khóa của bạn
mkdir -p ~/secure-boot-keys
cd ~/secure-boot-keys

# Tạo một private key và một chứng chỉ có hiệu lực trong 10 năm
openssl req -new -x509 -newkey rsa:2048 -nodes -days 3650 -subj "/CN=Khóa UKI tùy chỉnh của tôi/" -keyout uki.key -out uki.crt

# Chuyển đổi chứng chỉ sang định dạng DER để đăng ký vào UEFI
openssl x509 -in uki.crt -out uki.cer -outform DER

Hãy bảo vệ tệp uki.key cẩn thận nhất có thể. Bất kỳ ai có được tệp này đều có thể ký một kernel độc hại mà máy tính của bạn sẽ coi là hoàn toàn hợp lệ.

Bước 2: Xây dựng UKI với ukify

Đây là bước xử lý chính. Chúng ta sẽ gộp kernel (vmlinuz), initramfs và các tham số khởi động vào một tệp .efi duy nhất. Việc sử dụng tệp cấu hình cho ukify giúp quy trình có thể lặp lại và tránh sai sót khi gõ các chuỗi lệnh dài.

Tạo một tệp có tên uki-config.conf:

[UKI]
Linux=/boot/vmlinuz-linux
Initrd=/boot/initramfs-linux.img
Cmdline="root=UUID=550e8400-e29b-41d4-a716-446655440000 rw quiet bgrt_disable"
OSRelease=@/etc/os-release
Stub=/usr/lib/systemd/boot/efi/linuxx64.efi.stub

Xây dựng image chưa ký bằng cách chạy lệnh:

/usr/lib/systemd/ukify build --config=uki-config.conf --output=vmlinuz-unsigned.efi

Mặc dù ukify có thể ký các image trong quá trình xây dựng, tôi thích ký thủ công ở bước tiếp theo để đảm bảo quy trình công việc được rõ ràng nhất.

Bước 3: Ký Unified Image

Bây giờ chúng ta áp dụng dấu xác thực mã hóa. Bước này đính kèm chữ ký của bạn vào phần header PE của file binary EFI, cho phép firmware xác thực nó với các khóa mà bạn sẽ đăng ký ở bước tiếp theo.

sbsign --key uki.key --cert uki.crt --output /boot/EFI/Linux/systemd-linux.efi vmlinuz-unsigned.efi

Tôi khuyên bạn nên đặt đầu ra trong /boot/EFI/Linux/. Các phiên bản hiện đại của systemd-boot sẽ tự động quét thư mục này. Chúng sẽ tìm thấy các tệp .efi của bạn và thêm chúng vào menu khởi động mà không cần bất kỳ cấu hình thủ công nào.

Bước 4: Đăng ký khóa trong UEFI

Bo mạch chủ của bạn hiện chưa biết đến uki.crt. Bạn có hai cách để giải quyết vấn đề này:

  1. Quản lý MOK: Nếu bạn sử dụng ‘shim’ (mặc định cho Ubuntu hoặc Fedora), hãy sử dụng mokutil --import uki.cer. Lệnh này sẽ kích hoạt giao diện màn hình xanh trong lần khởi động tới để bạn xác nhận việc đăng ký khóa.
  2. Tùy chỉnh khóa: Bạn có thể thay thế các khóa mặc định của nhà sản xuất trong cài đặt UEFI bằng khóa của riêng mình. Đây là một bước nâng cao mang lại bảo mật cao nhất nhưng đòi hỏi nhiều công sức bảo trì hơn.

Đối với hầu hết các thiết lập, mokutil là lựa chọn thực tế nhất:

sudo mokutil --import ~/secure-boot-keys/uki.cer

Đặt mật khẩu tạm thời, khởi động lại và làm theo các hướng dẫn “Enroll MOK” trong môi trường UEFI.

Xác minh và Tự động hóa

Xác minh là mảnh ghép cuối cùng. Sau khi bạn đã khởi động vào UKI mới, bạn cần xác nhận rằng vòng lặp bảo mật đã được khép kín.

Kiểm tra trạng thái Secure Boot

Chạy bootctl để kiểm tra môi trường của bạn:

bootctl status

Tìm dòng Secure Boot: enabled. Nếu bạn thấy dòng này, firmware của bạn đã xác thực thành công chữ ký của UKI trước khi cho phép bất kỳ dòng code kernel nào được thực thi.

Xác minh chữ ký của file binary

Để kiểm tra kỹ tệp trên đĩa, hãy sử dụng sbverify:

sbverify --list /boot/EFI/Linux/systemd-linux.efi

Lệnh này hiển thị chi tiết chứng chỉ. Nếu tệp bị can thiệp, việc xác minh sẽ thất bại ngay lập tức.

Tối ưu hóa quy trình làm việc

Việc ký kernel thủ công sau mỗi lần cập nhật là một cách chắc chắn dẫn đến lỗi hệ thống. Trên Arch Linux, tôi sử dụng một hook của pacman. Trên các bản phân phối khác, một script trong /etc/kernel/install.d/ có thể tự động hóa quá trình ukifysbsign. Điều này đảm bảo rằng mỗi khi bạn cập nhật hệ thống, tính bảo mật của bạn vẫn được duy trì mà không cần can thiệp thủ công.

Bằng cách chuyển sang UKI, bạn loại bỏ cấu hình bootloader như một điểm yếu có thể gây lỗi. Kernel và initrd của bạn trở thành một khối thống nhất, bất biến. Đây là một bước tiến lớn so với các kiến trúc truyền thống và là thành phần quan trọng của bất kỳ máy trạm Linux nào được tăng cường bảo mật.

Share: