本記事は暗号化やセキュリティに関する記述がありますが、個人のメモ書きであり、内容の正しさを含め、直接的・間接的を問わず生じた問題等に対して、著者は一切の責任を負いません。
概要
- 保証期間内にHDDが故障した際、修理交換のためにHDDを送付したいが、中のデータを削除できずに送付できないジレンマがある
- HDDが故障する前に透過的暗号を導入しておくことで、HDDからのデータ流出を防止する
自宅サーバのHDDが壊れた
我が家のサーバは、NASやエンタープライズ向けのHDDを利用しており、保証期間が数年と長く設定されているが、今回は残念ながら期限が切れていた。無念。
バックアップサーバの調子の悪いHDD。NAS向け製品で保証期間が長いので、ワンチャンあるかと思ったが、2022年末で切れていた。残念。 https://t.co/Mxeo6qwqaF
— kWatanabe (@WWatchin) 2024年1月2日
一方、保証期間内であったとしても、データを含むHDDをメーカーに送ることは中々難しい。
故障品だとしても、検査の際にたまたま動くこともあるだろうし、メーカーならば故障部品を交換すればサルベージも簡単だと考えられる。廃棄時のように物理破壊するわけにもいかないし、故障しているので上書き消去もできない。
透過的暗号による保護
このような背景から、故障する前に他人からデータを読み取れない状態にしたい。その一方で、故障するまでは特別な操作なしに扱えるようにしたい。
これを実現するために透過的暗号を導入する。透過的暗号は、アクセスの際に自動で暗号と復号を行う仕組みで、鍵を持つ者は通常のHDDと同様に扱えるが、鍵を持たない者はデータが読み取れない。故障時はHDDのみを提出することで、物理アクセスによる情報流出の防止に期待する。
dm-crypt + LUKS
Linux の透過的暗号の仕組みとしては、dm-crypt と LUKS の組み合わせが主流らしい。
ディスク単体の暗号化から、システム全体の暗号化、複数の鍵を用いたアクセス制御や、ネットワークを用いた鍵配信まで、かなり高度な構成が取れる模様。
想定する驚異モデル
設定を検討するうえで、故障したHDDをメーカー修理に出すユースケースを想定し、驚異モデルを以下の通りとする。
- 攻撃者は、機密情報が含まれるHDD本体を入手できる
- 攻撃者は、入手したHDD本体へのあらゆる物理的アクセスができる
- 攻撃者は、HDDが搭載されていたサーバやその他のデバイスにはアクセスできない
- 内部犯・外部犯による攻撃や盗難は考慮しない。
すなわち、以下の設定では情報システムとしてのセキュリティ対策にはならない点に注意。
検証
パッケージの導入とアルゴリズムの選定
基本的な機能はカーネルが提供するため、導入するパッケージは管理ツールのみ。
$ sudo apt install cryptsetup
暗号化に用いるアルゴリズムを選定するため、ベンチマークを行う。
$ sudo cryptsetup benchmark # テストはストレージI/Oがなくメモリ上のもののため目安です。 PBKDF2-sha1 2396745 回/秒 (256 ビットの鍵) PBKDF2-sha256 4319571 回/秒 (256 ビットの鍵) PBKDF2-sha512 1829975 回/秒 (256 ビットの鍵) PBKDF2-ripemd160 1071068 回/秒 (256 ビットの鍵) PBKDF2-whirlpool 799219 回/秒 (256 ビットの鍵) argon2i 6 回, 1048576 KB使用, 4 スレッド (256 のビットの鍵) (2000 ms 計測) argon2id 6 回, 1048576 KB使用, 4 スレッド (256 のビットの鍵) (2000 ms 計測) # Algorithm | キー | 暗号化 | 復号化 aes-cbc 128b 1768.2 MiB/s 6683.9 MiB/s serpent-cbc 128b 118.3 MiB/s 816.0 MiB/s twofish-cbc 128b 261.4 MiB/s 526.6 MiB/s aes-cbc 256b 1415.0 MiB/s 5387.8 MiB/s serpent-cbc 256b 125.2 MiB/s 815.0 MiB/s twofish-cbc 256b 297.4 MiB/s 527.2 MiB/s aes-xts 256b 5489.9 MiB/s 5485.2 MiB/s serpent-xts 256b 779.2 MiB/s 740.5 MiB/s twofish-xts 256b 488.7 MiB/s 498.9 MiB/s aes-xts 512b 4897.4 MiB/s 4866.2 MiB/s serpent-xts 512b 786.7 MiB/s 740.2 MiB/s twofish-xts 512b 492.0 MiB/s 499.0 MiB/s
このシステムでは、ハッシュ化アルゴリズムは sha256
、暗号化アルゴリズムは aes-xts
が最も高速であることが分かる*1。256bitのAESならば強度の面でも申し分ない*2。
暗号化ボリュームの作成
今回は、/dev/sdb
にパーティションを作成し、暗号化ボリュームとする。パーティションの作成に特別な手順は必要ない。
$ sudo fdisk /dev/sdb Command (m for help): g Command (m for help): n Partition number (1-128, default 1): First sector (2048-16777182, default 2048): Last sector, +/-sectors or +/-size{K,M,G,T,P} (2048-16777182, default 16775167): Command (m for help): w
ベンチマークの結果を参考に、暗号化ボリュームを初期化する。今回は、(故障するかもしれない)HDD以外にはアクセスされない前提のため、アンロックするための鍵は、別のディスクにキーファイルを作成し、これを用いる。
まず、キーファイルを作成する。
$ sudo mkdir -p /etc/luks-keyfile
$ cat /dev/urandom | tr -dc "[:graph:]" | fold -w 2048| head -n 1 | sudo tee /etc/luks-keyfile/test ...
一応、root 以外で閲覧できないようパーミッションを設定する。
$ sudo chmod 700 /etc/luks-keyfile
$ sudo chmod 400 /etc/luks-keyfile/test
暗号化ボリュームを作成する。
$ sudo cryptsetup -v --cipher aes-xts-plain64 --key-size 256 --hash sha256 luksFormat /dev/sdb1 /etc/luks-keyfile/test 警告!! ======== /dev/sdb1 のデータを上書きします。戻せません。 よろしいですか? ('yes' を大文字で入力してください): YES キースロット 0 が作成されました。 コマンド成功。
手動でのアンロック
作成した暗号化ボリュームをアンロックし、 /dev/mapper/crypt-sdb1
としてマップする。
$ sudo cryptsetup open --type luks --key-file /etc/luks-keyfile/test /dev/sdb1 crypt-sdb1
すると、以下のように透過的暗号のレイヤが挿入される。
$ sudo lsblk -p /dev/sdb NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS /dev/sdb 8:16 0 8G 0 disk └─/dev/sdb1 8:17 0 8G 0 part └─/dev/mapper/crypt-sdb1 254:0 0 8G 0 crypt
以降は、このレイヤを物理HDDと同じように扱うことで、透過的暗号が実現される。
$ sudo mkfs -t ext4 /dev/mapper/crypt-sdb1
$ sudo mount /dev/mapper/crypt-sdb1 /mnt
$ ls /mnt
lost+found/
自動でのアンロック
今回は、利用中の盗難や攻撃を想定しないため、システムが起動すると自動でアンロックされ、ファイルシステムとしてマウントできるようにする。
そのために、まず暗号化ボリュームのUUIDを調べる。
$ sudo blkid /dev/sdb1 /dev/sdb1: UUID="e8e54b6a-6312-456b-bdff-5c7762b69d01" TYPE="crypto_LUKS" PARTUUID="30a698c2-c227-7f4c-8239-164128126283"
調べたUUID、マップするデバイスファイル、アンロックのためのキーファイルを /etc/crypttab
に記述する。
$ sudo vi /etc/crypttab crypt-sdb1 UUID=e8e54b6a-6312-456b-bdff-5c7762b69d01 /etc/luks-keyfile/test luks,timeout=30
これで、起動時に自動でアンロックされるため、通常のHDDと同様に /etc/fstab
にマウントポイントを記述しておくと、アンロックとマウントまで自動で行われる。
$ sudo vi /etc/fstab /dev/mapper/crypt-sdb1 /srv ext4 defaults 0 0
$ sudo reboot ...
$ df /dev/mapper/crypt-sdb1 ファイルシス 1K-ブロック 使用 使用可 使用% マウント位置 /dev/mapper/crypt-sdb1 8136484 24 7701568 1% /srv
ソフトウェアRAIDの透過的暗号
ソフトウェアRAIDと透過的暗号を組み合わせる場合、以下の2パターンがある。
- 暗号化ボリュームを使って、RAIDボリュームを作成 暗号化ボリュームを従来の物理HDDと同様に扱えるため、RAIDボリュームの管理や縮退時の対応が楽。ただし、HDDごとに暗号化ボリュームの構成が必要。
- RAIDボリュームを使って、暗号化ボリュームを作成 全てのHDDをひとつの暗号化ボリュームでまとめることができるが、RAIDボリュームの管理や縮退時の対応が難しい。
特に理由がなければ、前者が扱いやすい。この場合、特別な手順は必要なく、暗号化ボリュームに対して普通にRAIDの設定を行えば良い。
$ sudo lsblk -p /dev/sdc /dev/sdd NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS /dev/sdc 8:32 0 8G 0 disk └─/dev/sdc1 8:33 0 8G 0 part └─/dev/mapper/crypt-raid0 254:0 0 8G 0 crypt /dev/sdd 8:48 0 8G 0 disk └─/dev/sdd1 8:49 0 8G 0 part └─/dev/mapper/crypt-raid1 254:1 0 8G 0 crypt
$ sudo apt install mdadm
$ sudo mdadm --create --level=1 --metadata=1.2 --raid-devices=2 /dev/md0 /dev/mapper/crypt-raid0 /dev/mapper/crypt-raid1 mdadm: array /dev/md0 started.
$ sudo mdadm --detail --scan | sudo tee -a /etc/mdadm/mdadm.conf ARRAY /dev/md0 metadata=1.2 name=dmcrypt:0 UUID=07997157:3fd8cdc2:9fcf07a3:ce952c0f
$ sudo mdadm --assemble --scan
$ sudo lsblk -p /dev/sdc /dev/sdd NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS /dev/sdc 8:32 0 8G 0 disk └─/dev/sdc1 8:33 0 8G 0 part └─/dev/mapper/crypt-raid0 254:0 0 8G 0 crypt └─/dev/md0 9:0 0 8G 0 raid1 /dev/sdd 8:48 0 8G 0 disk └─/dev/sdd1 8:49 0 8G 0 part └─/dev/mapper/crypt-raid1 254:1 0 8G 0 crypt └─/dev/md0 9:0 0 8G 0 raid1
$ sudo mkfs -t ext4 /dev/md0
...
$ sudo blkid /dev/md0 /dev/md0: UUID="b9a593ff-3ea4-46aa-98fa-b93428a00fd1" BLOCK_SIZE="4096" TYPE="ext4"
$ sudo vi /etc/fstab UUID=b9a593ff-3ea4-46aa-98fa-b93428a00fd1 /opt ext4 defaults 0 0
$ sudo mount -a
$ sudo lsblk -p /dev/sdc /dev/sdd NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS /dev/sdc 8:32 0 8G 0 disk └─/dev/sdc1 8:33 0 8G 0 part └─/dev/mapper/crypt-raid0 254:0 0 8G 0 crypt └─/dev/md0 9:0 0 8G 0 raid1 /opt /dev/sdd 8:48 0 8G 0 disk └─/dev/sdd1 8:49 0 8G 0 part └─/dev/mapper/crypt-raid1 254:1 0 8G 0 crypt └─/dev/md0 9:0 0 8G 0 raid1 /opt
まとめ
- 保証期間内に壊れたHDDを修理に出せるようにするため、dm-crypt と LUKS を導入した
- セキュリティ対策としては機能しないが、HDDのみを提出する必要のあるケースにおいては、最低限の対策となると思う