ZFS on GELI
COVID-19のせいで、会社のMacBook Airを平日は毎日持ち歩いている。 万一の紛失や盗難に備えて、つい先日(今更)FileVaultを有効化してこのMBAのローカルストレージを暗号化した。 勢いで、私物のMacBook Proも暗号化した。
こうなると、次はXigmaNASで稼働している自宅のNASが気になる。 これにはTime Machineのバックアップが載っているが、Time Machineにはバックアップデータを暗号化する機能はない。 ローカルストレージは暗号化されているのにそのバックアップデータは平文という、この片手落ち感。
NASを暗号化、しよう。
XigmaNASのベースOSであるFreeBSDでは、現時点ではZFSのnative encryptionを利用できない。 なので、GELI (GEOM ELI) を使うというのが順当な選択肢になる。
FreeBSDに関してはnewbieなので正確性に欠けるかもしれないけれども、調べた限りではこういうことらしい。
- GELIはブロックデバイスレイヤーでストレージの暗号化を行なう
- ZFSは、GELIが提供する論理ブロックデバイスも物理デバイスと同様に扱うことができる
つまりGELIとZFSはレイヤーが異なり、オペレーションも完全に独立している。 最初は何だか複雑で面倒な構成だと思っていたけれど、理解してしまうとこれはこれで明快に思える。
最終目標は、既存のzpoolの冗長性を確保したまま、すべてのデバイスをGELIデバイスに交換すること。
既存のzpoolに、以下のようなmirror vdevが一つある。 ここに新たにGELIデバイスをattachして、一時的に3-way mirrorの構成とする。 空きベイは少なくとも一つあるものとする(ないと辛い)。
# zpool status
[...]
config:
NAME STATE READ WRITE CKSUM
tank ONLINE 0 0 0
mirror-0 ONLINE 0 0 0
ada0p1 ONLINE 0 0 0
ada1p1 ONLINE 0 0 0
[...]
新しいディスクにパーティションを整備する。 HDDの総セクタ数は、たとえ同じベンダー・同じモデルでも僅かに異なることがある(経験談)。 せっかく用意したHDDがその僅かな差のせいで使えない、というリスクは許容し難いので、余裕を残して使うことにしている。 ただし256MiBという数字に深い根拠はない。
# gpart create -s gpt ada2
# gpart add -t freebsd-zfs -a 4k -s <calculate_yourself> -i 1 ada2
# gpart show ada2
=> 34 5860533101 ada2 GPT (2.7T)
34 6 - free - (3.0K)
40 5860008800 1 freebsd-zfs (2.7T)
5860008840 524295 - free - (256M)
作成したパーティションをGELIで初期化してattachする。
# geli init -b -e AES-XTS -l 256 -s 4096 /dev/ada2p1
# geli attach /dev/ada2p1
# geli status
Name Status Components
ada2p1.eli ACTIVE ada2p1
GELIデバイスをvdevにattachし、resilverが完了するのを待つ。 無事3-way mirrorの状態になれば、既存のディスクを安全に(データの冗長性を確保したまま)detachすることができる。
# zpool attach tank ada1p1 ada2p1.eli
# zpool status
[...]
config:
NAME STATE READ WRITE CKSUM
tank ONLINE 0 0 0
mirror-0 ONLINE 0 0 0
ada0p1 ONLINE 0 0 0
ada1p1 ONLINE 0 0 0
ada2p1.eli ONLINE 0 0 0
[...]
あとは、残りの未暗号化ディスクについて以下の手順を繰り返す。
- vdevからdetachする
- (必要があれば)パーティションテーブルを調整する
- GELIで初期化しattachする
- GELIデバイスをvdevにattachする
GELIに関していくつか。
BOOTフラグに頼らず、OS起動後にリモートから手作業でattachする運用も考えはしたが、逆に手間がかかりそうなので諦めた。 KVMレスでは運用できなくなってしまうが、ストレージが整った状態でOSに引き渡す方が(特にXigmaNASのようなembeddedな環境では)無用なトラブルも避けられるだろう。
サイズを見比べるとGELIには4KiBのオーバーヘッドがあるように見える。 頭の片隅には置いておいた方が良いかもしれない。
# geli list
[...]
Providers:
1. Name: ada2p1.eli
Mediasize: 3000324501504 (2.7T)
Sectorsize: 4096
Mode: r0w0e0
Consumers:
1. Name: ada2p1
Mediasize: 3000324505600 (2.7T)
Sectorsize: 512
Stripesize: 4096
Stripeoffset: 0
Mode: r1w1e1
GELIにはチェックサムによる整合性検証の機能もあるが、ZFSと組み合わせる場合はZFSに任せてしまうのが一般的らしい。 実際のところ、敢えてGELIにやらせても単にリソースの無駄遣いだろう。
参考文献