LUKSでLinuxディスクを暗号化する:サーバー紛失・盗難時のデータ保護

Security tutorial - IT technology blog
Security tutorial - IT technology blog

ネットワークセキュリティだけでは足りない — 物理アクセスという脅威

以前、SSHへのブルートフォース攻撃を受けて、深夜に急対応したことがある。その後、ファイアウォール、fail2ban、SSHポートの変更など、できる対策はひと通り施した。しかし、あるシナリオだけはずっと見落としていた。誰かがサーバーのハードディスクを物理的に持ち去った場合、何が起きるのかという問題だ。

VPSならこのリスクは遠い話に聞こえるかもしれない。しかし、オフィスやコロケーション施設、自宅に設置したベアメタルサーバーでは、これは現実の脅威だ。rootパスワードをクラックする必要も、ファイアウォールを突破する必要もない。ディスクを取り外して別のマシンに接続し、マウントすれば、すべてのデータが丸見えになる。

これがLUKS(Linux Unified Key Setup)が生まれた理由だ。パーティション上のデータはブロックデバイス層でAES-256暗号化される — つまり、ロック解除されるまでOSでさえ何も知ることができない。パスフレーズかキーファイルがなければ、ハードディスクはランダムなバイト列でしかない — どのマシンに接続しても同じことだ。

cryptsetupのインストール

cryptsetupはLUKSを管理するパッケージだ。Ubuntuには通常プリインストールされている。他のディストリビューションは以下のコマンドで追加できる:

# Ubuntu / Debian
sudo apt update && sudo apt install cryptsetup -y

# CentOS / RHEL / Rocky Linux
sudo dnf install cryptsetup -y

# バージョン確認
cryptsetup --version
# cryptsetup 2.6.1

カーネルモジュールdm-cryptがロードされている必要がある。簡単に確認する方法:

lsmod | grep dm_crypt
# 空の場合は手動でロード:
sudo modprobe dm-crypt

LUKSの設定手順

ステップ1 — パーティションまたはディスクの準備

ここでは、暗号化が必要な追加ディスク/dev/sdbまたはパーティション/dev/sdb1があるとする。lsblkでデバイスを正確に確認しておくこと — cryptsetup luksFormatコマンドは既存データを完全に削除し、取り消しはできない。

lsblk
# NAME   MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
# sda      8:0    0   50G  0 disk
# └─sda1   8:1    0   50G  0 part /
# sdb      8:16   0   20G  0 disk   ← 暗号化対象のディスク

ステップ2 — LUKSでパーティションをフォーマット

sudo cryptsetup luksFormat /dev/sdb

このコマンドはYES(大文字)での確認とパスフレーズの入力を求める。このパスフレーズは忘れると復元不可能 — 強力なパスフレーズ(20文字以上)を使い、すぐにパスワードマネージャーへ保存すること。

暗号化アルゴリズムを明示的に指定したい場合:

# AES-256とXTSモード — cryptsetup >= 2.x のデフォルト
sudo cryptsetup luksFormat --type luks2 \
  --cipher aes-xts-plain64 \
  --key-size 512 \
  --hash sha256 \
  /dev/sdb

ステップ3 — 暗号化ボリュームを開く

フォーマット完了後、LUKSはパーティションを暗号化したが、まだ使用できない。まず「ロック解除」が必要 — luksOpenは復号を行い、パーティションを/dev/mapper/<名前>の仮想ブロックデバイスにマッピングする:

# "data_encrypted"は任意の名前 — /dev/mapper/data_encrypted として表示される
sudo cryptsetup luksOpen /dev/sdb data_encrypted
# パスフレーズを入力...

# 確認
ls -la /dev/mapper/data_encrypted
# lrwxrwxrwx 1 root root 7 ... /dev/mapper/data_encrypted -> ../dm-0

ステップ4 — ファイルシステムのフォーマットとマウント

ここから、/dev/mapper/data_encryptedは通常のパーティションと同様に見えて動作する — ファイルシステムをフォーマットし、マウントして、普通に使える:

# ext4でフォーマット
sudo mkfs.ext4 /dev/mapper/data_encrypted

# マウントポイントを作成
sudo mkdir -p /mnt/secure_data

# マウント
sudo mount /dev/mapper/data_encrypted /mnt/secure_data

# 確認
df -h /mnt/secure_data
# /dev/mapper/data_encrypted   20G  45M   19G   1% /mnt/secure_data

ステップ5 — 起動時のauto-mount設定

ここは多くの人が省略するところだ。再起動後にLUKSボリュームを自動マウントするには、/etc/crypttab/etc/fstabの2つのファイルを設定する必要がある。

まず、元のパーティション(device mapperではない)のUUIDを取得する:

sudo blkid /dev/sdb
# /dev/sdb: UUID="a1b2c3d4-e5f6-7890-abcd-ef1234567890" TYPE="crypto_LUKS"

/etc/crypttabに追記する:

sudo nano /etc/crypttab
# <マッパー名>     <デバイス>                                  <キーファイル>  <オプション>
data_encrypted   UUID=a1b2c3d4-e5f6-7890-abcd-ef1234567890   none       luks

noneがキーファイルの列にある場合、起動時にコンソールでパスフレーズを求められる。キーファイルを使って自動化(手入力不要)したい場合:

# 4096バイトのランダムキーファイルを作成
sudo dd if=/dev/urandom of=/root/luks_keyfile bs=4096 count=1
sudo chmod 400 /root/luks_keyfile

# LUKSにキーファイルを追加(既存のパスフレーズをバックアップとして保持)
sudo cryptsetup luksAddKey /dev/sdb /root/luks_keyfile

# crypttabを更新
# data_encrypted   UUID=...   /root/luks_keyfile   luks

その後、/etc/fstabに追記する:

sudo nano /etc/fstab
/dev/mapper/data_encrypted   /mnt/secure_data   ext4   defaults   0   2

確認と監視

LUKSのステータス確認

# ボリュームの詳細情報
sudo cryptsetup luksDump /dev/sdb
# LUKS header information
# Version:        2
# Epoch:          3
# Metadata area:  16384 [bytes]
# Keyslots area:  16744448 [bytes]
# UUID:           a1b2c3d4-...
# Label:          (no label)
# Subsystem:      (no subsystem)
# Flags:          (no flags)
# ...
# Keyslots:
#  0: luks2   ← パスフレーズ
#  1: luks2   ← キーファイル(追加した場合)

# デバイスマッパーのステータス
sudo cryptsetup status data_encrypted
# /dev/mapper/data_encrypted is active.
#   type:    LUKS2
#   cipher:  aes-xts-plain64
#   keysize: 512 bits
#   key location: keyring
#   device:  /dev/sdb
#   ...

LUKSヘッダーのバックアップ — 必須の手順

LUKSヘッダーはパーティションの先頭にある — 暗号化メタデータ、キースロット、ソルトが格納されている場所だ。そのエリアのバッドセクターや、誤ってddを違うデバイスに実行してしまうだけで、すべて終わりだ。パスフレーズが正しくてもデータは永遠に失われる。セットアップ直後に必ずバックアップすること — 後回しにしてはいけない:

sudo cryptsetup luksHeaderBackup /dev/sdb \
  --header-backup-file /root/luks_header_backup_sdb.img

# このファイルをサーバー外に保存(USB、S3、暗号化クラウドストレージなど)
# バックアップが有効か確認
sudo cryptsetup luksDump /root/luks_header_backup_sdb.img

使用しないときはボリュームを閉じる

# 先にアンマウント
sudo umount /mnt/secure_data

# LUKSを閉じる
sudo cryptsetup luksClose data_encrypted

# /dev/mapper/data_encrypted が消える
# ディスクが完全に暗号化された状態に戻る

パスフレーズの管理 — 追加、削除、変更

LUKSは最大8つのキースロットをサポートしている — つまり、複数のパスフレーズやキーファイルを同時に設定できる:

# 新しいパスフレーズを追加(例:チーム用のリカバリーパスフレーズ)
sudo cryptsetup luksAddKey /dev/sdb

# 古いパスフレーズを削除
sudo cryptsetup luksRemoveKey /dev/sdb

# 使用中のキースロットを確認
sudo cryptsetup luksDump /dev/sdb | grep -E "Keyslots|[0-9]+:"

実践で覚えておきたいポイント

  • パフォーマンスオーバーヘッド:AES-NI(ハードウェアアクセラレーション)は2010年以降のほとんどのCPUに搭載されている。grep aes /proc/cpuinfoで確認できる。搭載されていれば、暗号化のオーバーヘッドはほぼ無視できる — 実際のベンチマークでは、非暗号化と比べてスループットの差は3%未満であることが多い。
  • LUKS1 vs LUKS2:LUKS2(cryptsetup 2.x以降のデフォルト)を使うこと — Argon2鍵導出をサポートし、LUKS1よりもブルートフォースへの耐性が高い。
  • スワップパーティション:RAMのダンプがスワップにプレーンテキストで書き出される。具体的な例:使用中のSSH秘密鍵がメモリ上にあり、/dev/sda3にスワップアウトされた場合、ディスクを持っている人は即座に読み取れてしまう。このシナリオを避けるにはzramを使うか、スワップを個別に暗号化すること。
  • フルディスク暗号化 vs パーティション暗号化:この記事ではデータパーティション(data partition)の暗号化を解説している。ディスク全体(/含む)の暗号化はより複雑で、通常はOSの新規インストール時に行う。

あのSSH対応で深夜に走り回った夜から、セキュリティを後回しにすることはなくなった。LUKSは、重要なデータを保存する新しいサーバーをデプロイする際に必ず設定するものの一つになった。15分のセットアップで、ハードディスクが他人の手に渡るシナリオを考えたとき、完全に安心できる。

Share: