Mac で Bluetooth キーボード + FileVault 使うと再起動時に困る件を根本的に解決する

Macbook の内蔵キーボードや、Apple 純正の Bluetooth キーボードを使っている場合は問題ないんです。以下の条件が重なると、Mac 再起動時に詰むことになります。

- Apple 製以外の Bluetooh キーボードを使っている。
- ストレージを [FileVault][] で暗号化している。
- → すると、再起動時のパスワード入力欄でキーボードが反応せず、ログイン出来ない！！

[filevault]: https://support.apple.com/ja-jp/HT204837

今回の記事はそれを解決する Tips です。

## FileVault の問題

FileVault とは macOS に搭載されている、ストレージ全体を暗号化し、不正なアクセスを防いでくれる機能です。Windows で言う、BitLocker のようなものですね。特に業務で利用する端末では必ず有効化すべき機能です。

OS の再起動時にはパスワードを入力してストレージを復号するのですが、この時、macOS ではセキュリティ要件が厳しく、Apple 純正のキーボード以外は認識してくれないのです（有線接続なら大丈夫）。

## 一時的な解決法

これでは実質、3rd パーティのキーボードが使い物になりません。回避策は一応用意されていまして、ググると以下のように案内されています。

[FileVault2 のロックを解除した状態で Mac を再起動する方法 - 工事中](https://tmkymd.go5.jp/posts/filevault2authrestart/)

```sh
# 次回起動する時に要求されるパスワードを予め入力しておく
sudo fdesetup authrestart -delayminutes -1
```

これを起動時に毎回打ち込めばいいんです……って、それ面倒じゃないですか？　忘れちゃいませんか？　 Macbook ならいいんですよ。蓋開ければすぐそこに内蔵キーボードがあるんですから。でも Mac mini では？　 iMac では？　忘れたまま左上の林檎マークから再起動しちゃって「ああああああ！！？」ってなったことありますよね？

## 毎回自動的に `fdesetup` する

そう。↑ の入力自体、Mac を起動する度、自動でやるようにすればいいんです。先に手順から書きましょう。

### スクリプトの準備

先ず、以下のようなシェルスクリプトを作成します。ファイル名は任意の物で構いませんが、ディレクトリは `/etc/` などのシステムディレクトリが良いです（理由は後述）。

```sh
sudo vim /etc/authrestart.sh
```

```bash
#!/bin/bash -eu
username=$(/usr/bin/security find-generic-password -a authrestart -s username -w)
password=$(/usr/bin/security find-generic-password -a authrestart -s password -w)
(
  /usr/bin/fdesetup authrestart \
    -user $username \
    -delayminutes -1 \
    -verbose \
    -inputplist \
    << EOD 2>&1
      <plist>
        <dict>
          <key>Password</key>
          <string>$password</string>
        </dict>
      </plist>
EOD
) | /usr/bin/perl -MTime::Piece -nE 'print localtime->strftime("%FT%T") . " $_"'
```

次に以下のようなファイルを作ります。こちらもシステムディレクトリに置きますので、`sudo` が必要です。ファイル名は適当で構いません。

```sh
sudo vim /Library/LaunchDaemons/dev.delphinus.fdesetup.authrestart.plist
```

```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>Label</key>
	<string>dev.delphinus.fdesetup.authrestart</string>
	<key>ProgramArguments</key>
	<array>
    <string>/bin/bash</string>
    <string>/etc/authrestart.sh</string>
	</array>
	<key>RunAtLoad</key>
	<true/>
  <key>StandardOutPath</key>
  <string>/var/log/dev.delphinus.fdesetup.authrestart.log</string>
  <key>StandardErrorPath</key>
  <string>/var/log/dev.delphinus.fdesetup.authrestart.err.log</string>
</dict>
</plist>
```

### ユーザー名とパスワードの登録

最後に、ユーザー名とパスワードをキーチェーンに登録しましょう。

```sh
sudo security add-generic-password -a authrestart -s username -w 'あなたのユーザー名' /Library/Keychains/System.keychain
sudo security add-generic-password -a authrestart -s password -w 'あなたのパスワード' /Library/Keychains/System.keychain
```

「あなたの～」は実際のものに書き換えて下さい。ユーザー名は良いとして、そのまま打ち込むとパスワードがシェルのヒストリーに残ってしまいます。これが気になる人は冒頭にスペースを入れましょう（`bash` や `fish` で確認しました）。

```sh
# ↓シェルのヒストリーに記録される。
sudo security add-generic-password -a authrestart -s password -w 'あなたのパスワード' /Library/Keychains/System.keychain
# ↓シェルのヒストリーに記録されない！
 sudo security add-generic-password -a authrestart -s password -w 'あなたのパスワード' /Library/Keychains/System.keychain
```

`security` コマンドはキーチェーンへアクセスするときに使うコマンドです。今回は通常の使い方と異なり、ユーザーのキーチェーンではなく、システムのそれに書き込んでいます。こうしないとログイン前にアクセス出来ないんです。

最後の `/Library/Keychains/System.keychain` というのがシステムキーチェーンを表すパスなのですが、これはひょっとすると macOS のバージョンによって異なるかもしれません。これは以下のようにして確認出来ます。

```sh
security list-keychains

    "/Users/jinnouchi.yasushi/Library/Keychains/login.keychain-db"
    "/Library/Keychains/System.keychain"
```

### 再起動してみる

これで完了です。再起動してみると、ログに以下のように吐かれていたら成功です。次回から再起動するときは FileVault の復号のための入力画面が出なくなっているはずです（とはいえ、ログイン自体には相変わらずパスワードが必要です）。

```sh
cat /var/log/dev.delphinus.fdesetup.authrestart.log

2022-05-11T12:34:56 fdesetup: auth info dictionary path = stdin
2022-05-11T12:34:56 fdesetup: device path = /
2022-05-11T12:34:56 fdesetup: auth restart delay minutes = -1
```

## トラブルシューティング

### ログに何も記録されない

おそらく `fdesetup` が起動していません。このような時は [launchd][] 自体のログを見ましょう。場所は `/var/log/com.apple.xpc.launchd` です。

[launchd]: https://www.launchd.info

```sh
# 今回作成した plist の物だけを表示する
grep authrestart /var/log/com.apple.xpc.launchd/launchd.log
```

### `Permission Denied`

上記ログを見ていると以下のように表示されていることがあります。

```
service could not initialize: posix_spawn(/bin/sh) error: 0xd: permission denied
```

こういうの何の情報も無くて困るのですが、おそらくスクリプトの置き場所が問題です。セキュリティ上の問題から、起動時に実行されるファイルは `/Users/hoge` などのホームディレクトリにはアクセス出来ません。手順で `/etc/` 配下にスクリプトを置いたのはそれが理由です。

### 電源入れる時はどうするの……？

どうにも出来ません。再起動ではなく、「システム終了」してしまうとこの技は使えません。これはどうしようもない……。諦めて有線接続するか、Apple 製のキーボードを使いましょう。

## おまけ

折角買った RealForce R3 がこれでやっと使い物になった！