2008-03-11
LinuxでLVM領域を暗号化: 導入
ファイルサーバのRAIDを暗号化したいなあと思案中。トラブルがない時はいいけど、故障したときに壊れたHDDをそのまま捨てるのはちょっといやだなあ、と。
てことでまずは手始めに、端末にしているPC-LinuxのLVM領域全体を暗号化してみることに。
変更前の構成は次のような感じ。
hda: /dev/hda1 Windows recovery /dev/hda2 Windows /dev/hda3 /boot /dev/hda5 swap /dev/hda6 / /dev/hda7 LVM PV - VG:vg0 LVM VG:vg0: /dev/vg0/lvusr 6G /usr /dev/vg0/lvvar 4G /var /dev/vg0/lvtmp 2G /tmp /dev/vg0/lvusrlocal 6G /usr/local /dev/vg0/lvhome 1G /home
このうち、hda7全体をdm-crypt+LUKSにて暗号化する。
カーネルなどの状態は次の通り。
必要なものは:
参考資料は:
- man
- cryptsetup(5)
- crypttab(8)
- lvm(8)
- dm-crypt website
- LUKS website
- ほか
方針は:
- LVM領域全体を暗号化する
- /、/boot、swapは暗号化しない
- LVM領域の暗号化鍵は、ファイル1つとパスフレーズ1つの2段構え。どちらか1つだけでも復号できる。ファイルな鍵は /etc/lvm/lvm.seckey として保管する
準備
hda7内の全データを外付けHDDなどに退避。
対象領域を乱数で埋める
暗号化前の領域が平文のまま未使用領域に残っていると意味がないので、まず対象領域を乱数で埋める。
single userモードで起動、hda7を使っていない状態にする。hda7全体を疑似乱数で塗りつぶす。
# dd if=/dev/urandom of=/dev/hda7 bs=`blockdev --getss /dev/hda7` count=`blockdev --getsize /dev/hda7`
手元のPCでは3Mbytes/secぐらい。相当待たされる。
横着したい場合は、swap領域あたりを使って適当な長さの乱数列を用意し、それを繰り返しコピーすることでお茶を濁してもよい。
ゼロ埋めで消すだけでも元の平文は消去できる。ただ、使用開始後に平文側を見ると、使用領域は非ゼロ・未使用領域はゼロとなるため、どこが使用領域なのかがわかってしまうという問題がある。
鍵の作成
後で出てくる通り鍵長は256ビット(= 32バイト)なので、32バイト長の鍵を作成。
# dd if=/dev/random of=/etc/lvm/lvm.seckey bs=1 count=32
LUKSパーティションの作成
まずパスフレーズで作成、続いてファイルな鍵を追加登録。
(順序は単なる好み。ファイルを先にした方が手数は少ない)
# cryptsetup --cipher aes-cbc-essiv:sha256 --key-size 256 luksFormat /dev/hda7 → パスフレーズを2回入力する # cryptsetup luksAddKey /dev/hda7 /etc/lvm/lvm.seckey → パスフレーズを1回入力する
状態確認。
# cryptsetup luksDump /dev/hda7 LUKS header information for /dev/hda7 Version: 1 Cipher name: aes Cipher mode: cbc-essiv:sha256 ... Key Slot 0: ENABLED Iterations: ... ... Key Slot 1: ENABLED Iterations: ... ... Key Slot 2: DISABLED Key Slot 3: DISABLED ...
dm-cryptデバイスの作成
/dev/hda7 を暗号化したブロックデバイスとして、/dev/mapper/crypt-hda7を作成する。
(マッピング後の名前には特に意味はない。お好みで)
# cryptsetup --key-file /etc/lvm/lvm.seckey luksOpen /dev/hda7 crypt-hda7
LVMとファイルシステムの構築
LVMのPV・VG・LVと各ファイルシステムを作成。構成は暗号化前のものと同一。
# pvcreate /dev/mapper/crypt-hda7 # vgcreate vg0 /dev/mapper/crypt-hda7 # lvcreate --size 6G --name lvusr vg0 # lvcreate --size 4G --name lvvar vg0 # lvcreate --size 2G --name lvtmp vg0 # lvcreate --size 6G --name lvusrlocal vg0 # lvcreate --size 1G --name lvhome vg0 # mkfs -t ext3 /dev/vg0/lvusr # mkfs -t ext3 /dev/vg0/lvvar # mkfs -t ext3 /dev/vg0/lvtmp # mkfs -t ext3 /dev/vg0/lvusrlocal # mkfs -t ext3 /dev/vg0/lvhome
起動時の設定
/etc/crypttabを編集。次の1行を追加。
crypt-hda7 /dev/hda7 /etc/lvm/lvm.seckey luks
再起動し、crypt-hda7上のLVM領域がちゃんと自動認識されることを確認。
なお、手元のDebian sid(この記事を書いている時点のもの)では、/etc/crypttabを読むのは/etc/rcS.d/S26cryptdisks-earlyで、/etc/rcS.d/S26lvm2よりも(僅差だが)先に起動されるようになっていた。
ファイルシステムの内容を復元
退避しておいた全データを復元。
動作確認
通常モードで再起動。元通り動作することを確認。
実に何事もなかったかのように動く。起動時のログにもうちょっと報告があっても良さそうなものだが... まあいいか。
課題とか諸々
- 鍵が2つなのはなぜ?
- ファイルな鍵は人手を介さずにbootするため。パスフレーズな鍵はファイルな鍵を失ってもデータを読み出す手段を残しておくため
- 鍵が同一ストレージ上に生のまま入っていると意味ないのでは?
- その通り。まああくまでテストなので。
対象が端末的なものなら、再起動時に対話的操作を伴ってもよいので、ファイルな鍵を削除して起動時にパスフレーズを入れさせるという運用もあり。
対象がサーバなら、人がいないと再起動できないようでは困るので、物理的に異なるストレージデバイスに鍵を入れるなどが現実的か - /とか/bootは暗号化しないの?
- 難しそうなのでパス。どのぐらいできるのかも調べていない
- swapは暗号化しないの?
- 同上。ハイバネーションとの兼ね合いも未調査
- 性能は?
- これから測ってみる
- 3 http://www.google.co.jp/search?sourceid=navclient&hl=ja&ie=UTF-8&rls=GGLC,GGLC:1970-01,GGLC:ja&q=splay+Code
- 2 http://www.google.co.jp/search?q=svn ブランチ&hl=ja&lr=lang_ja&start=10&sa=N
- 1 http://d.hatena.ne.jp/asin/4274065979/hatenadiar02e-22
- 1 http://d.hatena.ne.jp/keyword/ソフトウェアRAID
- 1 http://d.hatena.ne.jp/y_sekiuchi/20080309/1205065135
- 1 http://www.google.co.in/search?q=modules+of+splay+trees&hl=en&start=10&sa=N
- 1 http://www.google.co.jp/hws/search?hl=ja&q=Raid+罎????&client=fenrir&adsafe=off&safe=off&lr=lang_ja
- 1 http://www.google.co.jp/hws/search?q=subversion+ブランチ+マージ&client=fenrir&safe=off&adsafe=off&hl=ja&lr=lang_ja&ie=UTF-8&oe=UTF-8&start=10&br=
- 1 http://www.google.co.jp/search?client=firefox-a&rls=org.mozilla:ja:official&channel=s&hl=ja&q=C+++ポリシー+クラス&lr=&btnG=Google+検索
- 1 http://www.google.co.jp/search?hl=ja&client=firefox-a&rls=org.mozilla:en-US:official&hs=uL4&q=man+lzma&btnG=検索&lr=lang_ja