CentOS 8がEOLになった件で、1週間以内に5台のサーバーをRocky Linuxへ急いでマイグレーションしなければなりませんでした。最も後悔したことの一つは、移行前にNBDEをセットアップする時間がなかったことです——結果的に新しい環境で一から設定し直すことになりました。この経験を活かして、今回はCentOS Stream 9向けに詳細な手順を記録しておきます。
背景:従来のLUKSが抱える実際の問題
データセンターにbare-metalサーバーがあり、ディスクがLUKSで暗号化されているとします。サーバーを再起動するたびに——カーネルアップデート、停電、メンテナンスにかかわらず——コンソールで手動でパスフレーズを入力するために待機しなければなりません。5〜10台のサーバーでもうんざりしますが、より大規模なフリートや夜間に人が常駐していない環境では言うまでもありません。
NBDE(Network-Bound Disk Encryption)はまさにこの問題を解決します。内部ネットワーク内(Tang serverが存在する場所)でサーバーが起動する際にディスクが自動的にアンロックされ、サーバーがネットワーク外に持ち出された場合は手動でパスフレーズを要求します。これがポイントです——automationを妨げることなく物理的なセキュリティを確保できます。
NBDEが最も適しているケース:
- 機密データ(PII、金融データ)を保持するデータベースサーバー
- コロケーションデータセンターのBare-metalまたはVM
- コンプライアンス要件:HIPAA、PCI-DSS、ISO 27001
- 担当者なしでunattended-upgradesの後に自動再起動するサーバー
アーキテクチャは2つの主要コンポーネントで構成されています:
- Tang server:McTLSプロトコルを使用するkey保管専用のサーバー。Tangはクライアントのkeyを保存しません——Diffie-Hellmanによるkey導出プロセスに参加するだけです。Serverが侵害されても、LUKS keyが漏洩することはありません。
- Clevis:クライアント側のFramework。複数の"pin"(tang、tpm2、sss)をサポートし、LUKS volumeをTangまたはTPMにBindします。
起動フロー:Dracut initramfs → ClevisがnetworkでTangに接続 → Tangがkey導出のためのデータを返す → LUKSがアンロック → 起動継続。
TangとClevisのインストール
1. Tang Serverのインストール
Tangはアンロックが必要なサーバー自体ではなく、専用のサーバーまたは別のVMで実行する必要があります。CentOS Stream 9の場合:
dnf install tang -y
systemctl enable --now tangd.socket
firewall-cmd --add-service=tangd --permanent
firewall-cmd --reload
Tangがリッスンしているか確認し、thumbprintを取得します(Clevisをbindする際に必要):
systemctl status tangd.socket
# keyのthumbprintを取得する
jose jwk thp -i /var/db/tang/*.jwk
thumbprintを保存してください——例:abc123XYZdef456。bindステップで使用します。
2. クライアント側のClevisインストール
自動暗号化が必要なCentOS Stream 9サーバーの場合:
dnf install clevis clevis-luks clevis-dracut -y
# TPM2サポートも必要な場合
dnf install clevis-tpm2 -y
詳細設定
ステップ1:Bindが必要なLUKS volumeを特定する
# LUKS deviceを確認する
lsblk -f | grep crypto
blkid | grep LUKS
# LUKS headerの情報を確認する(使用中のslot数、UUIDなど)
cryptsetup luksDump /dev/sda3
新しいディスクを追加した際の混乱を避けるため、device nameではなくUUIDを使用することをお勧めします。blkidの出力からUUIDを保存してください。
ステップ2:LUKSをTangにBind
# TANG_SERVER_IPとTHUMBPRINTを実際の値に置き換える
clevis luks bind -d /dev/sda3 tang \
'{"url":"http://TANG_SERVER_IP","thp":"THUMBPRINT"}'
Clevisは新しいslotを追加するために現在のLUKS passphraseを要求します。成功すると、LUKSに2つのslotが作成されます:slot 0(元のpassphrase)とslot 1(Clevis/Tang)。確認:
clevis luks list -d /dev/sda3
# 出力:
# 1: tang '{"url":"http://192.168.1.50","thp":"abc123..."}'
ステップ3:initramfsの再構築(最もよく見落とされるステップ)
これは私がかつてスキップしたステップで、その結果、本番サーバーのreboot後に午前2時にpassphrase入力を待つことになりました。BootloaderにClevisを組み込むためにinitramfsを再構築する必要があります:
dracut -fv --regenerate-all
initramfsにClevisが含まれていることを確認:
lsinitrd /boot/initramfs-$(uname -r).img | grep clevis
ステップ4:/etc/crypttabの更新
データvolume(rootではない)の場合、/etc/crypttabに追加します:
# フォーマット: name device keyfile options
data-encrypted UUID=your-luks-uuid none _netdev,x-initrd.attach
_netdevオプションはsystemdにmount前にnetworkが必要であることを通知します。x-initrd.attachはinitrd内で処理されることを保証します。これら2つのオプションがない場合、volumeは正しい起動順序でアンロックされません。
ステップ5(オプション):SSSによるHA——2台のTang server
高可用性が必要な場合、SSS(Shamir’s Secret Sharing)を使用することで、threshold付きで複数のpinを組み合わせることができます。例えば、2台のTang serverのうち少なくとも1台が必要な場合:
clevis luks bind -d /dev/sda3 sss \
'{"t":1,"pins":{"tang":[{"url":"http://tang1.internal","thp":"THUMB1"},{"url":"http://tang2.internal","thp":"THUMB2"}]}}'
この設定により、2台のTang serverのうち1台がダウンしてもサーバーを起動できます。
テストとモニタリング
rebootなしのテスト
# Clevisが復号できるかテスト
clevis luks unlock -d /dev/sda3 -n test-unlock
# 成功した場合 → /dev/mapper/test-unlockが作成される
# テスト後にクリーンアップ
cryptsetup close test-unlock
# Tang接続を直接テスト
curl -sS http://TANG_SERVER_IP/adv | jose fmt -j- -g payload -y -o-
# 出力はkeyを含むJSON——空の場合はfirewallを確認
起動時のログ確認
# 現在の起動セッションのClevisログ
journalctl -b 0 | grep -i clevis
# Tang serverのリアルタイムログ
journalctl -u tangd -f
Prometheus BlackboxでTangをモニタリング
Tangにはビルトインのmetricsがありません。Blackbox Exporterを使用して/advエンドポイントを確認します:
# blackbox.yml
modules:
tang_check:
prober: http
http:
valid_status_codes: [200]
method: GET
fail_if_body_not_matches_regexp:
- "keys"
# prometheus.yml
- job_name: 'tang'
metrics_path: /probe
params:
module: [tang_check]
static_configs:
- targets:
- http://TANG_SERVER_IP/adv
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- target_label: __address__
replacement: localhost:9115
重要なアラート:Tangが5分以上ダウンした場合は、即座にoncallに通知してください——次のreboot時に手動でpassphraseが要求されるためです。
Tang keyの定期ローテーション
# Tang serverで:新しいkeyを生成
tangd-keygen /var/db/tang
# クライアントで:新しいkeyでre-bind(slot 1)
clevis luks regen -d /dev/sda3 -s 1
6ヶ月ごとにkeyをローテーションするスケジュールを設定し、Ansible playbookでre-bindをトリガーすることで、各サーバーへの手動SSHが不要になります。
LUKSヘッダーのバックアップ——必須
以前のCentOS 8からRocky Linuxへの移行の件で、重要な教訓を学びました:設定完了直後にLUKS headerをバックアップすること。headerを失うと = dataを永久に失います。復旧する方法はありません:
cryptsetup luksHeaderBackup /dev/sda3 \
--header-backup-file /root/luks-header-sda3-backup.img
# このファイルを別の場所に保存する(同じサーバーではなく)
scp /root/luks-header-sda3-backup.img backup-server:/secure-backups/
dracutタイムアウトエラーの対処
ClevisがTangを見つけられずbootがタイムアウトする場合は、dracut configでタイムアウトを増やしてください:
# /etc/dracut.conf.d/clevis.conf
kernel_cmdline="rd.timeout=90 rd.neednet=1"
# 再構築する
dracut -fv --regenerate-all
NBDEのセットアップは初回に約1〜2時間かかりますが、その後はフリート全体が誰も立ち会わずに自動的に再起動できます——data-at-restが適切に暗号化されているため、セキュリティチームも安心できます。

