มาทำ Secure Boot บน Linux กันเถอะ

· 2 min read
มาทำ Secure Boot บน Linux กันเถอะ

Secure Boot คืออะไร?

Secure Boot เป็นฟังก์ชั่นของระบบไบออส UEFI ที่ป้องกันการติดตั้งไฟล์ระบบที่ไม่ได้รับการอนุมัติจากผู้ผลิดเมนบอร์ด
โดยเมื่อระบบบูต, ไบออส UEFI จะตรวจหาลายเซ็นดิจิตอลในไฟล์บูตของระบบปฏิบัติการ
หากตรวจพบและเช็คความถูกต้องผ่านหมด ก็จะทำการบูตระบบปฏิบัติการนั้นขึ้นมา
แต่ถ้าไม่พบ, ไม่ถูกต้อง หรือลายเซ็นมาจากเจ้าที่ไม่รู้จัก ก็จะปฏิเสธการบูตระบบนั้น

ฟีเจอร์นี้มีไว้ในกรณีที่ระบบปฏิบัติการที่มีรูโหว่แล้วถูกไวรัสเขียนทับไฟล์ระบบที่ใช้บูต หรือถูกผู้อื่นเข้าถึงคอมของเราแล้ววางไฟล์บูตที่มีช่องโหว่ให้โจมตีได้
เมื่อผู้ใช้รีสตาร์ต ระบบจะหยุดทำงานที่จอดำเพื่อไม่ให้ไวรัสก่อความเสียหายเพิ่มเติม หรือถูกโจมตีระบบ

จำเป็นแค่ไหน?

หากว่าระบของเราไม่ได้เข้ารหัสแบบ Full-disk encryption แล้วนั้น ตัว secure boot ไม่ได้จำเป็น หรือไม่มีประโยชน์ใด ๆ เลย นอกจากให้ Microsoft บังคับห้ามเราลง ระบบประติบัติการที่เราต้องการเท่านั้น (ปิด secure boot ใน bios ก็สามารถเข้าระบบได้เลย)

แต่สำหรับระบบที่เข้ารหัสไว้นั้น จะช่วยเพิ่มความปลอดภัยไปอีกระดับ เช่นหากโดยขโมยคอมไป แม้เขาจะพยายามแก้ไขไฟล์ boot ก็ไม่สามารถเข้าถึงระบบเราได้อยู่ดี มีเดียวทางเดียวคือล้างข้อมูลทั้งหมดทิ้งไปเท่านั้น ถึงจะใช้งานคอมเครื่องนั้น ๆ ได้ แม้จะปิด secure boot ใน bios แล้วก็ตาม

ทำให้ระบบ Linux ที่เข้ารหัสไว้ ปลอดภัยขึ้นอีกชั้นนึง

Boot Loader

BIOS > BOOT LOADER > KERNEL > INIT SYSTEM
    

ในระบบประติบัติการ Linux นั้น มีตัวเลือกสำหรับ Boot Loader ที่หลากหลาย อย่างระบบใหม่ ๆ จะใช้ systemd-boot ที่สะดวกใช้งานง่าย ปรับอะไรได้ไม่มากนัก
โดยตัวที่ใช้เยอะที่สุดคงจะเป็น GRUB ซึ่งสามารถปรับแต่งได้แทบทุก logic ของการบูตเข้าระบบของเรา และในบทความนี้ เราจะใช้ GRUB ในการทำ Secure Boot

โดยก่อนหน้านั้นเราต้องแบ่ง partition ส่วนนึงไปให้ /boot/efi ซึ่งเป็น filesystem แบบ fat ทั่ว ๆ ไป สำหรับ ให้ bios อ่านไฟล์ boot ของเราได้

❯ sudo fdisk -l
    Disk /dev/nvme0n1: 476.94 GiB, 512110190592 bytes, 1000215216 sectors
    Disk model: WD PC SN735 SDBPNHH-512G-1002
    Units: sectors of 1 * 512 = 512 bytes
    Sector size (logical/physical): 512 bytes / 512 bytes
    I/O size (minimum/optimal): 512 bytes / 512 bytes
    Disklabel type: gpt
    Disk identifier: 9A5798B5-DC04-4770-A26B-3A489642CF32
    
    Device           Start        End   Sectors   Size Type
    /dev/nvme0n1p1    2048    2099199   2097152     1G EFI System
    /dev/nvme0n1p2 2099200 1000214527 998115328 475.9G Linux filesystem
    

และอีกส่วน จะใช้ LVM (Logical Volume Management) ในการสร้าง Volume Group (VG) บน SSD ของผม สำหรับติดตั้งระบบที่เข้ารหัสไว้ โดยจะแบ่งพื้นที่ส่วนนึงไปเป็น swap partition ใช้สำหรับการเก็บข้อมูลตอนที่เราพับจอ หรือเข้าโหมด sleep
ที่เหลือทั้งหมด ก็จะเป็นพื้นที่ติดตั้ง Linux ของผม (disk นี้ผมไม่ได้แยก /home(user's home) กับ /(root) ไว้คนละ Partition เพราะว่าผมชอบทำ root เต็มบ่อย ๆ ฮาาา)

❯ sudo vgscan
      Found volume group "vg0" using metadata type lvm2
    
    ❯ sudo lvscan
      ACTIVE            '/dev/vg0/swap' [17.00 GiB] inherit
      ACTIVE            '/dev/vg0/void' [458.93 GiB] inherit
    

สำหรับวิธีการติดตั้ง Linux แบบเข้ารหัสนั้น มีอยู่ตามคู่มือตอนติดตั้ง Linux เกือบทุกตัวอยู่แล้ว ไม่ต้อง งง ยิ่งพวกที่เป็น GUI install อย่าง Fedora, Ubuntu บลา ๆ นั้นแค่คลิก ๆ ก็ทำได้แล้ว (แถมทำ Secure Boot ได้เลยอีกต่างหาก)

โดยที่ระบบที่ผมใช้ในบทความนี้ คือ VoidLinux ซี่งเป็นระบบง่าย ๆ ไม่มี systemd ให้กวนใจ

ส่วนของ software ที่ใช้จะมี

  1. grub
  2. sbctl
    และ bash script เล็กน้อย ในการทำ kernel hook สำหรับการ Sign ไฟล์ boot ของเราอัตโนมัติหลังจาก Update

เริ่มกันเลย!

อย่างแรก ตั้งค่า SecureBoot ใน Bios เป็น Setup-Mode ให้เรียบร้อยก่อน
จากนั้นต้องตั้งค่า Grub กันใหม่ โดยเพิ่ม module tpm และ --disable-shim-lock (สำหรับ Microsoft's CA) เผื่อกรณีที่อยากทำ Dual Boot เข้า Windows ด้วย

sudo grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=void --modules="tpm" --disable-shim-lock
    

จากนั้นก็มา Gen ไฟล์ตั้งค่าที่เพิ่งทำไปด้วยคำสั่ง

sudo grub-mkconfig -o /boot/grub/grub.cfg
    

แล้วก็ติดตั้ง sbctl ให้เรียบร้อย

sudo xbps-install sbctl
    

จากนั้นลองเช็คด้วยคำสั่ง sbctl status ก็จะแสดงผลประมาณนี้

❯ sbctl status
    Installed:      ✓ sbctl is installed
    .....
    

จากนั้นเราก็จะสร้าง Key สำหรับการ Sign ไฟล์ Boot ของเรา

sudo sbctl create-keys
    

พอได้คีย์แล้ว enroll-keys ต่อ คำสั่งนี้จะสร้างรหัสสำหรับ Verify ใน Bios ให้เราหลังจากการตั้ง Setup-Mode ใน Secure Boot (-m คือการเพิ่ม Cert ของ Microsoft ไปด้วย เผื่อ Dual Boot)

sudo sbctl enroll-keys -m
    

หลังจากขั้นตอนนี้ก็ใช้คำสั่งดู status อีกรอบ
และใช้คำสั่ง sudo sbctl verify เพื่อดูว่าเราต้อง Sign ไฟล์ไหนบ้าง

❯ sbctl status
    Installed:      ✓ sbctl is installed
    Owner GUID:     61bb7cf9-38bb-4ef5-94f6-960b095c9322
    Setup Mode:     ✓ Disabled
    Secure Boot:    ✓ Enabled
    Vendor Keys:    microsoft
    ❯ sudo sbctl verify
    Verifying file database and EFI images in /boot/efi..
    ✓ /boot/efi/EFI/void/grubx64.efi is signed
    

อย่างตัวอย่างข้างบนคือไฟล์เหล่านี้ได้ถูก sign เรียบร้อยแล้ว ก็สามารถ Boot ด้วย Secure Boot ได้เลย
หากไฟล์ไหนยังไม่ได้ Sign ก็จัดการด้วยคำสั่ง sudo sbctl sign -s /ไฟล์พาท เช่น

sudo sbctl sign -s /boot/efi/EFI/void/grubx64.efi
    

แล้วก็ลอง sudo sbctl verify ดูว่า sign เรียบร้อยดีไหม
ถ้าเรียบร้อยแล้วก็สามารถ reboot ไปเปิด SecureBoot ดูได้เลย ว่า Boot เข้าระบบได้หรือไม่

และบางระบบก็ต้อง sign ไฟล์ kernel ด้วยเหมือนกัน อย่างระบบผม ต้อง sign /boot/vmlinuz-{version} ด้วย ไม่งั้น Boot ไม่ได้

❯ sudo sbctl sign -s /boot/vmlinuz-6.9.6_1
    
    ❯ sudo sbctl verify
    Verifying file database and EFI images in /boot/efi...
    ✓ /boot/vmlinuz-6.9.6_1 is signed
    ✓ /boot/efi/EFI/void/grubx64.efi is signed
    

หลังจาก reboot ด้วย SecureBoot ได้เรียบร้อย เป็นอันเสร็จ
แต่อย่าลืมว่าถ้าระบบ Update เราต้องกลับมา Sign เองใหม่หรือเปล่า??

Kernel Hook

โดยทั่วไป ระบบ Linux จะมี Directory /etc/kernel.d/post-install/ ซึ่งจะรวบรวมเอา Script สำหรับใช้หลังจาก Update ระบบเช่น ตัว Grub เอง ก็สร้างไฟล์ config ใหม่ทุกครั้งหลังจาก update kernel

cat /etc/kernel.d/post-install/50-grub
    #!/bin/sh
    #
    # Kernel hook for GRUB 2.
    #
    # Arguments passed to this script: $1 pkgname, $2 version.
    #
    PKGNAME="$1"
    VERSION="$2"
    
    export ZPOOL_VDEV_NAME_PATH=YES
    
    if command -v grub-mkconfig >/dev/null 2>&1; then
            if [ -d $ROOTDIR/boot/grub ]; then
                    grub-mkconfig -o $ROOTDIR/boot/grub/grub.cfg
                    exit $?
            fi
    fi
    
    exit 0
    

และสังเกตุว่า ไฟล์ทั้งหมดใน Directory นี้นั้น จะนำหน้าด้วยตัวเลข ซึ่งเป็นลำดับของการทำงานนั่นเอง โดยที่เลขน้อยกว่า จะถูกรันก่อน จนครบ

❯ sudo ls /etc/kernel.d/post-install/ -l
    10-dkms
     20-initramfs -> ../../../usr/libexec/dracut/kernel-hook-postinst
     50-bootsize
    50-efibootmgr
    50-grub
    

เราก็จะทำการ Copy ไฟล์ 50-grub มาเป็น templates ในการทำ kernel hook และตั้งชื่อว่า 60-sign เพื่อให้แน่ใจว่า ทุกอย่างถูกติดตั้งไปก่อน แล้ว sign เป็นลำดับสุดท้าย

sudo cp /etc/kernel.d/post-install/50-grub  /etc/kernel.d/post-install/60-sign
    

แล้วก็เข้าไปแก้ไขไฟล์

sudo vi  /etc/kernel.d/post-install/60-sign
    

แล้วก็ปรับคำสั่งเป็น sbctl ให้เรียบร้อย
จะสังเกตุว่าผมได้ใช้ sign สองครั้ง คือ grub config และไฟล์ kernel vmlinuz- ที่มีเวอร์ชั่นตามท้าย

#!/bin/sh
    #
    # Kernel post-install hook for surcue boot.
    #
    # Arguments passed to this script: $1 pkgname, $2 version.
    #
    
    PKGNAME="$1"
    VERSION="$2"
    
    if command -v sbctl >/dev/null 2>&1; then
        if [ -d $ROOTDIR/boot/efi ]; then
            echo "Signing new packages v.$VERSION"
            sbctl sign -s /boot/efi/EFI/void/grubx64.efi
            sbctl sign -s /boot/vmlinuz-${VERSION}
            exit $?
        fi
    fi
    
    exit 0
    

เซฟไฟล์ และสุดท้าย ทำ permission ให้มัน excuteable หรือว่าให้โปรแกรมเรียยกทำงานได้

sudo chmod +x  /etc/kernel.d/post-install/60-sign
    

เนื่องจากว่าบางระบบจะไม่ให้ไฟล์ script ใดๆ มาทำงานได้ตามใจชอบ
เราต้องควบคุมเองว่าไฟล์ไหนมี สิทธ์ ที่จะทำงานได้ นั่นเอง

เพียงเท่านี้ เราก็จะมีระบบเข้ารหัสที่ปลอดภัยสุด ๆ ใครจะมาแอบเสียบแฟรชไดร์มาแก้ไขไฟล์ Boot วางยาเราไม่ได้ แน่นอน

This post and comments are published on Nostr.