ストレージの暗号化は実施して当然のセキュリティ対策のひとつとなりつつあります。一般的なスマートフォンであればほぼ暗号化された状態ですし、WindowsやmacOSでも暗号化するための設定が用意されています。たとえばWindowsの場合、PCの購入時点で暗号化がオンになっているケースもあります。サーバーも用途によっては暗号化したい場合もあるでしょう。
ここで問題になるのが、どのようにしてストレージ復号用のパスフレーズを入力するのか、です。今回はUbuntuのルートファイルシステムを暗号化した上で、起動時にリモートからSSH経由でストレージの復号する方法を紹介しましょう。
ストレージ暗号化における復号の手間と意味
Ubuntu自体は10年以上前から、インストール時にストレージを暗号化するオプションが提供されていました。現在はその手法としてLVMとLUKSを利用したLinuxにおける一般的な暗号化ストレージのシステムを採用しています。つまりシステムの起動時に、事前に設定されたパスフレーズを入力しないと、そのストレージはマウントできず、ストレージやPCが盗難されたとしてもおいそれとは中身を見られないようにできます。
Ubuntu 23.
TPMによる自動復号は、便利ではありますがセキュリティ上正しい対応かどうかは個々の使い方において検討が必要です。たとえば可搬性のノートPCの場合、ストレージだけ抜き取られて盗難されることは少なく、PCごと盗まれる可能性のほうが高いです。また、それ以上に懸念しなくてはならないのが、出先での紛失でしょう。TPMによる自動復号が有効化されている場合、ノートPCを入手した人は、電源を入れるだけで復号まではできてしまいます[2]。
特にLinuxの場合、物理的なデバイスにアクセスできる状態であれば、このあたりの暗号化が意味をなさなくなります。電源さえ入ればGRUBメニューからカーネルの起動オプションを変更し、管理者権限を取得できてしまうからです。これを防ぐとなるとGRUBやUEFI/
管理するパスワードが増えてしまうとそれはそれで煩雑です。そうすると結果的にTPMによる自動復号をやめて、毎回パスフレーズを入力するのが一番無難ではないか、との意見が出てきます。そこで問題になってくるのが
たとえばサーバーであればIPMIや各種リモート管理システムを使うことで、起動時のコンソールの取得は可能です。しかしながらノートPCやデスクトップPCの場合は、それらの機能を備えていないことのほうが多いでしょう。起動時にファイルシステムをマウントする前にアクセスするためのソフトウェア的な手段が必要となります。Ubuntuを含むLinuxにおいては、次のいずれかを使うことが一般的です。
- initramfsの中でSSHサーバーを動かし、リモートからログインする
- 起動時に特定のサーバーへアクセスし、そこから復号用のパスフレーズを取得する
前者はシンプルな方法です。SSH経由でセキュアにアクセスできれば、あとはCLIから復号してマウントするコマンドを実行するだけです。軽量なSSHサーバーである
後者はより複雑な仕組みではありますが、固定のIPアドレスが不要で、ユーザーにとっては手間がかからない仕組みです。たとえば社内ネットワーク内にのみ公開されているサーバーにアクセスしパスフレーズを取得できるようにしておけば、社内ネットワークで起動した場合のみ自動復号する仕組みを実現できます。この用途には
今回はまずUbuntuのストレージ暗号化の手順と、dropbearを使った復号方法について紹介します。
Ubuntuデスクトップにおけるストレージ暗号化
最初にUbuntuにおいてストレージを暗号化する方法を紹介しましょう。Ubuntuの場合、暗号化するかどうかは
UbuntuではZFSを利用した暗号化もサポートしています。ZFSに興味があればそちらを使ってみても良いでしょう。さらに
ここで入力したパスフレーズが、起動時に毎回入力するパスフレーズとなります。このパスフレーズを忘れると、2度とストレージの中身を参照できなくなりますので注意してください。ちなみに入力時点でキーボードレイアウトは自動的に設定されますので、空白を含む印字可能な記号類なども利用可能です。ただし急遽英語キーボードを使わなくてはならなくなったものの、パスフレーズは体で覚えていたなんてケースだと苦労します。それよりもパスフレーズをより長くしておくことが重要です。そのことを踏まえてパスフレーズを決めると良いでしょう。
旧版のインストーラーでは、暗号化ストレージのパスフレーズだけでなく、リカバリーキーの設定も行われていました。Ubuntu 24.cryptsetup luksAddKey
」
無事にインストール完了したら、再起動してみましょう。通常の起動とは異なり、GRUBメニューが表示されたあとにパスフレーズ入力画面が登場します。
パスフレーズの検証に成功し、ストレージがマウントされてログインすると、次のようなストレージの構成になっていることがわかります。
$ lsblk -i (中略) sda 8:0 0 50G 0 disk |-sda1 8:1 0 1G 0 part /boot/efi |-sda2 8:2 0 2G 0 part /boot `-sda3 8:3 0 46.9G 0 part `-dm_crypt-0 252:0 0 46.9G 0 crypt `-ubuntu--vg-ubuntu--lv 252:1 0 46.9G 0 lvm /
第一パーティション
ちなみにUbuntuの暗号化ストレージの文脈では次のような用語が登場します。
- LUKS
(Linux Unified Key Setup) :Linuxにおいてストレージを暗号化するために作られた仕様。暗号化用のメタデータ(復号用の鍵領域等) を保存する方法などがまとめられている。LUKS1とLUKS2が存在するが、Ubuntuだと基本的にLUKS2を使うことになる。 - cryptsetup:LUKSを含む様々な仕様の暗号化ストレージを操作するためのCLIツールとライブラリ。ユーザーは基本的にこのcryptsetupコマンドを使って操作する。
- dm-crypt:暗号化ストレージを構築するためのカーネル側の仕組み。
UbuntuでLVMベースの暗号化ストレージを使う場合は、これらの仕組みを構築して利用します。ただし日常的な利用においてこれらを意識する必要はなく、パスフレーズを追加したり、何かトラブルが発生したときに
たとえば現在の暗号化ストレージの状態は次のコマンドで確認できます。
$ sudo cryptsetup luksDump /dev/sda3 LUKS header information Version: 2 Epoch: 3 Metadata area: 16384 [bytes] Keyslots area: 16744448 [bytes] UUID: bc557732-a807-4e31-9bdf-5811b90fd96a Label: (no label) Subsystem: (no subsystem) Flags: (no flags) Data segments: 0: crypt (中略) Keyslots: 0: luks2 Key: 512 bits Priority: normal Cipher: aes-xts-plain64 Cipher key: 512 bits PBKDF: argon2id Time cost: 60 Memory: 94082 Threads: 2 (中略) Tokens: Digests: 0: pbkdf2 Hash: sha256 (中略)
ここではLUKSのメタデータから、鍵の数を含むさまざまな情報が得られます。もし鍵を追加した場合は、
これでUbuntuにおける暗号化ストレージの準備は完了です。
dropbearのインストールと設定
システム起動時は常にパスフレーズを入力しなくてはなりません。つまりPCの前にいる必要があります。これはこれでセキュリティの担保になるのですが、リモート接続するマシンだと不便です。たとえばWake on LANでマシンを起動しても、パスフレーズ入力のためにマシンの前に移動しなくてはならないのだとしたら、普通に電源を押しに行くのと変わらなくなってしまいます。
そこでPCが起動したら、ストレージをマウントする前にSSHサーバーを起動し、リモートからログインしてパスフレーズを入力するように変更してみましょう。これには軽量なSSHサーバーである
Ubuntuを含む一般的なLinuxシステムは、
- ブートローダーはカーネルとinitramfsをメモリにロードし、カーネルの実行を開始する
- カーネルはブートローダーから渡されたinitramfsの位置を元に内容をメモリ上に展開し、それを小さなルートファイルシステムとして扱う
- その中にシステム初期化用のスクリプトがあるのでカーネルはそれを実行する
- 初期化スクリプトの中で、本来のルートファイルシステムに対して適切なカーネルモジュールをロードし、準備し、ルートファイルシステムをマウントする
- ルートファイルシステムにあるinit
(Ubuntuだとsystemd) が実行される
暗号化ストレージをマウントするためにパスフレーズを入力するのは4のタイミングです。よってinitramfsの中にSSHサーバーをインストールし、4のスクリプト実行の途中でこれを起動すれば良いことになります[3]。
initramfsの中でちょっとログインしてコマンドを一個打つだけなので、OpenSSHほど高機能でなくてもかまいません。よってdropbearを使うことが一般的です。幸い、Ubuntuの場合は
早速dropbear-initramfsをインストールしてみましょう。
$ sudo apt install dropbear-initramfs (中略) Generating Dropbear RSA host key. Please wait. (中略) Generating Dropbear ECDSA host key. Please wait. (中略) Generating Dropbear ED25519 host key. Please wait. Generating 256 bit ed25519 key, this may take a while... 256 SHA256:6Aeq3rYPTb7jrz/zOwvbGYw0obqKUgt3qkjsH+5DBCo /etc/dropbear/initramfs/dropbear_ed25519_host_key (ED25519) (中略) update-initramfs: deferring update (trigger activated) Dropbear has been added to the initramfs. Don't forget to check your "ip=" kernel bootparameter to match your desired initramfs ip configuration. (中略) update-initramfs: Generating /boot/initrd.img-6.8.0-44-generic dropbear: WARNING: Invalid authorized_keys file, SSH login to initramfs won't work!
ここで表示されているログのポイントは4点です。
- SSHサーバー用のホスト鍵が
/etc/
以下に生成されていることdropbear/ initramfs/ - dropbearのIPアドレスを固定化するためには、カーネルの起動パラメーターに
「 ip=
」を設定しなくてはならないこと update-initramfs
が実行され、initramfsが再生成されていること- dropbearにSSHログインするためには、initramfsの中に
authorized_
を設定しなくてはならないことkeys
2番目と4番目については対応が必要であるため、このあとの手順で見ていきます。先にインストールされたものについて確認しましょう。まずdropbear本体は165KiBととても小さなバイナリです。
$ ls -lh /usr/sbin/dropbear -rwxr-xr-x 1 root root 165K 1月 25 2024 /usr/sbin/dropbear
dropbear関連の設定ファイルはいくつかありますが、主要なものは次のファイルでしょう。
/etc/
dropbear/ initramfs/ dropbear. conf - dropbearの起動オプションや終了時にリンクダウンするネットワークインターフェースを設定するファイルです。特にdropbearの待受ポート番号を変更したければ、このファイルで設定することになります。
/usr/
share/ initramfs-tools/ hooks/ dropbear update-initramfs
実行時に呼ばれるファイルです。dropbearを動かすための設定ファイル・鍵ファイルをinitramfsにコピーしています。特に重要なのは authorized_
でしょう。keys /etc/
が存在すれば、それをコピーします。なければdropbear/ initramfs/ authorized_ keys /etc/
をコピーします。それらの公開鍵に紐付いた秘密鍵でのみログインできます。ちなみにログイン時のアカウントはdropbear/ initramfs/ id_鍵の種別.pub 「root」 です。 /usr/
share/ initramfs-tools/ scripts/ init-premount/ dropbear - initramfsの中でdropbearを起動する部分のスクリプトです。ルートファイルシステムのマウント処理に入る前に、ネットワーク設定を行い、dropbearを起動します。もし割り当てられたIPアドレスをどこかに通知するのであれば、このスクリプトを
「/etc/ initramfs-tools」 以下の同名のパスに配置し、それをカスタマイズすることになります。このファイルを直接編集してしまうと、パッケージ更新時に元に戻ってしまう可能性があるので注意してください。 /usr/
share/ initramfs-tools/ scripts/ init-bottom/ dropbear - initramfsの中でマウント完了後にdropbearを終了するスクリプトです。
最低限必要な設定はauthorized_
の準備」
また、dropbearのポート番号の変更も検討すべき内容です。というのも、もし固定IPアドレスをPCに割り振る場合、dropbearが動く場合と、PCが起動したあとで同じIPアドレスを使いまわす可能性があるからです。このときPC側でSSHサーバーが起動した状態で、SSHログインしようとすると、dropbearのホストキーとPCのSSHサーバーのホストキーが異なるため、~/.ssh/
」
ポート番号を変えたければ/etc/
を次のように修正してください。
# Command line options to pass to dropbear(8)
#
#DROPBEAR_OPTIONS=""
DROPBEAR_OPTIONS="-p 2222"
あとはauthorized_
を準備します。たとえばGitHubにアップロードしている公開鍵のリストを取得したければ次のような手順になります。
wgetの場合: $ wget https://github.com/m-shibata.keys -qO authorized_keys curlの場合: $ curl https://github.com/itiut.keys -o authorized_keys
取得したauthorized_
を適切な場所にコピーして、initramfsを更新します。
$ sudo cp authorized_keys /etc/dropbear/initramfs/authorized_keys $ sudo update-initramfs -u -k all
最後の-k all
」
これで準備は完了です。PCを再起動してみましょう。
dropbearでログインした環境から復号コマンドを実行
再起動後に少し待てばパスフレーズの入力画面が表示されます。何らかの方法でIPアドレスを確認して、SSHログインしてください。IPv6対応環境であれば再起動前のIPv6アドレスがそのまま使えるはずです。
$ ssh -p 2222 root@192.0.2.100 (中略) BusyBox v1.36.1 (Ubuntu 1:1.36.1-6ubuntu3.1) built-in shell (ash) Enter 'help' for a list of built-in commands. #
うまくBusyBoxシェルになったら成功です。なお、-p 2222
」~/.ssh/
の更新を防げます。
$ ssh -p 2222 -o StrictHostKeyChecking=no \ -o UserKnownHostsFile=/dev/null root@192.0.2.100
このあたりは使い方に応じて変化させれば良いでしょう。
ちなみにログイン先のホームディレクトリはinitramfs用に一時的に作成したものとなります。
# pwd /root-sDDs0Edbqo # ps (中略) 264 root 110m S /usr/sbin/plymouthd --mode=boot --attach-to-session --pid-file=/run/plymouth/pid 268 root 4700 S /sbin/dropbear -Fs 275 root 3124 S {cryptroot} /bin/sh /scripts/local-top/cryptroot 326 root 4700 R /sbin/dropbear -Fs -2 8 327 root 2984 S -sh 1910 root 2688 S /lib/cryptsetup/askpass Please unlock disk dm_crypt-0: 1911 root 3124 S {cryptroot} /bin/sh /scripts/local-top/cryptroot 1912 root 11684 S /sbin/cryptsetup -T1 --type=luks --key-file=- open -- /dev/sda3 dm_crypt-0 1914 root 3764 S /bin/plymouth ask-for-password --prompt Please unlock disk dm_crypt-0 2171 root 2984 R {ps} -sh # cat /run/net-enp5s0.conf DEVICE='enp5s0' PROTO='dhcp' IPV4ADDR='192.0.2.100' IPV4BROADCAST='192.0.2.255' IPV4NETMASK='255.255.255.0' IPV4GATEWAY='192.0.2.1' IPV4DNS0='192.0.2.1' HOSTNAME='fde' DNSDOMAIN='lxd' ROOTSERVER='192.0.2.1' filename='' DHCPLEASETIME='3600' DOMAINSEARCH=''
プロセスとしてはdropbearが起動したあとに、/scripts/
が起動しています。このcryptrootスクリプトからaskpass
」
ちなみに今回はIPアドレスを指定していないために、ネットワークインターフェースはDHCPでアドレスを取得しています。
さて、無事にログインできた状態でやるべきことはcryptroot-unlock
」
# cryptroot-unlock Please unlock disk dm_crypt-0: パスフレーズの入力 cryptsetup: dm_crypt-0 set up successfully # Connection to 192.0.2.1 closed by remote host. Connection to 192.0.2.1 closed.
パスフレーズを入力して問題なければset up successfully
」init-bottom/
」closed by remote host
」
これで最低限リモートからストレージの復号を行えるようになりました。
IPアドレスの固定化
ここまでの手順では、dropbearが起動したときのネットワークインターフェースに割り振られたIPアドレスを、何らかの方法で取得する必要がありました。これは環境によってはとても面倒ですので、IPアドレスを固定化してしまいましょう。
しかしながらnetplanなどはまだ起動していないために、普通の方法では静的なIPアドレスを割り振れません。そこでカーネルパラメーターにIPアドレスの情報を記載します。これはNFS向けの仕組みなのですが、IPアドレスを割り振る部分については別にNFS使わなくても利用可能です。実際のところは指定されたパラメーターのうち必要なフィールドを、initramfsの中で使用しているだけです。
具体的にはGRUBの設定でカーネルのパラメーターを記載します。GRUBの設定については第743回の
具体的には/etc/
を次のように変更します。
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"
#GRUB_CMDLINE_LINUX=""
GRUB_CMDLINE_LINUX="ip=192.0.2.100::192.0.2.1:255.255.255.0:fde:enp5s0:none"
ここでip=
」
ip=自装置に割り当てたいIPアドレス:NFSサーバーのIPアドレス:ゲートウェイ:ネットマスク:ホスト名:インターフェース名:自動設定方法
さらに後ろに設定をつなげることも可能ではありますが、今回は使用しません。NFSサーバーのIPアドレスも関係ないので空にしてあります。複数のネットワークインターフェースがある場合は、インターフェース名を明記しましょう。単一の場合は入力しなくても大丈夫です。自動設定方法はDHCPやBOOTPを使用したい場合に設定します。今回は固定のIPアドレスを割り振るために
ちなみにこの仕組みはIPv6には未対応です。IPv6アドレスについてはRAやDHCPv6側でなんとかすることになります。
あとはこの設定を反映し、再起動するだけです。
$ sudo update-grub
IPアドレスが期待どおりに設定されているかを確認してください。もしうまく動かない場合は、BusyBoxシェルの中で/run/
」
ここまでの手順により、暗号化されたストレージを起動時にリモートからでも復号できるようになりました。今回はUbuntuデスクトップベースで説明しましたが、この方法はUbuntuサーバーでも問題なく利用できます。
ちなみに特定のネットワークに接続した状態で起動したときは、自動的に復号したいのであれば、前述したようにTangサーバーを使う方法が存在します。これはまた別の機会に紹介する予定です。