Raspberry Pi + Ubuntuに暗号化LVMを導入
はじめに
Raspberry Pi Imagerなどを使ってRaspberry PiにUbuntuをインストールした場合、ファイルシステムはmicroSDカード上のパーティションに直接配置される。この記事では、その状態からLUKSによるストレージ暗号化とLVMを用いた構成に移行する手順を述べる。
本記事では基本的に導入手順のみを扱う。ストレージ暗号化とLVMの利点や欠点、体系的な操作手順などは扱わないので、下記や記事末尾の参考文献を参照されたい。
- ストレージ暗号化
- ストレージ内のデータを暗号化することで、システム停止中のデータを保護すること
- 参照: 保存データ暗号化 - ArchWiki
- LUKS: Linux Unified Key Setup
- ストレージ暗号化の仕様のひとつ。Linuxでストレージ暗号化というとLUKSを使うことが多い
- 参照: dm-crypt/デバイスの暗号化 - ArchWiki
- LVM: Logical Volume Manager
- 物理的なストレージを抽象化して管理する枠組み。論理ボリュームと呼ばれる、使用中にリサイズや移動ができる仮想的なパーティションが使えるため、ファイルシステムを柔軟に管理できる
- 参照: LVM - ArchWiki
記載した手順は、Raspberry Pi 4にUbuntu Server 24.04 LTSを新規にインストールしたすぐ後の状態で動作確認した。
この記事での暗号化LVMの構成
この記事の手順で導入される暗号化LVMは、おおよそ下記のような構成である。
- ストレージ暗号化
- 1つのストレージ(microSDカード)に、ブート用の小さな物理パーティションと残りすべての大きな物理パーティションを設け、大きな物理パーティション全体をLUKSで暗号化する。ブート用のパーティションは暗号化しない
- LVM
- 暗号化されたパーティションを物理ボリュームとし、その1つの物理ボリュームからなるボリュームグループを1つ設け、その1つのボリュームグループ上にすべての論理ボリュームを格納する
- / (ルートファイルシステム)、/var、/home それぞれを1つの論理ボリュームに収める。各ファイルシステムはすべてExt4形式である
- /、/var、/home が分離されているため、いずれか1つに空きがなくなるなど問題が発生しても、他には波及しない
- 各ファイルシステムは少ない手間でリサイズできる
- ボリュームグループ名は
vgmyhost
とする-
myhost
の部分には、実際のショートホスト名を使う - ボリュームグループ名は、そのホスト上の他のボリュームグループ名と重複しない任意の文字列でよい。ただ、復旧作業時に別ホストにストレージを読み込ませた際にも名前が重複しないようにしておくと、運用しやすい
-
- 論理ボリューム名は
lvroot
、lvvar
、lvhome
とする-
lvroot
は / を、lvvar
は /var を、lvhome
は /home をそれぞれ格納する - 論理ボリューム名は、ボリュームグループ内で一意であれば任意の文字列でよい
-
- 暗号化の鍵の扱い
- 暗号化の鍵は、ブートパーティションのinitramfsイメージファイル内に平文のファイルとして置く
- 起動時にその鍵を使って自動でロックを解除するよう設定する
- この運用は、人手を介さずに起動できて手軽だが、鍵が保護されていないという問題がある。ほかの鍵管理方法については補足で扱う
移行手順の概要
暗号化LVMを用いていない状態からの移行は、下記の順序で行う。データを収めたままのパーティションを暗号化LVM構成に変えることはできないため、作業途上ではデータ退避用の一時的なパーティションを用いる。
- 現在のパーティションを縮小してストレージ末尾の領域を空け、空いた領域にデータ退避用の一時的なパーティションを設ける
- すべてのデータをその一時的なパーティションへとコピーする
- 元のパーティション上に暗号化LVMの領域を作成する
- すべてのデータをその暗号化パーティションへとコピーする
- 一時的なパーティションを削除し、暗号化パーティションをストレージ末尾まで拡張する
上記の手順では、1つのmicroSDカードだけで作業を完結させるために、すべてのデータを計2回コピーし、既存のパーティションの縮小と再拡張をおこなっている。複数のストレージを使ってよいなら、下記のいずれかのようにすれば手順を少なくできる。
- 作業の際に追加のストレージを使い、そこに一時的なパーティションを置く
- 追加のストレージ(例えばUSBメモリ)が必要
- 元のパーティションの一時的な縮小とその後の再拡張は不要
- 移行先を別のmicroSDカードにする
- Raspberry Piに2枚目のmicroSDカードを接続するために、USB接続のmicroSDカードリーダライタなどが必要
- すべてのデータをコピーする回数が1回で済む。パーティションの縮小や拡張は不要
移行前の構成
手順の動作確認を行った際の、移行前のパーティションとファイルシステムの構成は下記のとおり。この構成は、Raspberry Pi Imagerなどを使ってRaspberry PiにUbuntu Serverを導入した場合の初期状態で、使用したmicroSDカードの容量は8GBである。
Partition No. | Size | Partition ID: Type | Bootable? | Filesystem | Label | Mount Point |
---|---|---|---|---|---|---|
Primary 1 | 512.0 MiB | 0x0c: W95 FAT32 (LBA) | yes | FAT32 | system-boot | /boot/firmware |
Primary 2 | 6.9 GiB | 0x83: Linux | no | Ext4 | writable | / |
- / (ルートファイルシステム) の使用容量は 1.9 GiB
- うち、/var は 0.3 GiB、/home は 1 MiB 未満を使用
lsblkコマンドとdfコマンドによる表示結果は下記のとおり。
$ lsblk /dev/mmcblk0
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
mmcblk0 179:0 0 7.4G 0 disk
├─mmcblk0p1 179:1 0 512M 0 part /boot/firmware
└─mmcblk0p2 179:2 0 6.9G 0 part /
$ df -h | grep -v tmpfs
Filesystem Size Used Avail Use% Mounted on
/dev/mmcblk0p2 6.8G 1.9G 4.6G 29% /
/dev/mmcblk0p1 505M 85M 420M 17% /boot/firmware
移行手順
以降の記述では、プロンプトが $
であれば一般ユーザー権限での実行を、#
であればroot権限での実行を表すものとする。
事前準備: update-initramfs実行時にバックアップを残すようにする
update-initramfs実行時に、1つ前のinitramfsイメージファイルを残しておきたいなら、下記のように /etc/initramfs-tools/update-initramfs.conf の backup_initramfs の値を yes に設定する。
...
#
# backup_initramfs [ yes | no ]
#
# Default is no
# If set to no leaves no .bak backup files.
-backup_initramfs=no
+backup_initramfs=yes
この状態で update-initramfs -u
を実行すると、下記のように1つ前の /boot/initrd.img-xxx が /boot/initrd.img-xxx.bak として残されるようになる。新しいinitramfsイメージファイルでの起動に失敗したときに、1つ前のものを使って起動できることが利点である。
# update-initramfs -u
...
$ ls -l /boot/initrd.img*
lrwxrwxrwx ... /mnt/boot/initrd.img -> initrd.img-6.8.0-1004-raspi
-rw-r--r-- ... /mnt/boot/initrd.img-6.8.0-1004-raspi
-rw-r--r-- ... /mnt/boot/initrd.img-6.8.0-1004-raspi.bak
lrwxrwxrwx ... /mnt/boot/initrd.img.old -> initrd.img-6.8.0-1004-raspi
ルートファイルシステムとそのパーティションを縮小する
Raspberry Piを停止させ、microSDカードを取り出し、別のUnix環境に接続して下記の順に操作する。
(ここでは別のUnix環境でのmicroSDカードのデバイスファイルを /dev/sdb、ルートファイルシステムのあるパーティションを /dev/sdb2 として記載している)
resize2fsコマンドを使ってルートファイルシステムを縮小する。
# e2fsck -f /dev/sdb2
e2fsck 1.47.0 (5-Feb-2023)
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
...
writable: 57319/456064 files (0.1% non-contiguous), 530725/1809147 blocks
# resize2fs /dev/sdb2 3G
resize2fs 1.47.0 (5-Feb-2023)
Resizing the filesystem on /dev/sdb2 to 786432 (4k) blocks.
The filesystem on /dev/sdb2 is now 786432 (4k) blocks long.
- e2fsckコマンドにて、ファイルシステムをクリーンな状態にする
- resize2fsコマンドにて、ファイルシステムを 3 GiB まで縮小
- サイズはシステムの構成に合わせる。後述
パーティションを縮小する。パーティションを操作する手段はいくつかあるが、ここではpartedコマンドのresizepartコマンドを使用する。
# parted /dev/sdb
GNU Parted 3.5
Using /dev/sdb
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted) unit GiB
(parted) print
Model: Generic- SD/MMC (scsi)
Disk /dev/sdb: 7.40GiB
Sector size (logical/physical): 512B/512B
Partition Table: msdos
Disk Flags:
Number Start End Size Type File system Flags
1 0.00GiB 0.50GiB 0.50GiB primary fat32 boot, lba
2 0.50GiB 7.40GiB 6.90GiB primary ext4
(parted) resizepart 2 4.5GiB
Warning: Shrinking a partition can cause data loss, are you sure you want to continue?
Yes/No? y
(parted) print
Model: Generic- SD/MMC (scsi)
Disk /dev/sdb: 7.40GiB
Sector size (logical/physical): 512B/512B
Partition Table: msdos
Disk Flags:
Number Start End Size Type File system Flags
1 0.00GiB 0.50GiB 0.50GiB primary fat32 boot, lba
2 0.50GiB 4.50GiB 4.00GiB primary ext4
(parted) quit
Information: You may need to update /etc/fstab.
- printコマンドにて、現在のパーティション構成を確認。パーティション2の容量は 6.9 GiB とわかる
- resizepartコマンドにて、パーティション2を 4 GiB へとリサイズ
-
resizepart 2 4.5GiB
の第2引数4.5GiB
は末端セクタ位置の指定。開始位置が 0.5 GiB なので、サイズは 4.0 GiB になる
-
- printコマンドにて、リサイズ後のパーティション構成を確認。リサイズ後のパーティション2の実際の容量が 4.0 GiB であることを確認する
上記の例では、ファイルシステムを 3.0 GiB まで縮小し、そのパーティションを元の 6.9 GiB から 4.0 GiB へと縮小しているが、下記を満たしていればほかの数値でも問題ない。
- ファイルシステムのほうがパーティションよりも小さい
- パーティション縮小で確保された未使用領域のほうが、ルートファイルシステムの使用容量よりも大きい
一時的なデータ退避用パーティションを設けて全データを移す
引き続き、別のUnix環境にて操作する。ストレージの末尾の未使用領域にパーティションを作成する。ここではfdiskコマンドを使用する。
(入力が (デフォルト)
となっている箇所は、何も書かずに改行を入力してデフォルト値を選択することを意味する)
# fdisk /dev/sdb
Welcome to fdisk (util-linux 2.38.1).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.
Command (m for help): n
Partition type
p primary (2 primary, 0 extended, 2 free)
e extended (container for logical partitions)
Select (default p): p
Partition number (3,4, default 3): (デフォルト)
First sector (9437184-15523839, default 9437184): (デフォルト)
Last sector, +/-sectors or +/-size{K,M,G,T,P} (9437184-15523839, default 15523839): (デフォルト)
Created a new partition 3 of type 'Linux' and of size 2.9 GiB.
Command (m for help): p
Disk /dev/sdb: 7.4 GiB, 7948206080 bytes, 15523840 sectors
Disk model: SD/MMC
...
Device Boot Start End Sectors Size Id Type
/dev/sdb1 * 2048 1050623 1048576 512M c W95 FAT32 (LBA)
/dev/sdb2 1050624 9437183 8386560 4G 83 Linux
/dev/sdb3 9437184 15523839 6086656 2.9G 83 Linux
Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.
設けたパーティション上にExt4ファイルシステムを作成する。Raspberry Pi + Ubuntu の場合は、ラベル writable
を使ってルートファイルシステムを特定しているため、ラベルを付与する。
# mkfs -t ext4 -L writable /dev/sdb3
mke2fs 1.47.0 (5-Feb-2023)
Creating filesystem with 760832 4k blocks and 190464 inodes
...
元のルートファイルシステムの内容を新しいファイルシステムへとコピーする。
# mkdir /mnt/orig /mnt/new
# mount -r /dev/sdb2 /mnt/orig
# mount /dev/sdb3 /mnt/new
# rsync -AHXaxv /mnt/orig/ /mnt/new/
sending incremental file list
...
# umount /mnt/orig /mnt/new
# rmdir /mnt/orig /mnt/new
- マウントポイント用に /mnt/orig と /mnt/new を作成する
- 元のルートファイルシステム(/dev/sdb2)を /mnt/orig にread onlyとしてマウントする
- 新しいファイルシステム(/dev/sdb3)を /mnt/new にマウントする
- /mnt/orig の内容を /mnt/new にコピーする
- アンマウントし、マウントポイント用の一時的なディレクトリを削除する
新しいルートファイルシステムから起動させるために、tune2fsコマンドにて元のルートファイルシステム(/dev/sdb2)の writable
ラベルを削除する。
# tune2fs -L '' /dev/sdb2
tune2fs 1.47.0 (5-Feb-2023)
完了したら、microSDカードをRaspberry Piに戻して起動し、正常に動作していることを確認する。また、例えば下記のようにして、パーティションとファイルシステムの構成が意図どおりであることを確認する。
$ lsblk /dev/mmcblk0
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
mmcblk0 179:0 0 7.4G 0 disk
├─mmcblk0p1 179:1 0 512M 0 part /boot/firmware
├─mmcblk0p2 179:2 0 4G 0 part
└─mmcblk0p3 179:3 0 2.9G 0 part /
$ df -h | grep -v tmpfs
Filesystem Size Used Avail Use% Mounted on
/dev/mmcblk0p3 2.8G 1.9G 794M 71% /
/dev/mmcblk0p1 505M 85M 420M 17% /boot/firmware
以降はRaspberry Pi上で操作する。
空いたパーティションにLUKSによる暗号化領域を設ける
/dev/mmcblk0p2 にLUKSによる暗号化領域を設ける。作成の際に、手動でのロック解除に使用するパスフレーズを登録する。
# cryptsetup luksFormat /dev/mmcblk0p2
WARNING: Device /dev/mmcblk0p2 already contains a 'ext4' superblock signature.
WARNING!
========
This will overwrite data on /dev/mmcblk0p2 irrevocably.
Are you sure? (Type 'yes' in capital letters): YES
Enter passphrase for /dev/mmcblk0p2: (パスフレーズを入力)
Verify passphrase: (もう一度パスフレーズを入力)
以降で使用するため、LUKS領域のロックを解除しておく。ロック解除後のデバイス名を、ここでは mmcblk0p2-crypt としている。
# cryptsetup luksOpen /dev/mmcblk0p2 mmcblk0p2-crypt
Passphrase: (パスフレーズを入力)
$ ls -l /dev/mapper/mmcblk0p2-crypt
lrwxrwxrwx ... /dev/mapper/mmcblk0p2-crypt -> ../dm-0
元のルートファイルシステム上の暗号化されていないデータを完全に消去したい場合には、例えば下記のようにして、ロック解除後のデバイス全体をゼロで上書きすればよい。これにより、/dev/mmcblk0p2 のLUKSヘッダを除く全域がランダムな値と見分けがつかない暗号文で上書きされる。
(デバイス全体へのゼロ書き込みに、ここでは shred -n 0 -z -v DEVICE
を使っている)
# shred -n 0 -z -v /dev/mapper/mmcblk0p2-crypt
shred: /dev/mapper/mmcblk0p2-crypt: pass 1/1 (000000)...
shred: /dev/mapper/mmcblk0p2-crypt: pass 1/1 (000000)...16MiB/4.0GiB 0%
shred: /dev/mapper/mmcblk0p2-crypt: pass 1/1 (000000)...36MiB/4.0GiB 0%
...
shred: /dev/mapper/mmcblk0p2-crypt: pass 1/1 (000000)...4.0GiB/4.0GiB 100%
暗号化パーティション上にLVMの領域を設ける
pvcreateコマンドにて、ロック解除後のデバイスの上にLVMの物理ボリュームを作成する。
# pvcreate /dev/mapper/mmcblk0p2-crypt
Physical volume "/dev/mapper/mmcblk0p2-crypt" successfully created.
vgcreateコマンドにて、その物理ボリューム1つからなるボリュームグループ vgmyhost
を作成する。
# vgcreate vgmyhost /dev/mapper/mmcblk0p2-crypt
Volume group "vgmyhost" successfully created
論理ボリュームを作成しルートファイルシステムの内容をコピーする
lvcreateコマンドとmkfsコマンドにて、ボリュームグループ内にルートファイルシステム用の論理ボリューム lvroot
とファイルシステムを作成する。
(ここではサイズを 2.5 GiB としている。データを格納できる大きさであればよい)
# lvcreate --name lvroot --size 2.5G vgmyhost
Logical volume "lvroot" created.
# mkfs -t ext4 /dev/vgmyhost/lvroot
...
現在のルートファイルシステムの内容をコピーする。
# mount /dev/vgmyhost/lvroot /mnt
# rsync -AHXaxv / /mnt/
...
鍵ファイルを作成しLUKSに追加登録する
LUKS用の鍵ファイルを新規作成し、追加の鍵としてLUKSに登録する。ここでは、乱数生成デバイス /dev/random から4KBを取得して新しいルートファイルシステム内の /etc/keys/mmcblk0p2-crypt.key (作業時に操作するファイルは /mnt/etc/keys/mmcblk0p2-crypt.key) に保存し、それを鍵ファイルとしている。
# mkdir /mnt/etc/keys
# chmod go-rwx /mnt/etc/keys
# dd if=/dev/random of=/mnt/etc/keys/mmcblk0p2-crypt.key bs=1k count=4
# chmod go-rw /mnt/etc/keys/mmcblk0p2-crypt.key
# cryptsetup luksAddKey /dev/mmcblk0p2 /mnt/etc/keys/mmcblk0p2-crypt.key
Enter any existing passphrase: (パスフレーズを入力)
新しいルートファイルシステム内の起動に関する設定を変更する
新しいルートファイルシステム内の /etc/fstab (/mnt/etc/fstab) を変更し、起動後のシステムが新しいルートファイルシステムを使うよう設定する。
...
# <filesystem> <mountpoint> <type> <options> <dump> <pass>
-LABEL=writable / auto defaults 0 1
+/dev/vgmyhost/lvroot / auto defaults 0 1
...
- 変更前:
writable
というラベルのファイルシステム - 変更後:
vgmyhost
ボリュームグループのlvroot
という論理ボリューム内のファイルシステム
起動時に鍵ファイルを使って暗号化パーティションのロックを解除するよう、/mnt/etc/crypttab に下記のような1行を追記する。
# <target name> <source device> <key file> <options>
+mmcblk0p2-crypt UUID=... /etc/keys/mmcblk0p2-crypt.key luks
- /etc/keys/mmcblk0p2-crypt.key という鍵ファイルを使い、起動時に
UUID=...
という暗号化デバイスのロックを解除し /dev/mapper/mmcblk0p2-crypt にマッピングする -
UUID=...
の...
には、暗号化されたパーティション(/dev/mmcblk0p2)のデバイスUUIDを記述する。デバイスUUIDは、blkid -s UUID -o value /dev/mmcblk0p2
にて確認できる
/mnt/etc/cryptsetup-initramfs/conf-hook を変更し、LUKS用の鍵ファイル /etc/keys/mmcblk0p2-crypt.key がinitramfsイメージファイルに格納されるようにする。
...
+KEYFILE_PATTERN="/etc/keys/*.key"
...
initramfsイメージファイル内の鍵ファイルを保護するため、システム稼働中にはroot権限でしか /boot/initrd.img-... にアクセスできないようにする。/mnt/etc/initramfs-tools/conf.d/ 内に、下記の内容のファイルを例えば umask_strict.conf という名前で新規に追加すればよい。
+UMASK=0077
Raspberry Pi + Ubuntu の場合は、/boot/initrd.img-... のコピーが /boot/firmware/initrd.img に置かれる。これも同様に保護するには、/mnt/etc/fstab の /boot/firmware のエントリに下記のように umask=0077
オプションを追加して、/boot/firmware 全体のパーミッションを限定する。
(/boot/firmware はFAT32ファイルシステムのため、ファイル単位のパーミッション設定はできない)
# <filesystem> <mountpoint> <type> <options> <dump> <pass>
-LABEL=system-boot /boot/firmware auto defaults 0 2
+LABEL=system-boot /boot/firmware auto defaults,umask=0077 0 2
...
ブートパーティション内の起動に関する設定を変更する
/boot/firmware/cmdline.txt を編集し、Linuxカーネルが使用するルートファイルシステムの指定 root=...
を LABEL=writable
から /dev/vgmyhost/lvroot
へと変更する。
-console=serial0,115200 ... root=LABEL=writable rootfstype=ext4 ...
+console=serial0,115200 ... root=/dev/vgmyhost/lvroot rootfstype=ext4 ...
ブートパーティション内のinitramfsファイルを更新する
新しいルートファイルシステム内の変更後の設定を使って、update-initramfs -u
コマンドにて /mnt/boot/initrd.img-... と /boot/firmware/initrd.img の2つのinitramfsイメージファイルを更新する。2つあるが、内容は同一である。反映のための操作は移行後のパーティション構成環境下で行う必要があるため、chrootコマンドを用いて例えば下記のように行う。
# mount --rbind /boot/firmware /mnt/boot/firmware
# mount --rbind /dev /mnt/dev
# mount --rbind /proc /mnt/proc
# mount --rbind /run /mnt/run
# mount --rbind /sys /mnt/sys
# chroot /mnt update-initramfs -u
update-initramfs: Generating /boot/initrd.img-6.8.0-1004-raspi
...
chrootコマンド完了後に、/mnt/boot/initrd.img-... と /boot/firmware/initrd.img の両方が更新されていること、2つが同一内容のファイルであることを確認する。
/mnt/boot/initrd.img-... だけが更新され、/boot/firmware/initrd.img は更新されないことがあるようなので、そうなっていた場合には、下記のように更新された /mnt/boot/initrd.img-... (特定の1ファイル) を /boot/firmware/initrd.img へとコピーする。
$ ls -l /mnt/boot/initrd.img*
...
-rw------- ... initrd.img-6.8.0-1004-raspi
...
# mv /boot/firmware/initrd.img /boot/firmware/initrd.img.bak
# cp /mnt/boot/initrd.img-6.8.0-1004-raspi /boot/firmware/initrd.img
/boot/firmware/initrd.img 内に鍵ファイル mmcblk0p2-crypt.key が埋め込まれていることをlsinitramfsコマンドにて確認する。
# lsinitramfs /boot/firmware/initrd.img
...
cryptroot
cryptroot/crypttab
cryptroot/keyfiles
cryptroot/keyfiles/mmcblk0p2-crypt.key
etc
...
新しいルートファイルシステムから起動できることを確認する
再起動を行い、問題なく動作することを確認する。意図どおり設定できていれば、パーティションとファイルシステムの構成は下記のようになっている。
$ lsblk /dev/mmcblk0
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
mmcblk0 179:0 0 7.4G 0 disk
├─mmcblk0p1 179:1 0 512M 0 part /boot/firmware
├─mmcblk0p2 179:2 0 4G 0 part
│ └─mmcblk0p2-crypt 253:0 0 4G 0 crypt
│ └─vgmyhost-lvroot 253:1 0 2.5G 0 lvm /
└─mmcblk0p3 179:3 0 2.9G 0 part
$ df -h | grep -v tmpfs
Filesystem Size Used Avail Use% Mounted on
/dev/vgmyhost/lvroot 2.4G 1.9G 394M 79% /
/dev/mmcblk0p1 505M 136M 369M 27% /boot/firmware
起動できなかった場合には、Raspberry Piを停止させてmicroSDカードを取り外し、内容を下記のように更新すれば、元のルートファイルシステムから起動できる。起動後に、何が問題だったのかを調べればよい。
- /boot/firmware/ (第1パーティション) の ./cmdline.txt の
root=...
をroot=LABEL=writable
に戻す - /boot/firmware/initrd.img.bak を /boot/firmware/initrd.img に戻す。
もしくは、元のルートファイルシステム (第3パーティション) の ./boot/initrd.img-... を /boot/firmware/initrd.img に上書きする
一時的なパーティションを削除する
一時的なパーティションを削除する前に、そこに置かれている暗号化されていないデータを完全に消去したい場合には、例えば下記のようにして削除前のパーティション全体をランダム値書き込みで消去する。
(デバイス全体へのランダム値書き込みに、ここでは shred -n 1 -v DEVICE
を使っている)
# shred -n 1 -v /dev/mmcblk0p3
shred: /dev/mmcblk0p3: pass 1/1 (random)...
shred: /dev/mmcblk0p3: pass 1/1 (random)...16MiB/4.0GiB 0%
...
一時的なパーティションを削除する。ここではpartedコマンドのrmコマンドを使用する。
$ lsblk /dev/mmcblk0
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
mmcblk0 179:0 0 7.4G 0 disk
├─mmcblk0p1 179:1 0 512M 0 part /boot/firmware
├─mmcblk0p2 179:2 0 4G 0 part
│ └─mmcblk0p2-crypt 253:0 0 4G 0 crypt
│ └─vgmyhost-lvroot 253:1 0 2.5G 0 lvm /
└─mmcblk0p3 179:3 0 2.9G 0 part
# parted /dev/mmcblk0 rm 3
Information: You may need to update /etc/fstab.
$ lsblk /dev/mmcblk0
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
mmcblk0 179:0 0 7.4G 0 disk
├─mmcblk0p1 179:1 0 512M 0 part /boot/firmware
└─mmcblk0p2 179:2 0 4G 0 part
└─mmcblk0p2-crypt 253:0 0 4G 0 crypt
└─vgmyhost-lvroot 253:1 0 2.5G 0 lvm /
暗号化パーティションをストレージ末尾まで拡張する
最初に暗号化パーティション、次にそれに含まれるLUKS領域、最後にそれに含まれる物理ボリュームという順序で拡張を行い、一時的なパーティションを置いていた領域を暗号化パーティションの一部として使えるようにする。
拡張前のストレージは下記のようになっている。
$ lsblk /dev/mmcblk0
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
mmcblk0 179:0 0 7.4G 0 disk
├─mmcblk0p1 179:1 0 512M 0 part /boot/firmware
└─mmcblk0p2 179:2 0 4G 0 part
└─mmcblk0p2-crypt 253:0 0 4G 0 crypt
└─vgmyhost-lvroot 253:1 0 2.5G 0 lvm /
# pvs
PV VG Fmt Attr PSize PFree
/dev/mapper/mmcblk0p2-crypt vgmyhost lvm2 a-- 3.98g 1.48g
- パーティション /dev/mmcblk0p2 は 4 GiB
- LUKS領域としての /dev/mapper/mmcblk0p2-crypt は 4 GiB
- 物理ボリュームとしての /dev/mapper/mmcblk0p2-crypt は 3.98 GiB
パーティションをストレージ末尾まで拡張する。partedコマンドのresizepartコマンドを使用する。
(resizepart 2 -1s
の 2
は物理パーティション番号を、-1s
はデバイス末尾のセクタ番号を意味する)
# parted /dev/mmcblk0
GNU Parted 3.6
Using /dev/mmcblk0
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted) resizepart 2 -1s
(parted) quit
Information: You may need to update /etc/fstab.
masaki@ice:~$ lsblk /dev/mmcblk0
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
mmcblk0 179:0 0 7.4G 0 disk
├─mmcblk0p1 179:1 0 512M 0 part /boot/firmware
└─mmcblk0p2 179:2 0 6.9G 0 part
└─mmcblk0p2-crypt 253:0 0 4G 0 crypt
└─vgmyhost-lvroot 253:1 0 2.5G 0 lvm /
- パーティション /dev/mmcblk0p2 は 6.9 GiB (拡張済み)
- LUKS領域としての /dev/mapper/mmcblk0p2-crypt は 4 GiB (拡張前)
cryptsetupコマンドのresizeコマンドにて、mmcblk0p2-crypt
としてマッピングしているLUKS領域を最大サイズまで拡張する。
# cryptsetup resize mmcblk0p2-crypt
Enter passphrase for /dev/mmcblk0p2: (パスフレーズを入力)
$ lsblk /dev/mmcblk0
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
mmcblk0 179:0 0 7.4G 0 disk
├─mmcblk0p1 179:1 0 512M 0 part /boot/firmware
└─mmcblk0p2 179:2 0 6.9G 0 part
└─mmcblk0p2-crypt 253:0 0 6.9G 0 crypt
└─vgmyhost-lvroot 253:1 0 2.5G 0 lvm /
# pvs
PV VG Fmt Attr PSize PFree
/dev/mapper/mmcblk0p2-crypt vgmyhost lvm2 a-- 3.98g 1.48g
- パーティション /dev/mmcblk0p2 は 6.9 GiB (拡張済み)
- LUKS領域としての /dev/mapper/mmcblk0p2-crypt は 6.9 GiB (拡張済み)
- 物理ボリュームとしての /dev/mapper/mmcblk0p2-crypt は 3.98 GiB (拡張前)
pvresizeコマンドにて、物理ボリュームを最大サイズまで拡張する。
# pvresize /dev/mapper/mmcblk0p2-crypt
Physical volume "/dev/mapper/mmcblk0p2-crypt" changed
1 physical volume(s) resized or updated / 0 physical volume(s) not resized
完了したら、ストレージの状況を確認する。
$ lsblk /dev/mmcblk0
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
mmcblk0 179:0 0 7.4G 0 disk
├─mmcblk0p1 179:1 0 512M 0 part /boot/firmware
└─mmcblk0p2 179:2 0 6.9G 0 part
└─mmcblk0p2-crypt 253:0 0 6.9G 0 crypt
└─vgmyhost-lvroot 253:1 0 2.5G 0 lvm /
# pvs
PV VG Fmt Attr PSize PFree
/dev/mapper/mmcblk0p2-crypt vgmyhost lvm2 a-- 6.88g 4.38g
- パーティション /dev/mmcblk0p2 は 6.9 GiB
- LUKS領域としての /dev/mapper/mmcblk0p2-crypt は 6.9 GiB
- 物理ボリュームとしての /dev/mapper/mmcblk0p2-crypt は 6.88 GiB
/var を論理ボリューム上に移す
lvcreateコマンドとmkfsコマンドにて、/var 用の論理ボリューム lvvar
とファイルシステムを作成する。
(ここでのサイズ 3 GiB は、以後の運用で /var が徐々に大きくなることを見越した大きめの値である)
# lvcreate --name lvvar --size 3G vgmyhost
Logical volume "lvvar" created.
# mkfs -t ext4 /dev/vgmyhost/lvvar
...
現在の /var の内容をコピーする。
# mount /dev/vgmyhost/lvvar /mnt
# rsync -AHXaxv /var/ /mnt/
...
# umount /mnt
/etc/fstab を編集し、/dev/vgmyhost/lvvar が /var としてマウントされるよう設定する。例えば下記のような行を追加する。
# <filesystem> <mountpoint> <type> <options> <dump> <pass>
+/dev/vgmyhost/lvvar /var auto nodev 0 2
...
記述後、下記のように古い /var を /var.orig に退避し、新しい /var をマウントする。
# mv /var /var.orig
# mkdir /var
# mount /var
すべてのプロセスが新しい /var を使うよう、再起動する。問題なければ、不要になった /var.orig を削除する。
/home を論理ボリューム上に移す
/var と同様に、/home 用の論理ボリューム lvhome
とファイルシステムを作成する。
# lvcreate --name lvhome --size 256M vgmyhost
Logical volume "lvhome" created.
# mkfs -t ext4 /dev/vgmyhost/lvhome
...
現在の /home の内容をコピーする。
# mount /dev/vgmyhost/lvhome /mnt
# rsync -AHXaxv /home/ /mnt/
sending incremental file list
...
# umount /mnt
/etc/fstab を編集し、/dev/vgmyhost/lvhome が /home としてマウントされるよう設定する。
例えば下記のような行を追加する。
# <filesystem> <mountpoint> <type> <options> <dump> <pass>
+/dev/vgmyhost/lvhome /home auto nodev 0 2
...
記述後、下記のように古い /home を /home.orig に退避し、新しい /home をマウントする。
# mv /home /home.orig
# mkdir /home
# mount /home
問題なければ、不要になった /home.orig を削除する。
移行後の構成
ストレージ構成
移行後のストレージ構成は下記のとおり。
-
パーティション構成
Partition No. Size Partition ID: Type Bootable? Primary 1 512.0 MiB 0x0c: W95 FAT32 (LBA) yes Primary 2 6.9 GiB 0x83: Linux no -
LUKSとLVMの構成
- ストレージの第2パーティション(/dev/mmcblk0p2)はLUKSで暗号化されている
- その暗号化されたパーティションはLVMの物理ボリュームである
- ボリュームグループ
vgmyhost
は、その物理ボリューム1つからなる - ルートファイルシステムやその他のファイルシステムはそれぞれの論理ボリュームに収められ、そのボリュームグループ
vgmyhost
に格納されている
-
ファイルシステム構成
Device Size Type Label Mount Point /dev/mmcblk0p1 512.0 MiB FAT32 system-boot /boot/firmware /dev/vgmyhost/lvroot 2.5 GiB Ext4 / /dev/vgmyhost/lvvar 3.0 GiB Ext4 /var /dev/vgmyhost/lvhome 256.0 MiB Ext4 /home
lsblkコマンドとdfコマンドによる表示結果は下記のとおり。
$ lsblk /dev/mmcblk0
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
mmcblk0 179:0 0 7.4G 0 disk
├─mmcblk0p1 179:1 0 512M 0 part /boot/firmware
└─mmcblk0p2 179:2 0 6.9G 0 part
└─mmcblk0p2-crypt 253:0 0 6.9G 0 crypt
├─vgmyhost-lvroot 253:1 0 2.5G 0 lvm /
├─vgmyhost-lvvar 253:2 0 3G 0 lvm /var
└─vgmyhost-lvhome 253:3 0 256M 0 lvm /home
$ df -h | grep -v tmpfs
Filesystem Size Used Avail Use% Mounted on
/dev/vgmyhost/lvroot 2.4G 1.7G 592M 75% /
/dev/mapper/vgmyhost-lvvar 2.9G 305M 2.5G 11% /var
/dev/mapper/vgmyhost-lvhome 224M 60K 206M 1% /home
/dev/mmcblk0p1 505M 136M 369M 27% /boot/firmware
鍵の配置
LUKSによる暗号化の鍵として、下記の2つが使用される。いずれかがあれば暗号化パーティションのロックを解除できる。
- 鍵ファイル (自動起動時に使用)
- パスフレーズ (復旧作業時などに使用)
鍵ファイルは、下記の箇所に置かれる。複数あるが、内容は同一である。
- 暗号化されたルートパーティション内
- /etc/keys/mmcblk0p2-crypt.key
- /boot/initrd.img-... 内の /cryptroot/keyfiles/mmcblk0p2-crypt.key
- 暗号化されていないブートパーティション /boot/firmware 内 (保護されていないため注意)
- ./initrd.img* 内の /cryptroot/keyfiles/mmcblk0p2-crypt.key
補足
暗号化されたストレージの性能
暗号化と復号のスループットは、cryptsetupのbenchmarkサブコマンドで測定できる。手元のRaspberry Pi 4 + Ubuntu Server 24.04 LTSでは、下記のような結果だった。
$ cryptsetup benchmark
# Tests are approximate using memory only (no storage IO).
PBKDF2-sha1 359101 iterations per second for 256-bit key
PBKDF2-sha256 603323 iterations per second for 256-bit key
PBKDF2-sha512 499321 iterations per second for 256-bit key
PBKDF2-ripemd160 305885 iterations per second for 256-bit key
PBKDF2-whirlpool 127501 iterations per second for 256-bit key
argon2i 4 iterations, 342224 memory, 4 parallel threads (CPUs) for 256-bit key (requested 2000 ms time)
argon2id 4 iterations, 344926 memory, 4 parallel threads (CPUs) for 256-bit key (requested 2000 ms time)
# Algorithm | Key | Encryption | Decryption
aes-cbc 128b 73.1 MiB/s 75.1 MiB/s
serpent-cbc 128b 38.7 MiB/s 39.0 MiB/s
twofish-cbc 128b 56.6 MiB/s 57.2 MiB/s
aes-cbc 256b 61.1 MiB/s 62.6 MiB/s
serpent-cbc 256b 38.7 MiB/s 39.0 MiB/s
twofish-cbc 256b 56.7 MiB/s 57.3 MiB/s
aes-xts 256b 101.6 MiB/s 103.1 MiB/s
serpent-xts 256b 44.3 MiB/s 45.1 MiB/s
twofish-xts 256b 71.4 MiB/s 70.8 MiB/s
aes-xts 512b 79.4 MiB/s 80.3 MiB/s
serpent-xts 512b 44.3 MiB/s 45.1 MiB/s
twofish-xts 512b 71.4 MiB/s 70.8 MiB/s
cryptsetupによるLUKS領域作成をデフォルト設定で行うと、暗号化方式は aes-xts-plain64、鍵長は 512 ビットになる。上記の Algorithm = aes-xts
、Key = 512b
で見ると、暗号化(write)のスループットは 79.4 MiB/sec、復号(read)のスループットは 80.3 MiB/secである。
前述のRaspberry Pi 4 + Ubuntu Server 24.04 LTSに2種類のストレージを接続してLUKS領域を設け、hdparmコマンドでreadスループットを計測したところ、下記の結果になった。
Device | LUKSあり? | read [MiB/sec] |
---|---|---|
microSDカード | なし | 21.63 |
microSDカード | あり | 22.41 |
USB接続のSSD | なし | 284.28 |
USB接続のSSD | あり | 81.85 |
復号のスループットが約80MiB/secなので、それよりもreadのスループットが低いmicroSDカードにLUKSを使っても性能は低下しないこと、スループットが高いUSB接続のSSDにLUKSを使うと性能が低下することがわかる。
(microSDカードの結果は、測定誤差の影響か、LUKSありのほうが性能が高くなっている)
なお、hdparmコマンドによる測定の様子は下記のとおり。/dev/mmcblk0 はmicroSDカード、/dev/sda はUSB接続SSDである。
# hdparm -t /dev/mmcblk0p2
/dev/mmcblk0p2:
Timing buffered disk reads: 66 MB in 3.05 seconds = 21.63 MB/sec
# hdparm -t /dev/mapper/mmcblk0p2-crypt
/dev/mapper/mmcblk0p2-crypt:
Timing buffered disk reads: 68 MB in 3.03 seconds = 22.41 MB/sec
# hdparm -t /dev/sda1
/dev/sda1:
Timing buffered disk reads: 854 MB in 3.00 seconds = 284.28 MB/sec
# hdparm -t /dev/mapper/sda1-crypt
/dev/mapper/sda1-crypt:
Timing buffered disk reads: 246 MB in 3.01 seconds = 81.85 MB/sec
鍵の管理方法の選択肢
本編で述べた方法を含め、鍵の管理方法の選択肢には例えば下記がある。いずれも素朴なもので、より本格的な方法は本記事では扱わない。
- 鍵はパスフレーズのみ
- 起動するたびに手動でパスフレーズを入力する必要がある
- 鍵ファイルをinitramfsイメージファイルに格納 (本編で述べた方法)
- 自動起動できる
- 鍵ファイルはブートパーティションに平文のままで置かれ、保護されない
- 鍵ファイルを鍵専用の別のストレージに格納
- 自動起動できる
- 鍵ファイルは鍵専用のストレージに平文のままで置かれ、電子的には保護されない
- システム停止中は、鍵専用のストレージと暗号化ストレージを物理的に隔離できる。
例えば、暗号化ストレージが故障した場合に、そのまま安全に廃棄できる
鍵の管理方法の設定は /etc/crypttab に対して行う。以降に、それぞれの方法での設定例を示す。
パスフレーズのみ
# <target name> <source device> <key file> <options>
mmcblk0p2-crypt UUID=... none luks
- 第1フィールドは、ロック解除後の /dev/mapper/ 内でのマッピング名。この例では /dev/mapper/mmcblk0p2-crypt になる
- 第2フィールドは、ロック解除対象の暗号化デバイスのデバイスファイル。
UUID=...
はデバイスUUIDによる指定である。デバイスUUIDはblkid -s UUID -o value /dev/mmcblk0p2
などとして確認できる - 第3フィールドは鍵ファイル。
none
が指定された場合には、コンソールにてパスフレーズ入力が促される - 第4フィールドはオプション。
luks
はLUKSを使用することを指定
鍵ファイルをinitramfsイメージファイルに格納
# <target name> <source device> <key file> <options>
mmcblk0p2-crypt UUID=... /etc/keys/mmcblk0p2-crypt.key luks
- 第3フィールドの鍵ファイル指定に、LUKSに登録した鍵ファイルのパスを記述する
(この例では鍵ファイルを /etc/keys/ に置いている) - 第3フィールド以外はパスフレーズのみの場合と同一
また、下記も設定する必要がある。
- /etc/cryptsetup-initramfs/conf-hook
-
KEYFILE_PATTERN="/etc/keys/*.key"
という1行を追記し、initramfsイメージファイル作成の際に /etc/keys/*.key を鍵ファイルとして扱うよう指示する
-
暗号化の鍵を /boot/initrd.img-... と /boot/firmware/initrd.img に埋め込むことになるため、これらのファイルのパーミッションを限定したいなら下記も設定する。
- /etc/initramfs-tools/initramfs.conf または /etc/initramfs-tools/conf.d/*.conf に
UMASK=0077
を記述 - /etc/fstab の /boot/firmware のエントリの第4フィールドのオプションに
umask=0077
を記述- /boot/firmware はFAT32ファイルシステムのため、ファイル単位のアクセス制限ができない。代わりにファイルシステム全体のパーミッションを制限する
ひととおり設定したら、update-initramfs -u
を実行してinitramfsイメージファイルに反映させる。
鍵ファイルを鍵専用のストレージに格納
# <target name> <source device> <key file> <options>
mmcblk0p2-crypt UUID=... /dev/disk/by-uuid/...:/keys/mmcblk0p2-crypt.key:10 luks,keyscript=passdev
- 第4フィールドのオプションに
,
(カンマ)で区切ってkeyscript=passdev
を追加し、/lib/cryptsetup/scripts/passdev という実行可能ファイルを使って鍵を扱うことを指定 - 第3フィールドに passdev に渡す引数を記述。
:
で区切られた各フィールドの意味は下記のとおり-
/dev/disk/by-uuid/...
: 鍵ファイルを収めたファイルシステムのデバイスファイルのパス。ここではデバイスをUUIDで指定している。...
には実際のUUIDを入れる -
/keys/mmcblk0p2-crypt.key
: そのファイルシステム内での鍵ファイルのパス -
10
: タイムアウト時間を秒単位で指定 (省略可能)
-
- 第3フィールドと第4フィールド以外はパスフレーズのみの場合と同一
鍵専用のストレージは、例えば下記のようにして準備すればよい。
- 鍵専用のストレージ上にパーティションを1つ作成
- そのパーティションにExt4ファイルシステムを作成
- そのファイルシステムに ./keys ディレクトリを作成
- 乱数を使って生成した鍵ファイルを ./keys/mmcblk0p2-crypt.key として保存 (手順は本編と同様)
- その鍵ファイルをLUKSに鍵として登録 (本編と同様)
鍵ファイルを収めたファイルシステムは、起動時に passdev によってreadonlyマウントされ、鍵読み取り後にアンマウントされる。システム稼働中は使用しないため、マウントする必要はない。
参考文献は下記。
- Debian Cryptsetup docs - README
- /usr/share/doc/cryptsetup-initramfs/README.initramfs.gz
- UbuntuやDebianなどのシステム内のローカルファイル
- passdevの使い方が記載されている
自動起動に失敗した場合の対処方法
initramfsによるルートファイルシステムの読み込みに失敗した場合は、コンソールを使用可能な状態で起動し、自動起動に失敗して表示されるinitramfsのコマンドプロンプトにて、下記のようにパスフレーズを使って暗号化パーティションのロックを解除すれば起動できる。
(initramfs) cryptsetup luksOpen /dev/mmcblk0p2 mmcblk0p2-crypt
Passphrase: (パスフレーズを入力)
(initramfs) exit
...
論理ボリュームをリサイズする手順
特定の論理ボリューム(例えば /dev/vgmyhost/lvhome)を拡張するには、lvextendコマンドを用いて例えば下記のようにする。
# lvextend --size +128M --resizefs /dev/vgmyhost/lvhome
Size of logical volume vgmyhost/lvhome changed from 256.00 MiB (64 extents) to 384.00 MiB (96 extents).
Logical volume vgmyhost/lvhome successfully resized.
resize2fs 1.47.0 (5-Feb-2023)
Filesystem at /dev/mapper/vgmyhost-lvhome is mounted on /home; on-line resizing required
old_desc_blocks = 1, new_desc_blocks = 1
The filesystem on /dev/mapper/vgmyhost-lvhome is now 98304 (4k) blocks long.
-
--size +128M
にて、現在のサイズを基準に 128 MiB 拡張するよう指示している - 引数
--resizefs
を指定しているため、論理ボリュームとともにファイルシステムもリサイズされる - ファイルシステムによるが、Ext4ファイルシステムであればマウントしたまま拡張できる
同様に、縮小にはlvreduceコマンドを使用する。
# lvreduce --size -128M --resizefs /dev/vgmyhost/lvhome
Do you want to unmount "/home" ? [Y|n] y
fsck from util-linux 2.39.3
/dev/mapper/vgmyhost-lvhome: 2788/98304 files (0.0% non-contiguous), 16679/98304 blocks
resize2fs 1.47.0 (5-Feb-2023)
Resizing the filesystem on /dev/mapper/vgmyhost-lvhome to 32768 (4k) blocks.
The filesystem on /dev/mapper/vgmyhost-lvhome is now 32768 (4k) blocks long.
mount: (hint) your fstab has been modified, but systemd still uses
the old version; use 'systemctl daemon-reload' to reload.
Size of logical volume vgmyhost/lvhome changed from 384.00 MiB (96 extents) to 128.00 MiB (32 extents).
Logical volume vgmyhost/lvhome successfully resized.
-
--size -128M
にて、現在のサイズを基準に 128 MiB 縮小するよう指示している - そのファイルシステム上のファイルをopenしているプロセスが存在すると、実行してもエラーになる。すべてのプロセスを止めてから再実行するか、あるいはホストを停止させて別のUnix環境にストレージを接続して実施するとよい
暗号化LVM領域のあるストレージを別ホストに接続して操作する手順
別のUnix環境に対象のストレージを接続したら、下記の順序で操作する。ここでは対象のストレージのデバイスを /dev/sdb、暗号化パーティションを /dev/sdb2 として記載する。
暗号化パーティションのロックを解除する。解除の際にはパスフレーズを使用する。
# cryptsetup luksOpen /dev/sdb2 sdb2-crypt
Enter passphrase for /dev/sdb2: (パスフレーズを入力)
ロックを解除すると、LVMの物理ボリューム・ボリュームグループ・論理ボリュームが自動で認識される。lsblkコマンドなどで認識されたことを確認する。
$ lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
...
sdb 179:0 0 7.4G 0 disk
├─sdb1 179:1 0 512M 0 part
└─sdb2 179:2 0 6.9G 0 part
└─sdb2-crypt 253:0 0 6.9G 0 crypt
├─vgmyhost-lvroot 253:1 0 2.5G 0 lvm
├─vgmyhost-lvvar 253:2 0 3G 0 lvm
└─vgmyhost-lvhome 253:3 0 256M 0 lvm
この状態にできたら、例えば /dev/vgmyhost/lvroot をリサイズするなど、目的の操作を行う。
目的の操作が完了したら、ボリュームグループと暗号化デバイスを停止させる。lsblkコマンドなどで停止したことを確認する。
# vgchange --activate n vgmyhost
0 logical volume(s) in volume group "vgmyhost" now active
# cryptsetup luksClose sdb2-crypt
$ lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
...
sdb 179:0 0 7.4G 0 disk
├─sdb1 179:1 0 512M 0 part
└─sdb2 179:2 0 6.9G 0 part
停止したことが確認できたら、メディアを取り外す。
参考文献
- ストレージ暗号化
- LUKS
- LVM
- LUKSとLVM
- GNU Parted
Discussion