Chienomi

メインシステムをEncFS on BtrfsからBtrfs on dm-cryptに変更

zsh

  • TOP
  • Old Archives
  • メインシステムをEncFS on BtrfsからBtrfs on dm-cryptに変更

概要

散々やるよといっていた構成変更だが、ついに実行した。

作業はかなり面倒で、1時間半ほどかかってしまった。

今までは次のようになっていた。

  • 4ディスクによるBtrfsを編成
  • Btrfsはサブボリュームを持つ
  • ひとつのサブボリュームを丸々EncFSとする
  • .zshrcでencfsコマンドを呼び、マウントする

この方法のメリットは次のようなものだ

  • 強力で柔軟な暗号化
  • ファイル単位でのバックアップが、暗号化したまま可能
  • 手軽
  • rootでもユーザーデータにアクセスできないので、かなり安全

一方デメリットは次のようなもの

  • rootでユーザーデータにアクセスできないとKVMが暗号化されたディスクにイメージを置けないなど結構不便
  • 特にバックアップで困る
  • ファイルアクセスは常にEncFSがトップ。どのプロセスがIO負荷になっているのかわからない

下準備

先日のrsoftmirrorとrsyncを使ってデータをすべてスレーブにバックアップ

dm-crypt

4kBのurandomデータをめちゃくちゃに暗号しまくって、その中から512Bを切り出す方法で鍵ファイルを作成。これを使う。

cryptsetup --hash=sha512 --key-size=512 --ciper="twofish-xts-plain" --offset=0 key-file=/etc/worldencmount/keyfile --type=plain open device name

単にopen。LUKSではluksFormatという専用のアクションがあるが、プレーンだとない。 ちなみに、twofish-xts-plain結構遅い

これをしただけだとBtrfsの存在はblkidでは残っているように見えてしまう。 そこでrebootするのだが、その前に/etc/fstabを編集してbtrfsをマウントしないようにしておかないと痛い目を見る。

Btrfs

リブートしたら暗号化を行うのと同じ手順でデバイスをオープンする。 Btrfsはそのオープンしたデバイスに対して行う。

# mkfs.btrfs -m raid1 -d raid1 -l WorldBtrfs /dev/mapper/world_enc_*

ちなみに、ストライプで高速化するのではなく、ミラーで分散してもらうことにした。 ミラーするかどうかは悩んだのだが、やはり安全をとってミラー。つまり、2ミラー、1バックアップになる。

サブボリュームを作ることを忘れていて若干ハマった。

# mount /dev/mapper/world_enc_1 /mnt/1
# cd /mnt/1
# btrfs subvolume create shared-world

設定ファイルにblkidでdm-cryptのPARTUUIDを送り込んでおく。 また、btrfsのUUIDを/etc/fstabに送り込んでおく。

# blkid | grep -F /dev/mapper/world_enc_* | tail -n 1 >> /etc/fstab

そしてvim

# vim /etc/fstab

コピペしてUUIDを書き換え、ゴミを消去し、コメントアウトを外し、noautoオプションを追加する。

修正

そういえばこの方法はdiskのパーティションを暗号化している。 これは推奨される方法だが、やはりできればwhole diskの暗号化をしたい。 LUKSも含め3TB以上のwhole diskの暗号化には対応している。

だが、そうするとかなり重大な問題が生じる。 PARTUUIDやPARTLABELが使えなくなるのだ。

これは結構困ったことで、どうしたものかと思ったが、/dev/disk/by-idを使うことにした。 これはWWIDと呼ばれる、システムに依存しないデバイスに対して永続的なIDであるという。 若干手間だが、確実だ。

ちなみにこの修正、同期がかなり進んだ段階でリセットする形で行った。 この修正に30分くらいかかってしまった。

セットアップスクリプト

#!/usr/bin/zsh

#read config file.
. /etc/worldencmount/worldrc || exit 1

#decryption
for disk in "${disks[@]}"
do
  cryptsetup --hash=sha512 --key-size=512 --cipher="twofish-xts-plain" --offset=0 --key-file=${keyfile:-/etc/worldencmount/seedfile} --type=plain open "$disk" dmcw_${disk:t}
done

.zshrc

#Check shared zshrc file.

if [[ -e $HOME/share/.zshrc ]]
then
  # Enable shared zshrc
  . $HOME/share/.zshrc
else
  # Disabled shared zshrc.
  
  print ~/share/.zshrc "is not exist." >&2
  print "Probably encrypted filesystem don't mount yet." >&2
  print "Let's mount it!" >&2
  print >&2
  
  ## Decryption ##
  if sudo btrfs filesystem show | grep -F -q HydrangeaMasterBtr
  then
    print "Btrfs filesystem already active." >&2
  else
    if sudo /usr/local/sbin/worldencmount
    then
      print "Okay, succeed to decrypt." >&2
    else
      print "Oh, failed to decrypt disks." >&2
      print "Aborting..." >&2
      exit 2
    fi
  fi
  
  ## Mount ##
  if sudo mount ~/share
  then
    print "Okay, succeed to mount the filesystem." >&2
    print "You can use the World." >&2
    exit 0
  else
    print "Gosh! failed to mount. I don't know why." >&2
    print "Please fix it." >&2
    exit 3
  fi
fi

いままでよりだいぶ複雑になった。 結局、自動マウントではなく.zshrcで処理するようにした。 このほうが合理的だ。

slave側の自動マウント

逆にslave側は常にマウントされているべきなので、systemdユニットを書く。

[Unit]
Description=Mount World filesystem.
After=network.service

[Service]
ExecStart=/usr/local/sbin/worldmount

[Install]
WantedBy=multi-user.target

そして自動起動

# systemctl enable worldmount

ものすごく手抜きで、実はまだテストしていないが、動くはずだ。 ちなみにCentOS7である。

同期

rsyncで新たに作られた~/shareに同期する。 これは復旧作業なので通常とは逆方向のsyncとなる。 結果的には約14時間かかった。gzipのためか時間はかかったが、容量は2.02TiBと約2/3に抑えられた。

鍵のバックアップ

鍵ファイルがなくなると困るのでバックアップ。 しかしそれだけでは暗号化している意味がないので、鍵ファイルも暗号化した上でCD-Rに焼く。 暗号化はopensslのencを使うのが手っ取り早く、確実。 復号化用のスクリプトも同梱した。

総論

今回の作業はそれなりにしんどかったが、それでも同期を別とすれば1時間半ほどで終了した。 (ただしそれは最初にしたようにパーティションベースで行った場合のみの話)

元々EncFSにしたのは暫定的な措置だったし、スレーブサーバー設置に伴ってこういった作業をすることは想定していた。