NixOSでセキュアブートを設定する

以前Arch Linuxでは、セキュアブートを設定していたので、NixOSでも設定しました。 NixOSでセキュアブートを構成する方法は、nix-community/lanzabooteを使う方法が一般的なそうなので、それに従って行いました。

方針としては、基本的には以前Arch Linuxで行なったやり方である、sbctlによる方法です。 lanzabooteの特徴は、カーネル、initrd,カーネルコマンドラインをバンドルした*.efiなファイルであるユニファイドカーネルイメージ(UKI)を作成し、それを署名することでセキュアブートを実現しています。 この方法では、単に、カーネル、ブートローダーに署名する方法ではできなかった、initrdの改竄を検出することができるためよりセキュアな環境を実現可能です。

鍵の操作

sbctlによる鍵の作成

まず、sbctlをインストールします。

nix-shellで一時的に導入するのでも良いですが、今後もトラブルシューティングや確認などで使用することが見込まれるため、以下のようにグローバルにインストールしました。

1
2
3
4
environment.systemPackages = with pkgs; [
  # For debugging and troubleshooting Secure Boot.
  sbctl
];

続いて、sbctl create-keysで鍵を作成します。

1
sudo sbctl creat-keys

鍵の作成は特に問題なく完了しました。

作成された鍵は/var/lib/sbctlに保存されていました。 この鍵の保存先は後ほど必要なので、メモしておきましょう。

作成した鍵のenroll

今回は、前回のArch Linuxで設定した時に作成した鍵は削除して、新たに鍵を作成&登録しました。

まず、マシンのUEFI-BIOSに入って、secure-bootをセットアップモードにします。 この時に前回登録した鍵が削除されました。

その後で再起動して、以下のコマンドで鍵をします。

1
sudo sbctl enroll-keys -m # '-m' を絶対に忘れるな!

ここで、-mオプションはマイクロソフトの鍵を消さずに自分で生成した鍵を追加するようすることを意味します。 これを忘れると、マイクロソフトの鍵で署名された一部のデバイスドライバが読めなくなって最悪の場合ではマシンが文鎮化する恐れがあるので絶対に忘れないようにしましょう。

鍵を追加しようとしたところ以下のようなエーラーが出ました。

1
2
3
‼ File is immutable: /sys/firmware/efi/efivars/KEK-8be4df61-93ca-11d2-aa0d-00e098032b8c
‼ File is immutable: /sys/firmware/efi/efivars/db-d719b2cb-3d3a-4596-a3bc-dad00e67656f
You need to chattr -i files in efivarfs

どうやら書き込みしたいファイルがイミューダブルなのでミューダブルになるようにしろとのことなので以下のようにしてミューダブルにしました。

1
2
sudo chattr -i /sys/firmware/efi/efivars/KEK-8be4df61-93ca-11d2-aa0d-00e098032b8c
sudo chattr -i /sys/firmware/efi/efivars/db-d719b2cb-3d3a-4596-a3bc-dad00e67656f 

この後で再び鍵の追加を行うと無事成功しました。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
sudo sbctl enroll-keys -m # '-m' を絶対に忘れるな!
Enrolling keys to EFI variables...
With vendor keys from microsoft...✓
Enrolled keys to the EFI variables!
sbctl status
Installed:      ✓ sbctl is installed
Owner GUID:     541a99e4-09dd-4990-99ca-dd8bb4b254ec
Setup Mode:     ✓ Disabled
Secure Boot:    ✗ Disabled
Vendor Keys:    microsoft

lanzabooteの設定

とりあえず設定する

以下のlanzabooteのガイドに従って設定しました。flakeを使う方法と使わない方法がありますが、 筆者のNixOSの設定はflake化済みなので前者を採用しました。

筆者の元の設定aki-ph-chem/nix(まだ、セキュアブートの設定がされていない状態のコミット)に以下のように設定を追加しました。

まず以下の内容で、flakelanzabooteを導入して利用できるようにします。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
diff --git a/flake.nix b/flake.nix
index 18bf060..221cc50 100644
--- a/flake.nix
+++ b/flake.nix
@@ -9,6 +9,14 @@
       inputs.nixpkgs.follows = "nixpkgs";
     };
     nixgl.url = "github:nix-community/nixGL";
+
+    # for secure-boot
+    lanzaboote = {
+      url = "github:nix-community/lanzaboote/v0.4.3";
+      # Optional but recommended to limit the size of your system closure.
+      inputs.nixpkgs.follows = "nixpkgs";
+    };
+
     # GitHub: aki-ph-chem/dotfiles
     dotfiles = {
       url = "github:aki-ph-chem/dotfiles/main";
@@ -19,6 +27,7 @@
   outputs =
     {
       nixpkgs,
+      lanzaboote,
       home-manager,
       nixgl,
       dotfiles,

続いて以下でlanzabooteの設定をします。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
diff --git a/hosts/nixosSwayLaptop/default.nix b/hosts/nixosSwayLaptop/default.nix
index 855f6cb..2b361ac 100644
--- a/hosts/nixosSwayLaptop/default.nix
+++ b/hosts/nixosSwayLaptop/default.nix
@@ -5,6 +5,7 @@
 let
   inherit (inputs)
     nixpkgs
+    lanzaboote
     home-manager
     self
     dotfiles
@@ -20,6 +21,18 @@ nixpkgs.lib.nixosSystem {
   inherit pkgs;

   modules = [
+    lanzaboote.nixosModules.lanzaboote
+    (
+      { pkgs, lib, ... }:
+      {
+        boot.loader.systemd-boot.enable = lib.mkForce false;
+
+        boot.lanzaboote = {
+          enable = true;
+          pkiBundle = "/var/lib/sbctl";
+        };
+      }
+    )
     {
       imports = [
         (import "${flakeRoot}/nixos/fonts" { inherit pkgs; })
@@ -85,7 +98,6 @@ nixpkgs.lib.nixosSystem {
       ];

       # Use the systemd-boot EFI boot loader.
-      boot.loader.systemd-boot.enable = true;
       boot.loader.efi.canTouchEfiVariables = true;
       boot.kernelPackages = pkgs.linuxPackages_latest; # Use latest kernel.

pkiBundleには、sbctlで生成された鍵が保存されたディレクトリである/var/lib/sbctlを指定しています。

また、boot.loader.systemd-boot.enableは以下のように変更しています。 この設定はデフォルトのsystemd-bootのモジュールを置き換えること意味します。

1
boot.loader.systemd-boot.enable = lib.mkForce false;

ここまで設定したものをビルドして適用しました。 Rustのビルドが走るようで結構時間がかかりました。

1
sudo nixos-rebuild switch --flake .#nixosSwayLaptop --impure

これで、UKIの作成と署名が行われたはずなので、以下で確かめてみます。

1
sudo sbctl verify

kernel-から初まるものは署名されず、*.efiなファイルが署名されている状態になるはずです というのも、カーネルを署名するのではなく、UKIを作成してそれに署名しているからです。

最後にシャットダウンして、UEFI-BIOからsecure-bootを再度有効化してちゃんと起動したら成功です。

保存しておく世代について

ここまでで、セキュアブートは設定できました。

しかし、構成の変更で生成されたNixOSの世代が全て署名されて/bootが圧迫されてしまいます。 しかも、通常のガベージコレクタの操作をしても削除されません。

そこで、lanzabooteのリポジトリのうち以下を見るとboot.lanzaboote.configurationLimitで残しておく世代を設定できることが分りました。

今回は7世代まで残すことにして以下のように設定しました。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
diff --git a/hosts/nixosSwayLaptop/default.nix b/hosts/nixosSwayLaptop/default.nix
index c4a1256..dff34b5 100644
--- a/hosts/nixosSwayLaptop/default.nix
+++ b/hosts/nixosSwayLaptop/default.nix
@@ -54,6 +54,8 @@ nixpkgs.lib.nixosSystem {
         boot.lanzaboote = {
           enable = true;
           pkiBundle = "/var/lib/sbctl";
+          # see https://github.com/nix-community/lanzaboote/blob/master/nix/modules/lanzaboote.nix
+          configurationLimit = 7;
         };
       }
     )

これで/bootを圧迫する問題を解決できました。

同居(別のディスクからデュアルブートしている)windowsの様子は?

このセキュアブートを設定してから同居(dual-boot)しているbitlockerを適用したwindowsを起動したところセキュアブートのポリシーが変ったようで回復キーを求めました。

一旦そのキーを入れたら、何度か windows <-> Linuxと行き来しましたが、以降問題なく起動するようになりました。

最後に

前回のLUKSによるディスク暗号化に続いて、セキュアブートまで設定できました。

1度、sbctlによる方法でセキュアブートを設定したことはありますが、鍵関係の操作は相変わらず緊張しますね。

また、執筆中に発見したのですが、sbctlを使って自分で署名する方法は、ハードウェアによっては使えないケースがあるようです。

CC BY
Hugo で構築されています。
テーマ StackJimmy によって設計されています。