ぶていのログでぶログ

思い出したが吉日

(Linux) ブート時の暗号ドライブの解除キー入力を1回にする

私の今の環境は、rootパーティションとswapパーティションの2つを暗号化している。 そうすると、起動時に解除キーの入力を2回若干煩わしい。 いい感じに回避する方法がないか検索したら、以下のサイトがヒットした。

unix.stackexchange.com

keyscript=decrypt_keyctl を使う

暗号ドライブを定義している /etc/crypttab に、 keyscript=decrypt_keyctl を追加する。 例えば、私の環境では以下のようになった。

❯ diff -u crypttab /etc/crypttab
--- crypttab    2021-02-11 22:17:32.696478795 +0900
+++ /etc/crypttab       2020-12-21 12:00:10.879134160 +0900
@@ -1,2 +1,2 @@
-nvme0n1p6_crypt UUID=43da95b3-6833-4888-b5f8-eb122992e78d none luks,swap,discard
-nvme0n1p7_crypt UUID=6cb13e8f-c7d0-49f9-a3b2-68b27ff98ee8 none luks,discard
+nvme0n1p6_crypt UUID=43da95b3-6833-4888-b5f8-eb122992e78d none luks,swap,discard,keyscript=decrypt_keyctl
+nvme0n1p7_crypt UUID=6cb13e8f-c7d0-49f9-a3b2-68b27ff98ee8 none luks,discard,keyscript=decrypt_keyctl

これだけではだめで、initramfsをアップデートする必要があるのだが、decrypt_keyctlスクリプトは内部的にkeyctlコマンドが必要で、このコマンドがないとupdate-initramfsがコケる。 そのため以下のコマンドでkeyctlコマンドをインストールする。

$ sudo apt install keyutils

最後にinitramfsをアップデートすれば次回の起動から反映される。

$ sudo update-initramfs -u

仕組み

decrypt_keyctl自体かなりシンプルなシェルスクリプトである。 keyctlコマンドを使って、特定のIDのキーが登録されていればそれを使い、登録されていなければパスワードを聞くという作りになっている。

keyctlコマンドのことを初めて知ったのだが、鍵管理ユーティリティらしい。 例えば、testというIDで鍵を登録するのは以下のようなコマンドになる。

$ PASSWORD=test
$ echo -n "$PASSWORD" | keyctl padd user test @u
353196000

コマンド実行後に出力される数字は登録した鍵の識別子になる。 取り出す場合はkeyctl pipe を使う。

$ keyctl pipe 353196000
test

実際に、どういう仕組みになっているのか気になってstraceしてみた。

$ strace keyctl pipe 353196000
-- snip --
keyctl(KEYCTL_READ, 353196000, "test\n", 5) = 5 👈 これ
write(1, "test\n", 5)                   = 5
exit_group(0)                           = ?
+++ exited with 0 +++

どうやらkeyctlというシステムコールを読んでいるようだ。 Linuxカーネルにこういう機能もあるんだなぁ。

man7.org

まとめ

keyctlを使うことでブート時の暗号ドライブの解除キー入力を1回にできる。 対象のドライブが2つくらいだとそこまで手間は減らないかもしれないが、たまに2回目の入力をミスってエラーになりイラッとすることがあるので、少しでも便利すると精神が安定する。

実は1年くらい前に同じネタを書こうと思って下書きを書いていたのだがそちらはお蔵入りになった。 お蔵入りになった理由は古すぎて腐ったのもあるのだが、decrypt_keyctlを使わずにdecrypt_derivedを使っていた。 こちらは、共通鍵を追加することで、最初に解除したドライブに登録された鍵を使って2つ目のドライブを解除するようなスクリプトになっている。 こちらを使わなかったというより、Ubuntu20.04から使えなくなった*1っぽいので、今回の手法に変更した。 まぁ、decrypt_keyctlのほうが手間がかからずに導入できるので結果オーライである。

unix.stackexchange.com

*1:/lib/cryptsetup/scripts/decrypt_derived <crypt_drive> するとエラーになる