【ヘッドレス】Raspberry Pi 3 セットアップ for macOS

散々同様の記事は投稿されていますが，備忘録として書き残します．
今回は，Raspberry Piにヘッドレス(=ディスプレイなし)でセットアップします．（リンクの一部にアフェリを含みます．）

## 環境など
* 作業 PC: macOS Monterey 12.6
* 本体: Raspberry Pi 3 MODEL B (Raspberry Pi 3 MODEL B+ でも同様でした)
* SDカード: [TOSHIBA EXCERIA microSDHC16GB Class10 UHS-1対応 最大読込速度48MB/s 防水/耐X線 海外パッケージ品 THN-M301R0160A4](http://amzn.to/2BTBcnU)
    * 用途的に容量は少なくてよかったので，16GBを選択しました．
    * この商品は日本国内でのサポートは受けれないので注意しましょう．
* 書き込むOS: Raspberry Pi OS (2022-09-22)
    * Raspberry Pi OS Lite: 最小限のイメージ．CUI 環境．
    * Raspberry Pi OS with desktop: デスクトップ付きイメージ．
    * Raspberry Pi OS with desktop and recommended software: デスクトップ付き，推奨ソフトウェア入り．

## やること
* OSのダウンロード
* OSをSDカードに書き込む
* SSHの有効化，Wi-Fiの設定
* Raspberry Piの起動
* Raspberry Piの設定

## OSのダウンロード
今回は，Raspberry Pi OS (Raspberry Pi OS Lite) をインストールする．[^1]
[^1]: まぁ，今回の私の用途ではGUIはいらないので…

[Operating system images – Raspberry Pi](https://www.raspberrypi.com/software/operating-systems/)からRaspberry Pi OS LiteをDownload ZIPをクリックしてダウンロードする．
`$ wget https://downloads.raspberrypi.com/raspios_lite_armhf_latest` (32bit版)， `$ wget https://downloads.raspberrypi.com/raspios_lite_arm64_latest` (64bit版) でダウンロードしても良い．
ダウンロードは環境によっては結構時間がかかるので，気長に待つ．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59163/2d3f759b-0af0-c9bc-62da-300aa523f304.png)

（「Show SHA256 file integrity hash:」をクリックするとファイルハッシュが表示される）

ダウンロードが完了したら，一応ファイル破損がないか確かめる:

```shell-session
$ openssl sha256 2022-09-22-raspios-bullseye-arm64-lite.img.xz
SHA256(2022-09-22-raspios-bullseye-arm64-lite.img.xz)= 72c773781a0a57160eb3fa8bb2a927642fe60c3af62bc980827057bcecb7b98b
```

一致しているので，大丈夫ですね👌．

## OSをSDカードに書き込む
まずはxzファイルの解凍する:

```shell-session
$ unxz 2022-09-22-raspios-bullseye-arm64-lite.img.xz # 64bit
$ unxz 2022-09-22-raspios-bullseye-armhf-lite.img.xz # 32bit
```

※ unxz コマンドがない場合は `$ brew install xz` でインストールできるはず．

その後，純正の変換器(USB-C Digital AV Multiportアダプタ)と，[サンワサプライのUSB2.0カードリーダ(ADR-ML158K)](http://amzn.to/2otmnky)を使って，microSDHCを挿入する．
（もちろん別ので良い）

そしたら，SDカードのマウント先を確認する:

```shell-session
$ diskutil list
...
/dev/disk2 (external, physical):
...
```

次にSDカードをFAT32でフォーマットする(今回はSDカードのマウント先が`/dev/disk2`という想定):

```shell-session
$ diskutil eraseDisk FAT32 RPI /dev/disk2
```

フォーマット後，ddコマンドでの書き込みのため，SDカードをアンマウントする:

```shell-session
$ diskutil unmountDisk /dev/disk2
```

最後に，ddコマンドでSDカードにOSイメージを書き込む:

```shell-session
$ sudo dd bs=1m if=2022-09-22-raspios-bullseye-arm64-lite.img of=/dev/rdisk2 conv=sync # 64bit
$ sudo dd bs=1m if=2022-09-22-raspios-bullseye-armhf-lite.img of=/dev/rdisk2 conv=sync # 32bit
```

## SSH，Wi-Fi，ユーザの設定
まずは，cdコマンドで移動:

```shell-session
$ cd /Volumes/boot
```

### SSHの有効化
起動時にsshを有効にするため，書き込んだSDカードの最上位に`ssh`という名前の空ファイルを作成する:

```shell-session
$ touch ssh
```

### Wi-Fiの設定
書き込んだSDカードの最上位に，`wpa_supplicant.conf`という名前のファイルを作成する．
このファイルは，起動時に自動でRaspbian上の`/etc/wpa_supplicant/wpa_supplicant.conf`を上書きするようになっている．
上書き後，SDカードの最上位に作成したファイルは削除される．

Wi-Fiのパスフレーズは平文でも保存できるが，256bitのハッシュ化されたキーを保存した方が良い．
キーは[WPA key calculation: From passphrase to hex](http://jorisvr.nl/wpapsk.html)のページにアクセスし，Network SSIDとWPA passphraseを入力し、Calculateボタンをクリックすると得ることができる．

[<img width="820" alt="WPA key calculation" src="https://qiita-image-store.s3.amazonaws.com/0/59163/0c9a177a-e1ae-e50f-9346-2e69fd5c3b09.png">](http://jorisvr.nl/wpapsk.html)

`bac3cdf26d42c3a61fb858ef0295a0166e94f84dbabc1088bfa090cef3cb1dcb`のようなキーが得られる．
これを元にファイルを作成する: 

```shell-session
$ vim wpa_supplicant.conf
```

```conf:wpa_supplicant.conf
country=JP
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
network={
    ssid="abc"
    psk=bac3cdf26d42c3a61fb858ef0295a0166e94f84dbabc1088bfa090cef3cb1dcb
}
```

### ユーザの設定
気づけば，デフォルトの「pi」ユーザは削除されたのでユーザの設定を忘れずに行う．

```shell-session
$ vim userconf
```

```conf:userconf
username:encrypted-password
```

暗号化したパスワードは次のように入力して生成する:

```shell-session
$  echo 'raw-password' | openssl passwd -6 -stdin
```

シェルのヒストリーに暗号化前のパスワードを残したくないので先頭にスペースを入れて実行した（せめてもの抵抗）．
※ヒストリーへの保存条件は使用する環境の設定によって異なるので注意

### SDカードの取り外し
設定が終わったら，以下を実行したのち，SDカードを取り外す: 

```shell-session
$ cd
$ diskutil eject /dev/rdisk2
```

## Raspberry Piの起動
SDカードを取り外したら，Raspberry Piに挿入し，電源を接続する．

電源接続後，sshコマンドでRaspberry Piに接続する:

```shell-session
$ ssh username@raspberrypi.local
```

ユーザ名，パスワードは `userconf` 作成時に指定したものを使用する．

#### ※注意
過去に別の `raspberrypi.local` に接続したことがあると，以下のようなエラーが出る場合がある．

```shell-session
$ ssh pi@raspberrypi.local
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@       WARNING: POSSIBLE DNS SPOOFING DETECTED!          @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
The ECDSA host key for raspberrypi.local has changed,
and the key for the corresponding IP address fe80::f88c:658:xxxx:xxxx%en0
is unknown. This could either mean that
DNS SPOOFING is happening or the IP address for the host
and its host key have changed at the same time.
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the ECDSA key sent by the remote host is
SHA256:0E0bGTNgBRDx/HvSCguEACBoAG8OaF+YlsoPlMMRuMs.
Please contact your system administrator.
Add correct host key in /Users/user/.ssh/known_hosts to get rid of this message.
Offending ECDSA key in /Users/user/.ssh/known_hosts:xx
ECDSA host key for raspberrypi.local has changed and you have requested strict checking.
Host key verification failed.
```

これは，前に接続した `raspberrypi.local` と fingerprint が一致しておらず，中間者攻撃の可能性があるため接続がキャンセルされたことを表す．

この場合は下のコマンドで前回までの fingerprint を削除すると問題なく接続できる．

```shell-session
$ ssh-keygen -R raspberrypi.local
$ ssh username@raspberrypi.local
```

## Raspberry Piの設定
### 初期設定
まずは，初期設定を行う:

```bash
$ sudo raspi-config
```
1. 「8 Update」を選択し，ツール自体を最新にしておく．
2. 「1 System Options」の「S4 Hostname」を選択し，ホスト名を設定する．
3. 「5 Localisation Options」の「L1 Locale」を選択し，言語の設定をする．
    ここでは，あくまで私の設定を紹介する．
    まぁ，趣味の問題なのでみなさん思い思いに設定してください．
    1. 「en_GB.UTF-8 UTF-8」でスペースキーを押し，選択解除
    2. 「en_US.UTF-8 UTF-8」でスペースキーを押し，選択
    3. 「ja_JP.UTF-8 UTF-8」でスペースキーを押し，選択
    4. Tabキーを押し，「Ok」を選択
    5. 「C.UTF-8」を選択し，「Ok」を選択  
4. 「5 Localisation Options」の「L2 Timezone」を選択し，タイムゾーンの設定をする．
    1. 「Asia」，「Tokyo」を選択
5. 「5 Localisation Options」の「L4 WLAN Country」を選択し，使用する国を設定する．
    1. 「JP Japan」を選択
6. 「5 Localisation Options」の「I3 Change Keyboard Layout」を選択し，キーボードの設定をする．（必要であれば．今回はパス．）
7. 「Finish」を選択して初期設定は終了（再起動するか聞かれたら「Yes」を選択して再起動する）．

### アップデートの実施
とりあえず，さっさとアップデートしてしまう:

```shell-session
$ sudo apt update       # パッケージリストの更新
$ sudo apt full-upgrade # パッケージの更新
$ sudo rpi-update       # ファームウェアの更新（オプション）
$ sudo reboot           # 反映のための再起動
```

### SSHの設定
**鍵でログインする環境にしたい人のみ実行してください。なんのことかわからない方は次のファイヤウォールの設定まで飛ばすことをお勧めします。**

認証されたキーのみでログインできるように，`root`ではログインできないように変更する:

```shell-session
$ sudo apt install vim-nox
$ sudo vim /etc/ssh/sshd_config
```

```diff:/etc/ssh/sshd_config
- #PermitRootLogin prohibit-password
+ PermitRootLogin no
```
```diff:/etc/ssh/sshd_config
- #PubkeyAuthentication yes
+ PubkeyAuthentication yes
```
```diff:/etc/ssh/sshd_config
- #PasswordAuthentication yes
- #PermitEmptyPasswords no
+ PasswordAuthentication no
+ PermitEmptyPasswords no
```
```diff:/etc/ssh/sshd_config
- UsePAM yes
+ UsePAM no
```

そしたら，実際に公開鍵を書き込む

#### 公開鍵を書き込む
##### スマートに書き込む
```shell-session:手元のPCの環境から
$ ssh-copy-id -i ~/.ssh/id_ed25519 username@raspberrypi.local
```

##### 大人しくシンプルに書き込む
```shell-session
$ mkdir ~/.ssh
$ vim ~/.ssh/authorized_keys
```
```diff:~/.ssh/authorized_keys
+ ssh-ed25519 xxxxxxxxx xxx@xxx.local
```

パーミッションを整える:

```shell-session
$ chmod 0700 ~/.ssh
$ chmod 0600 ~/.ssh/authorized_keys
```

#### 公開鍵を登録したら…
反映のため，サービスの再起動:

```shell-session
$ sudo systemctl restart ssh
```

設定にミスがないか確認するため，新しいターミナルでログインテストする．
接続中のを切断すると，設定にミスがあった際に，ログインできず修正できなくなるので注意．

### ファイヤウォールの設定
設定しないのは楽でいいですが，やはりセキュリティー的には設定するべきですので，設定します．

iptablesがいちばん有名だとは思いますが，設定が~~めんどくさい~~複雑なので，今回はufw (Uncomplicated FireWall)を使用する．

インストール:

```shell-session
$ sudo apt install ufw
```

ファイヤウォールの状態を確認:

```shell-session
$ sudo ufw status
Status: inactive
```

インストールした直後は無効になっている．

ファイヤウォールの設定の基本は，
1. 外部からの接続は受け付けない
2. 必要なポートの通信だけ許す
です．
それに従い，今回はローカルのssh接続のみ許可するように設定します:

```bash
$ sudo ufw default deny
Default incoming policy changed to 'deny'
(be sure to update your rules accordingly)
$ sudo ufw allow proto tcp from 10.0.0.0/8 to any port 22 # 環境に合わせて設定してください．
Rules updated
$ sudo ufw enable
Command may disrupt existing ssh connections. Proceed with operation (y|n)? y
Firewall is active and enabled on system startup
$ sudo ufw status
Status: active

To                         Action      From
--                         ------      ----
22/tcp                     ALLOW       10.0.0.0/8
```

これで共通のセットアップは完了です．
あとは，私はzshでも入れてから，色々遊んでみます．


## 参考
- [Qiita: Raspberry Pi 3を買ってMacを使ってWiFi接続とSSHの接続するまで (@toshihirock)](https://qiita.com/toshihirock/items/8e7f0887b565defe7989)
- [Qiita: raspbian 2016-11-25 をインストールしてssh接続まで (@t114)](https://qiita.com/t114/items/26b3c82d52aa86809bde)
- [Qiita: Raspberry Piの無線LANをmicroSDで設定する (@mascii)](https://qiita.com/mascii/items/0d1a280ac58ed8f6f999)
- [Qiita: Raspberry Pi 初期設定 (@HeRo)](https://qiita.com/HeRo/items/c1c30d7267faeb304538)
- [Raspberry Pi Documentation: Installing operating system images on Mac OS](https://www.raspberrypi.org/documentation/installation/installing-images/mac.md)
- [An update to Raspberry Pi OS Bullseye - Raspberry Pi](https://www.raspberrypi.com/news/raspberry-pi-bullseye-update-april-2022/)
- [Make: Japan | Raspberry Piを攻撃から守るための手順](http://makezine.jp/blog/2017/09/secure-your-raspberry-pi-against-attackers.html)
- [Make. | ファイヤーウォールの設定](http://make.bcde.jp/raspberry-pi/%E3%83%95%E3%82%A1%E3%82%A4%E3%83%A4%E3%83%BC%E3%82%A6%E3%82%A9%E3%83%BC%E3%83%AB%E3%81%AE%E8%A8%AD%E5%AE%9A/)