FedoraサーバーをLUKS暗号化ディスクで運用するのは、最初から当然の選択だった。物理盗難時のデータ保護は最低限の要件――交渉の余地はない。しかしリブートが必要になると問題が生じる:コンソールかdropbear経由のSSHで手動パスフレーズを入力しなければならず、誰も常駐していない場合は非常に不便だ。調べていくうちに、ClevisとTangを組み合わせたNBDEがまさにこの問題を解決することがわかった――安全なローカルネットワーク内で起動時にディスクを自動アンロックしてくれる。
このセットアップをhomelabで6ヶ月間運用した後、2台のプロダクションサーバーに適用した。この記事は、つまずいた箇所も含めて、実際に行ったことをそのまま記録したものだ。
NBDEの仕組み
NBDE(Network-Bound Disk Encryption)は「ネットワークに紐付いた」ディスク暗号化モデルだ――Tangサーバーがあるローカルネットワークに接続している時だけ、ディスクが自動アンロックされる。ネットワーク外に持ち出したり、ケーブルを抜いたりすれば――ディスクは完全に保護されたままだ。
主要な3つのコンポーネント:
- Tang:シンプルなHTTPサーバーで、ディスクアンロック用のキーマテリアルを提供する。TangはクライアントのシークレットをいっさいI保存しない――McCallum-Relyeaプロトコルに基づいた設計だ。
- Clevis:LUKSと統合するクライアントサイドのツール。ClevisはディスクをTangサーバー(またはTPM、あるいはその両方の組み合わせ)に「ピン」し、起動時の自動アンロックを処理する。
- LUKS:Linuxのディスク暗号化機能で、複数のキースロットをサポートする――Clevisは元のパスフレーズに触れることなく、新しいキースロットを追加する。
重要なポイント:TangはLUKSパスフレーズを知らない。アンロックプロセスはECDH(楕円曲線Diffie-Hellman)を使用する――Tangはネットワーク上で「存在して応答する」だけでよい。シークレットの保存なし、集中的な漏洩ポイントなし。
環境の準備
同じLANネットワーク内の2台のマシンを使用する:
- Tangサーバー:Fedora Server、IP
192.168.1.10――Raspberry Pi、VM、あるいはローカルネットワーク内の古いマシンでも構わない。 - クライアント:LUKSディスクを持つFedora Workstation/Server、IP
192.168.1.20。
要件:Fedora 36以上(筆者はFedora 40を使用)、既にLUKS暗号化済みのディスク、同一サブネット内の2台のマシン。
Tangサーバーのインストール
Tangサーバー(192.168.1.10)で:
sudo dnf install tang -y
sudo systemctl enable --now tangd.socket
Tangはソケットアクティベーション経由で動作する――常駐サービスは不要で、リクエストが来た時だけ「起動」する。デフォルトでポート7500をリッスンする。
Tangのファイアウォールを開放する:
sudo firewall-cmd --add-service=tangd --permanent
sudo firewall-cmd --reload
クライアントマシンから、Tangが動作しているか素早くテストする:
curl http://192.168.1.10:7500/adv
payloadフィールドを含むJSONが返ってくれば、Tangが正しく動作している。これはadvertisement――Clevisがバインディングに使うTangサーバーの公開鍵だ。
TangのThumbprintを取得する
Thumbprintはバインディング時にTangサーバーを検証するために使用し、中間者攻撃を防ぐ。Tangマシン上で実行する:
sudo tang-show-keys
出力は3DqH5h1TxhJGRD9pZm...のようなbase64文字列だ。メモしておく――バインドのステップで必要になる。
クライアントへのClevisのインストール
クライアントマシン(192.168.1.20)で、Clevisとdracutモジュールをインストールしてinitramfsに統合する:
sudo dnf install clevis clevis-luks clevis-dracut -y
LUKSディスクをTangにバインドする
LUKSパーティションを特定する:
lsblk -f | grep crypto_LUKS
パーティションが/dev/sda2だとする。Tangにバインドする際、thumbprintは先のステップで取得した値に置き換える:
sudo clevis luks bind -d /dev/sda2 tang '{"url":"http://192.168.1.10:7500","thp":"3DqH5h1TxhJGRD9pZm"}'
Clevisが新しいキースロットを追加するためにLUKSパスフレーズを求めてくる――入力すれば完了だ。元のパスフレーズはそのまま残る。Clevisは新しいスロットを追加するだけで、既存のものは削除しない。
バインド後のキースロットを確認する:
sudo cryptsetup luksDump /dev/sda2 | grep -E "Keyslot|ENABLED"
initramfsの再生成――最も忘れがちなステップ
バインドが完了したら、すぐにinitramfsを再生成しなければならない――このステップを飛ばすとClevisが起動時に実行されない:
sudo dracut --force
最初にまさにここでつまずいた――バインドは完了したがdracutを忘れ、リブートしても従来通り手動でパスフレーズを入力しなければならなかった。原因を突き止めるのに30分かかった。
initramfs内のネットワーク設定
ここには微妙な問題がある:クライアントはTangサーバーに接続するためにネットワークが必要だが、ルートファイルシステムはLUKSでロックされている――先にアンロックしなければならない。古典的な「鶏と卵」問題だ。clevis-dracutはネットワークスタックをinitramfsに直接組み込むことでこれを解決する。
initramfs内でネットワークを有効にするカーネルパラメータを追加する(DHCP):
sudo grubby --update-kernel=ALL --args="rd.neednet=1 ip=dhcp"
スタティックIPを使用する場合(サーバーでは一般的):
sudo grubby --update-kernel=ALL --args="rd.neednet=1 ip=192.168.1.20::192.168.1.1:255.255.255.0:myhostname:eth0:none"
新しい設定を反映するためにinitramfsを再度生成する:
sudo dracut --force
本番リブート前のテスト
バインディングを確認するために手動アンロックする――Tangが動作していればパスフレーズは不要だ:
sudo clevis luks unlock -d /dev/sda2
パスフレーズを求めてこなければ、セットアップは正しい。この時点で本番リブートをしても安全だ。
Tangサーバーが利用できない場合の対処
プロダクションデプロイ前に最も心配だった質問:Tangサーバーがダウンした時、クライアントマシンは起動できるのか?
答えは:起動できる、ただし手動でパスフレーズを入力する必要がある。Clevisはinitramfsでタングへの接続を試み、約30秒後にタイムアウトし、LUKSパスフレーズの入力プロンプトにフォールバックする。元のパスフレーズは正常に機能する。
Tangがダウンしている時に黒い画面を30秒眺めながら待つのはかなり不快だ。タイムアウトを短縮する:
sudo grubby --update-kernel=ALL --args="rd.clevis.tang.timeout=10"
sudo dracut --force
Tangキーの定期ローテーション
約6ヶ月ごとに、キーが漏洩した場合のリスクを減らすためにTangキーをローテーションすることを推奨する。Fedora 40はTang 14以上を使用しており、tangd-keygenコマンドはもはや存在しない。キーはサービスの初回起動時に自動生成され、/var/db/tang/に保存される。
jose(tangパッケージに付属)で新しいkey exchangeを追加し、サービスをリロードする:
# 現在のキーを確認
ls /var/db/tang/
sudo tang-show-keys
# 新しいkey exchangeを生成
sudo jose jwk gen -i '{"alg":"EC","crv":"P-521","key_ops":["deriveKey"]}' \
| sudo tee /var/db/tang/rotate-exc.jwk > /dev/null
sudo systemctl reload tangd.socket
各クライアントで、新しいキーにre-bindする(SLOTはClevisが使用しているキースロット番号に置き換える):
# Clevisが使用しているスロットを確認
sudo clevis luks list -d /dev/sda2
# そのスロットをre-bind
sudo clevis luks regen -d /dev/sda2 -s SLOT
sudo dracut --force
古いキーは手動で削除するまで/var/db/tang/に残る――まだre-bindしていないクライアントが引き続き機能するためのセーフティネットとして機能する。
6ヶ月間で学んだこと
NBDEの優れた点は、セットアップが完了したら気にしなくていいことだ――サーバーはカーネルアップデート後に自動リブートし、深夜にパスフレーズを入力するために起きている必要がない。運用面で最も満足していることだ。
実際の運用を通じて学んだいくつかのこと:
- TangサーバーはクライアントよりもI先に起動しなければならない:停電後に両方が同時にリブートすると、クライアントはタイムアウトして手動パスフレーズが必要になる。TangマシンへのUPSは価値ある投資だ。
- Tangのアップタイムを別途監視する:Uptime KumaにシンプルなHTTPチェックを追加した――Tangがダウンするとすぐにアラートが来て、そのタイミングでクライアントサーバーがリブートしないようにできる。
- Tangは必ず別のマシンに置く:当たり前に聞こえるが、それでも聞かれることがある。TangとクライアントをI同じマシンに置くと、暗号化の意味が完全に失われる。
- 定期的にフォールバックをテストする:毎四半期、Tangサーバーをシャットダウンしてクライアントをリブートし、フォールバックパスフレーズが機能することを確認している。本当に必要な時になって、パスフレーズを忘れていたことに気づかないようにしよう。
まとめ
ClevisとTangを使ったNBDEは、両方を同時に実現させてくれる:十分強力なディスク暗号化と、リブートのたびにパスフレーズを入力しなくてよい利便性。トレードオフはTangサーバーの可用性への依存だが――フォールバックパスフレーズは引き続き機能するため、このリスクは許容範囲内だ。
スタック全体がFedoraの公式リポジトリに含まれている――他の多くの自作ソリューションとは異なり、サードパーティのリポジトリを追加する必要がない。
