セキュリティ関連のテーマを扱う者として,医者の不養生みたいなことはしてはいけないと思い,持ち歩くデバイスには最大限の対策をしている(ほんまか?).

その一環として,ラップトップではディスク暗号化とSecure Bootを有効にしている.
元はArch Linuxでこれらをやっていたが,NixOS以降後も同様の環境を再現できたので,その方法を記録しておく.

(既に半年以上前にやっていたものですが,最近修理から返ってきたマシンに再設定したのでこの機会に文字に起こしました)

概要

  • NixOSをLUKS暗号化ディスクにインストールし,Secure BootとTPM2.0による自動アンロックまで導入する
  • Windows 11とのデュアルブート構成も同時に行う
    • そのため真面目に使うなら少なくともSecure Bootは必須
    • 同一ドライブ上に導入する想定

Prerequisites

  • Windows 11がインストール済み
    • Bitlockerは一旦解除しておいた方が良い.回復キーを何度か入れる羽目になるので.
  • Secure Bootは一時的に無効化しておく
  • NixOSはクリーンインストール
    • そもそも後からFull Disk Encryptionをするのは厳しいので

パーティションの調整

各自の好みのサイズをNixOS用に確保しておけば良いが,ESP(EFI System Partition)は1-2GiB程度まで拡張しておくことを推奨.

NixOSでは/boot以下にESPをマウントするのが基本構成で,/boot/efi/nixos以下に,存在するgenerationでin-usedなカーネルとinitrdを保持する.多くの場合initrdは100MiBを超えるサイズとなるため,複数のkernelとinitrdが存在するとESPが圧迫されてすぐ領域不足となる.

パーティション拡張は色々方法があると思うので割愛.Windowsだと怪しいソフトがよく出てきますが,推奨はしません(一応使ったことはあります).

NixOSのRootFSは未使用領域としてパーティションのみ切っておく.

NixOSのインストール

GUIインストーラでは設定可能な項目に限りがあるので,CLIでのマニュアルインストールを行う.GUI付きLive USBでも別にマニュアルインストールを行うことはできる.

Live環境を起動し,sudo -i等でrootのシェルに入る.

パーティションのフォーマット・マウント

LUKSをセットアップする.ここでは,ターゲットパーティションが/dev/nvme0n1p5と仮定.

# LUKS partitionの作成
cryptsetup luksFormat -y --label="NixOS-LUKS" /dev/nvme0n1p5
# LUKS partitonをアンロック
# /dev/mapper/luks にマップされる
cryptsetup luksOpen /dev/nvme0n1p5 luks

OpenしたLUKS partitionをフォーマットする.
ここではRootFSにbtrfsを使用するが,各自の好みのFilesystemでもよい.
サブボリュームを使用したbtrfs特有の構成をするので,他のFSを使う場合は読み飛ばしてOK.

# btrfsでフォーマット
mkfs.btrfs -L "NixOS-ROOT" /dev/mapper/luks
# subvolumeを切るために一時的にマウント
mount /dev/mapper/luks /mnt
# subvolumeを作成
btrfs subvolume create /mnt/root
btrfs subvolume create /mnt/home
btrfs subvolume create /mnt/nix
btrfs subvolume create /mnt/swap
# マウント解除
umount /mnt
# 実際の運用構成でマウント
mount -o compress=ztsd,subvol=root /dev/mapper/luks /mnt
mkdir -p /mnt/{home,nix,swap}
mount -o compress=zstd,subvol=home /dev/mapper/luks /mnt/home
mount -o compress=zstd,noatime,subvol=nix /dev/mapper/luks /mnt/nix
mount -o noatime,subvol=swap /dev/mapper/luks /mnt/swap
# Swap作成
btrfs filesystem mkswapfile --size 8g --uuid clear /mnt/swap/swapfile
swapon /mnt/swap/swapfile

Configuration生成・適用

この状態でconfiguration.nixhardware-configuration.nixを生成する.生成後,最小限の変更を入れた上でインストールする.
一般ユーザーの作成程度はここでやっておくとよい.また,FSのマウントマップはby-uuidで生成されているが,パーティションにlabelを振っているならby-labelでの指定に変えておくと見た目が分かりやすい.

# configurationの生成
nixos-generate-config --root /mnt
vim /mnt/etc/nixos/configuration.nix
vim /mnt/etc/nixos/hardware-configuration.nix
/mnt/etc/nixos/configuration.nix
  # Just uncomment and change username
  users.users.myuu = {
    isNormalUser = true;
    extraGroups = [ "wheel" ]; # Enable ‘sudo’ for the user.
  };
/mnt/etc/nixos/hardware-configuration.nix
  # Modify to use /dev/disk/by-label/*
  boot.initrd.luks.devices."luks".device = "/dev/disk/by-label/NixOS-LUKS";
 
  fileSystems."/" = {
    device = "/dev/disk/by-label/NixOS-ROOT";
    fsType = "btrfs";
    options = [ "subvol=root" ];
  };
 
  fileSystems."/home" = {
    device = "/dev/disk/by-label/NixOS-ROOT";
    fsType = "btrfs";
    options = [ "subvol=home" ];
  };
 
  fileSystems."/nix" = {
    device = "/dev/disk/by-label/NixOS-ROOT";
    fsType = "btrfs";
    options = [
      "subvol=nix"
      "noatime"
    ];
  };
 
  fileSystems."/swap" = {
    device = "/dev/disk/by-label/NixOS-ROOT";
    fsType = "btrfs";
    options = [
      "subvol=swap"
      "noatime"
    ];
  };
 
  fileSystems."/boot" = {
    device = "/dev/disk/by-label/SYSTEM";
    fsType = "vfat";
    options = [
      "fmask=0077"
      "dmask=0077"
    ];
  };
# インストール
nixos-install

すべて完了したら,再起動してインストールしたNixOSを起動する.
正しくインストールできていれば,initプロセスの間にLUKSのPassphraseが聞かれる.

Secure Boot

NixOSでのSecure Bootには,Lanzabooteを利用する.Lanzabooteはドキュメントがしっかりしているので,ここで改めて書く必要もないが,掻い摘まんで書き起こしておく.

Lanzaboote QUICK START

Secure Boot Keyの作成

sbctlを使用してSecure Boot Keyを作成・管理する.

nix-shell -p sbctl
sudo sbctl create-keys

Lanzabooteの導入

Lanzabooteのドキュメントを参照.flakesかnivを使うことになる.flakesで導入するにはそもそもconfigurationをflakesで管理している必要があるが,この際にflakes管理にしてしまうとよい.

nixos-rebuild switchして再起動した後,stubが署名されているか確認する.

sudo sbctl verify

Dual Boot環境だとESPに大量のstubがあるため大量に未署名のものがリストされるが,無視でよい.
とりあえず以下のものが署名されていれば問題無い.

  • BOOTX64.EFI
  • nixos-generation-*.efi
  • systemd-bootx64.efi

Secure Bootの有効化

このSecure Bootでは, 自身で作成した独自のSecure Boot Keyを用いる(俗に言うCustom Modeというやつ).

まずはBIOSにてSecure BootをSetup Modeにする.これにより,独自の鍵をインポート可能な状態になる.
やり方はマシンベンダーによって様々だが,大抵は Setup ModeReset, Delete Secure Boot Key などの文言が書かれている.

その後NixOSを起動し,事前に作成していたSecure Boot Keyをインポートする.

sudo sbctl enroll-keys --microsoft

ここで,--microsoftを渡すことでMicrosoftのOEM Keyを一緒にenrollしている.BIOS側でMSのKeyを認めるオプションがない場合などは,ここでenrollしておかないとWindowsがSecure Boot Violationで起動不能となる(気がする).とりあえず何も考えずに付けておいて良いだろう.

enrollの際,efivarfsに書き込めずエラーとなるケースがある.その場合,エラーとなったファイルに対してchattrでアトリビュートを設定することで対処可能.

# このようなエラーとなる
 File is immutable: /sys/firmware/efi/efivars/KEK-hoge...
 File is immutable: /sys/firmware/efi/efivars/db-fuga...
You need to chattr -i files in efivarfs
sudo chattr -i /sys/firmware/efi/efivars/KEK-hoge...
sudo chattr -i /sys/firmware/efi/efivars/db-fuga...

bootctl statusでSeucre Bootがenabledとなっていれば完了.

System:
      Firmware: UEFI 2.70 (Dell 1.00)
 Firmware Arch: x64
   Secure Boot: enabled (deployed)
  TPM2 Support: yes
  Measured UKI: yes
  Boot into FW: supported

Current Boot Loader:
      Product: systemd-boot 257.6
     Features: ✓ Boot counting
               ✓ Menu timeout control
               ✓ One-shot menu timeout control
               ✓ Default entry control
               ✓ One-shot entry control
               ✓ Support for XBOOTLDR partition
               ✓ Support for passing random seed to OS
               ✓ Load drop-in drivers
               ✓ Support Type #1 sort-key field
               ✓ Support @saved pseudo-entry
               ✓ Support Type #1 devicetree field
               ✓ Enroll SecureBoot keys
               ✓ Retain SHIM protocols
               ✓ Menu can be disabled
               ✓ Multi-Profile UKIs are supported
               ✓ Boot loader set partition information
    Partition: /dev/disk/by-partuuid/85ceda52-3b90-47f9-b282-911d82317a29
       Loader: └─/EFI/systemd/systemd-bootx64.efi
Current Entry: nixos-generation-69-476cyowt6jzex6bdmu5y2tk7xm7vjrcpiyieoxlbisblk777e2yq.efi

Current Stub:
      Product: lanzastub 0.4.2
     Features: ✓ Stub sets loader partition information
               ✗ Picks up credentials from boot partition
               ✗ Picks up system extension images from boot partition
               ✗ Picks up configuration extension images from boot partition
               ✗ Measures kernel+command line+sysexts
               ✗ Support for passing random seed to OS
               ✗ Pick up .cmdline from addons
               ✗ Pick up .cmdline from SMBIOS Type 11
               ✗ Pick up .dtb from addons
               ✗ Stub understands profile selector
               ✗ Stub sets stub partition information
               ✗ Stub loader set partition information
...

TPMを用いたLUKSのアンロック

ここまで全ての設定が問題なくできていれば,以下のコマンドのみで完了する.

sudo systemd-cryptenroll --tpm2-device=auto --tpm2-pcrs=0+4+7 /dev/nvme0n1p5

--tpm2-pcrsで復号に使用するPCR Bankを指定している.どのBankを指定すべきかは想定する脅威によって異なるが,少なくともPCR[0](UEFI FW Code) とPCR[7](Secure Boot State) は指定しておくと良いだろう.各BankのUsageはArchWikiを参照するとよい.

再起動し,LUKSのPassphraseが要求されなければ設定完了.もしBootloaderのアップデートなどで状態が変化した場合は,再度同一のコマンドを実行すればOK.

Windows側の調整

NixOSでの全ての作業完了後,Windows側のセキュリティ設定を元に戻す.ここでは,WindowsをLanzabooteで導入したsystemd-boot経由で起動する想定である.

TPMの状態が変わるため,BitLockerが有効なままインストールを行った場合は回復キーを要求される.一時的に解除していた場合はここで再度有効化する.

また,Windows Helloの認証情報もTPMの状態の変化により使用不可能となるため,再設定が要求される.
MSアカウントに紐付いている場合,MSアカウント経由でPINの再設定となる.

The END

これにて完了.
セキュリティで固めたマシンを使っていると謎に優越感に浸れます(???)

Reference