先日、CentOS7 : システム全体を暗号化したOSの自動起動(LVM on LUKS)という記事を公開しましたが、その内容は暗号化を実質的に無意味にするもので、実用に耐えませんでした。
今回は、前回をベースに試行錯誤し、ある程度有用な実装方法を考えましたので、公開します。
設計思想
暗号化解除に使う鍵を常時アクセス可能な場所に保存することは、暗号化を無意味にすることです。
今回は、必要なときだけ保存することとし、運用中は鍵を無効化するという発想です。ワンタイムパスワードと同じ発想ですね。
再起動する際に、わざわざコンソールを開いてパスフレーズを入力するのは手間ですし、再起動が必要な時にコンソールにアクセスできる環境が確保できるとは限らず、こういった問題を解消する一つのソリューションになるものと思います。
Step1: 暗号化構成
CentOS7 : システム全体を暗号化したOSの自動起動(LVM on LUKS)の通り、暗号化構成を行います。
Step2: マスターキーの作成と登録
/boot/keyfile に保存される鍵を有効にしたり無効にしたりするための鍵を作成し登録します。
1 2 3 4 5 6 |
sudo mkdir /etc/LUKS-KEY/ sudo touch /etc/LUKS-KEY/keyfile sudo chmod 400 /etc/LUKS-KEY/keyfile sudo dd if=/dev/urandom of=/etc/LUKS-KEY/keyfile bs=1 count=4096 sudo chattr +i /etc/LUKS-KEY/keyfile sudo cryptsetup -v luksAddKey /dev/sda2 /etc/LUKS-KEY/keyfile -d /boot/keyfile |
Step3: ブートキーの更新スクリプトの作成
/boot/keyfile を作成したり削除したり、キースロットに登録したり抹消したりするスクリプトを作成します。
1 |
sudo vi /usr/sbin/luks-key-maker |
シェルスクリプトは書き慣れてないので間違えてたら教えてください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
#!/bin/bash # Copyright 2018 WWW.ABTEN.NET # 暗号化されたドライブのパス LUKS_DEVICE="/dev/sda2" # マスターキーの保存パス MASTER_KEY="/etc/LUKS-KEY/keyfile" # ブート時に使用するキーのパス BOOT_KEY="/boot/keyfile" CMDNAME=`basename $0` LOCKFILE="/tmp/luks.lock" if [ -f ${LOCKFILE} ]; then echo '"'${LOCKFILE}'"ファイルが存在します' echo '安全のため処理を中止します。' elif [ -f ${MASTER_KEY} ]; then # ロックファイルを作成します。 touch ${LOCKFILE} [ "$2" != "quiet" ] && echo '処理を開始します。' if [ "$1" = "make" ]; then [ "$2" != "quiet" ] && echo '"make"オプションが指定されました。' if [ -f ${BOOT_KEY} ]; then echo '"'${BOOT_KEY}'"ファイルが存在します' echo '安全のため処理を中止します。' echo '"'${CMDNAME}' delete"を実行してから再度"'${CMDNAME}' make"を実行してください。' else touch ${BOOT_KEY} chmod 400 ${BOOT_KEY} dd if=/dev/urandom of=${BOOT_KEY} bs=1024 count=8 status=noxfer > /dev/null 2>&1 chattr +i ${BOOT_KEY} cryptsetup luksAddKey ${LUKS_DEVICE} ${BOOT_KEY} -d ${MASTER_KEY} fi elif [ "$1" = "delete" ]; then [ "$2" != "quiet" ] && echo '"delete"オプションが指定されました。' if [ -f ${BOOT_KEY} ]; then cryptsetup luksRemoveKey ${LUKS_DEVICE} ${BOOT_KEY} chattr -i ${BOOT_KEY} shred --remove ${BOOT_KEY} else echo '"'${BOOT_KEY}'"ファイルが存在しません' fi elif [ "$1" = "reboot" ]; then [ "$2" != "quiet" ] && echo '"reboot"オプションが指定されました。' # ブートキーが存在していれば、いったん削除無効化する if [ -f ${BOOT_KEY} ]; then cryptsetup luksRemoveKey ${LUKS_DEVICE} ${BOOT_KEY} chattr -i ${BOOT_KEY} shred --remove ${BOOT_KEY} fi # ブートキーを生成し、キースロットに登録する touch ${BOOT_KEY} chmod 400 ${BOOT_KEY} dd if=/dev/urandom of=${BOOT_KEY} bs=1024 count=8 status=noxfer > /dev/null 2>&1 chattr +i ${BOOT_KEY} cryptsetup luksAddKey ${LUKS_DEVICE} ${BOOT_KEY} -d ${MASTER_KEY} # ロックファイルを削除します。 rm -f ${LOCKFILE} # 再起動の実行 shutdown -r now exit 0 else echo '第1引数は"make" "delete" "reboot" のいずれかを指定する必要があります。' echo '第2引数に"quiet"を指定すると標準出力を抑制します。' fi # ロックファイルを削除します。 rm -f ${LOCKFILE} else echo '"'${MASTER_KEY}'"ファイルが存在しません。' echo '安全のため処理を中止します。' fi exit 0 |
適当なパーミッションを設定します。
1 |
sudo chmod 700 /usr/sbin/luks-key-maker |
Step4: カスタムユニットファイルの作成
OS 起動時に、/boot/keyfile の鍵を無効化するために、カスタムユニットファイルを作成します。
1 2 3 4 |
sudo touch /usr/lib/systemd/system/luks-key-renew-cmd.service chmod 664 /usr/lib/systemd/system/luks-key-renew-cmd.service ln -s /usr/lib/systemd/system/luks-key-renew-cmd.service /etc/systemd/system/multi-user.target.wants/luks-key-renew-cmd.service vi /usr/lib/systemd/system/luks-key-renew-cmd.service |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# Copyright 2018 WWW.ABTEN.NET [Unit] Description=LUKS-KEY-RENEW After=cryptsetup.target lvm2-lvmpolld.socket Requires=cryptsetup.target lvm2-lvmpolld.socket [Service] Type=oneshot User=root Group=root ExecStart=/usr/sbin/luks-key-maker delete quiet [Install] WantedBy=multi-user.target |
設定を有効化します。
1 2 |
sudo systemctl daemon-reload sudo systemctl enable luks-key-renew-cmd.service |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
# Copyright 2018 WWW.ABTEN.NET [Unit] Description=LUKS-KEY-RENEW After=cryptsetup.target lvm2-lvmpolld.socket Requires=cryptsetup.target lvm2-lvmpolld.socket [Service] Type=simple User=root Group=root ExecStart=/usr/sbin/luks-key-maker delete quiet ExecStop=/usr/sbin/luks-key-maker make quiet RemainAfterExit=true [Install] WantedBy=multi-user.target |
この場合、ctrl + alt + delete や シャットダウン時にも、鍵が自動的に再生成されるので、暗号化が無意味になってしまうかも知れません。
鍵を無効化して終了させるためには、以下の手順が必要になります。
1 2 |
sudo systemctl stop luks-key-renew-cmd.service sudo /usr/sbin/luks-key-maker delete |
サーバに物理的にアクセス可能な第三者によって、サービスを正常終了されると、鍵が自動的に再生成さる点に留意する必要があります。
Step5: bash alias の設定など
詳細は割愛しますが、以下のコマンドを実行してから再起動すると、起動時のパスワード入力をスキップできます。
1 |
sudo luks-key-maker make |
このコマンドで /boot/keyfile が作成されると同時に、キースロットに登録されます。
再起動後は、サービスが自動的にキースロットの解放と /boot/keyfile の削除を行います。
再起動を取りやめて、作成された /boot/keyfile を手動で削除する場合は、以下のコマンドを実行すると再起動後と同じ状態になります。
1 |
sudo luks-key-maker delete |
reboot コマンドなどのエイリアス設定を適切に書き変えると、煩雑な作業から解放されるかもしれません。
1 2 |
# ex.luks-key-maker(luks-key-renew-cmd.service) alias reboot='sudo luks-key-maker make quiet && sudo reboot' |
あるいは
1 2 3 |
# ex.luks-key-maker(luks-key-renew-cmd.service) alias sudo='sudo ' alias reboot='luks-key-maker reboot quiet' |
など。
セキュリティ上の留意点
OS 起動後は /boot/keyfile のキーが無効化されたうえで削除されますので、その時点で物理的にストレージが盗難されたとしても安全な状態が維持されます。
システムがいつ再起動のために “luks-key-maker make” を実行するかは、通常外部から認識できないでしょうから、成立可能性の低い攻撃といえるでしょう。
仮に、VPS などのサービス管理者(ホスト)が、逐一データの状態を監視復元できたとすれば、再起動時に危殆化される訳だが、そのような状況下においてコンソールにパスフレーズを入力することは、キーストロークの監視蓄積だけでよいことから比較的容易であり、”luks-key-maker make” を使った再起動時のパスフレーズ入力スキップはセキュリティレベルの向上に資するものと考えています。