Raspberry Pi を USB ストレージから起動する

# はじめに

SD カード上のブートローダーによる USB ストレージ起動を行なう環境を新規構築します。

本記事では、以下の略称を使用します。

* `Raspberry Pi`のことを`Pi`と表記します。
* `USB ストレージ`のことを`HDD`と表記します。SSD を利用しても問題ないと思います。
* `sudo`を介するコマンド実行部分を`#`プロンプトで表記します。

ちなみにSDカードを必要としない HDD 単体起動も Pi のモデルによっては可能ではあります。



# インストール


### イメージをダウンロードする

`NOOBS`よりは`Raspbian`そのもののほうが良いです。`NOOBS`は色々パーティションが作成されるので、ちょっと面倒そうでした。

ここでは[公式](https://www.raspberrypi.org/downloads/raspbian/)から`Raspbian Buster Lite`をダウンロードしました。

```
Raspbian Buster Lite
Minimal image based on Debian Buster
Version:September 2019
Release date:2019-09-26
Kernel version:4.19
Size:426 MB
```

公式はかなり遅いので、ミラーサイトからダウンロートしたほうがよいかもしれません。


### ブートローダー SD カードの準備

ダウンロードした img ファイルを SD カードに書き込み、`boot`パーティション直下に`ssh`という空のファイルを作成します。


### HDD の準備

ダウンロードした img ファイルを HDD に書き込み、`boot`パーティション直下に`ssh`という空のファイルを作成します。



### Pi の起動

SD カードのみ差し込んだ状態で Pi を起動します。しばらく待って ssh 接続を試みます。Pi が起動したかどうかは、なんとなく緑色の LED の点滅具合で判断します。何度か不定期に点滅し、その後に点滅しなくなったら起動できたと考えてよさそうです。そもそも緑色の LED が点灯しないならば起動してないと思います。

```:IPアドレスが192.168.1.100の例(Windows)
> ssh pi@192.168.1.100
pi@192.168.1.100's password:
```

初期ユーザー`pi`のパスワードは`raspberry`です。ログインが確認できたら HDD を USB 接続します。


### パーディションサイズの拡大

現状、`/dev/sda2`のパーティションサイズが、HDD に書き込んだイメージサイズの大きさになっています。これを HDD の最大サイズに拡張します。

```:console（一部抜粋）
# fdisk /dev/sda
Device     Boot  Start     End Sectors  Size Id Type
/dev/sda1         8192  532480  524289  256M  c W95 FAT32 (LBA)
/dev/sda2       540672 4292607 3751936  1.8G 83 Linux
```

まず、`/dev/sda2`パーテションを削除し、最大サイズで作成しなおします。この時、`Start`セクタは同じ値を設定します。`End`セクタを HDD の最終セクタに指定します。

仕組みとしては、パーティションを削除しただけでは HDD の内容までは失われないので、すかさず同じ開始地点から、サイズを拡大した終了地点を指定し、最後にディスクに書き込むといった操作になります。

```:fdisk
Command (m for help): d
Partition number (1,2, default 2): 2

Partition 2 has been deleted.

Command (m for help): n
Partition type
   p   primary (1 primary, 0 extended, 3 free)
   e   extended (container for logical partitions)
Select (default p):

Using default response p.
Partition number (2-4, default 2):
First sector (2048-3907029167, default 2048): 540672
Last sector, +/-sectors or +/-size{K,M,G,T,P} (540672-3907029167, default 3907029167):

Created a new partition 2 of type 'Linux' and of size 1.8 TiB.
Partition #2 contains a ext4 signature.

Do you want to remove the signature? [Y]es/[N]o: N

Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.

# resize2fs /dev/sda2
resize2fs 1.44.5 (15-Dec-2018)
Please run 'e2fsck -f /dev/sda2' first.

# e2fsck -f /dev/sda2
e2fsck 1.44.5 (15-Dec-2018)
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
rootfs: 42263/117360 files (0.2% non-contiguous), 313274/468992 blocks
```

つづいて、ファイルシステムサイズをパーティションサイズに合わせて拡張します。マウント中のファイルシステムに対しての操作にはなるので、問題がありそう？ なさそう？ という感じのメッセージが表示されますが、正常に拡張を行なうことができます。

```:console
# resize2fs /dev/sda2
resize2fs 1.44.5 (15-Dec-2018)
Filesystem at /dev/sda2 is mounted on /; on-line resizing required
old_desc_blocks = 1, new_desc_blocks = 117
The filesystem on /dev/sda2 is now 488311062 (4k) blocks long.
```

### PARTUUID の確認

```:console
# blkid
/dev/mmcblk0p1: LABEL_FATBOOT="boot" LABEL="boot" UUID="F661-303B" TYPE="vfat" PARTUUID="d84d06b8-01"
/dev/mmcblk0p2: LABEL="rootfs" UUID="8d008fde-f12a-47f7-8519-197ea707d3d4" TYPE="ext4" PARTUUID="d84d06b8-02"
/dev/mmcblk0: PTUUID="d84d06b8" PTTYPE="dos"
/dev/sda1: LABEL_FATBOOT="boot" LABEL="boot" UUID="F661-303B" TYPE="vfat" PARTUUID="17869b7d-01"
/dev/sda2: LABEL="rootfs" UUID="8d008fde-f12a-47f7-8519-197ea707d3d4" TYPE="ext4" PARTUUID="17869b7d-02"
```

この結果はどこかにメモしておきます。重要なのは`/dev/`ではじまるデバイス名と`PARTUUID`の値です。そして、どのパーティションなのかの判断材料として`LABEL_FATBOOT`や`LABEL`の値も意識しておきます。

デバイス名が`/dev/mmcblk0p`で始まるのが SD カードで、`/dev/sda`で始まるのが HDD です。


### `/boot/cmdline.txt`の編集

SD カード上の`cmdline.txt`を編集しますが、先にバックアップを作成しておきます。

```:console
# cp /boot/cmdline.txt /boot/cmdline.sd.txt
```

もし、この後の作業で SD カードからの起動ができなくなってしまった場合、SD カードを PC に接続し、バックアップしたファイルを`/boot/cmdline.txt`に書き戻したうえで Pi に SD カードを刺し直したうえで起動しなおします。

テキストエディタで`/boot/cmdline.txt`を開きます。

```:console
# vi /boot/cmdline.txt
dwc_otg.lpm_enable=0 console=serial0,115200 console=tty1 root=PARTUUID=5a25cb3e-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait
```

重要なのは`root=PARTUUID=`の部分です。この値が、さきほど`blkid`した際にメモした SD カード上の`LABEL="rootfs`の`PARTUUID`値を示しています。これを`/dev/sda`で始まる`LABEL="rootfs`の`PARTUUID`値に置き換えます。

これまでの手順通りならば、SD カードは`/dev/mmcblk0p2`、HDD は`/dev/sda2`であるはずです。もし違うなら読み替えてください。

```:/boot/cmdline.txt
dwc_otg.lpm_enable=0 console=serial0,115200 console=tty1 root=PARTUUID=17869b7d-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait
```

`reboot`し、再起動後に`/root`以下にどちらのファイルが存在するかで切り替えを判断したいと思います。

```:console
# reboot
```

しばらく待ち、`ssh`接続してみます。

```:IPアドレスが192.168.1.100の例(Windows)
> ssh pi@192.168.1.100
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    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.
（省略）
ECDSA host key for 192.168.1.100 has changed and you have requested strict checking.
Host key verification failed.
```

怒られました。これは、ホスト鍵が変化したために起こる問題です。この時点で HDD 起動に切り替わっていることが確認できたようなものです。この状態をリセットして、再度`ssh`接続を試みます。

```:IPアドレスが192.168.1.100の例(Windows)
> ssh-keygen -R 192.168.1.100
> ssh pi@192.168.1.100
pi@192.168.1.100's password:
```

はい、結果を見なくても確実ですね。パスワード`raspberry`を入力して HDD 側環境へログインします。

ここまでの作業で、SD カードからブートし、HDD 上のパーティションから OS がブートしたことが確認できました。



# fstab の修正

`/etc/fstab` を確認します。注目すべきは`/boot`および`/`パーティションの`PARTUUID`の値です。ここでは、`boot`パーティションは SD カード、`/`パーテションは HDD の UUID 値に修正します。

これが正しくおこなわれていないと、これ以降の作業で`apt dist-upgrade`などを行なった後、`reboot`した際に不整合が発生します。



# OS の更新

```:console
# apt dist-upgrade
```



# パッケージ更新

まずは基本中の基本。パッケージを最新版に更新します。

```:console
# apt update
# apt upgrade
```



# Wi-Fi と bluetooth を無効にする

今回用意した`Pi`の運用目的はサーバーなので、無線通信を無効化します。

ぱっと見`bluetooth`はデーモンが起動しているように見えたので、`systemctl`から停止してみましたが、再起動すると復活していました。

調べてみると、`/boot/config.txt`というファイルがあるらしく、ここにサービスの停止を明示しないといけないようです。

`systemctl`の設定を無視する上位の設定ルールが存在するのはどうなのかな？ と思いはするものの、まぁしょうがないです。

```:/boot/config.txt
# Disable wifi and bluetooth.
dtoverlay=pi3-disable-wifi  
dtoverlay=pi3-disable-bt
```

その他のオプションに関しては`/boot/overlays/README`に詳しく記載されています。

リブートします。

```:console
# reboot
```


# pi ユーザーを置き換える

ユーザー名やパスワードが固定ということは、そこを突く攻撃に対応できないことになるので、ユーザー名とパスワードを変更したいと思います。

初期状態では`pi`ユーザーしか存在しないため、`tmp`ユーザーを作成し`sudo`グループに所属させます。最後にパスワードを設定します。

```:piユーザーconsole
# useradd -M tmp
# gpasswd -a tmp sudo
# passwd tmp
```

ログアウトし、`tmp`ユーザーでログインします。

`pi`ユーザーを元とする、変更先のユーザーを作成します。ここではユーザー名を`newusername`としていますが、お好きな名前に読み替えてください。

```:tmpユーザーconsole
# usermod -l newusername pi
# usermod -d /home/newusername -m newusername
# groupmod -n newusername pi
```

newusername でログイン後、`tmp`ユーザーを削除し自身のパスワードを変更します。

```:newusernameユーザーconsole
# userdel tmp
# passwd
```



# ssh 接続用キーペアの作成と登録

非公開鍵と公開鍵のペアを作成し、サーバー側に公開鍵を登録しておきます。

キーペアの作成は通常クライアント側で行ないます。OpenSSH がインストールされた Windows 環境などでも作成可能です。

以下、OpenSSH がインストールされている場合の手順です。

```:Windows
C:\Users\localuser> ssh-keygen

Generating public/private rsa key pair.
Enter file in which to save the key (C:\Users\localuser/.ssh/id_rsa): ←基本的にはそのまま改行
Enter passphrase (empty for no passphrase): ←パスフレーズの入力
Enter same passphrase again: ←パスフレーズの再入力
```

ここまでの作業で、ホームフォルダの`.ssh`フォルダ内に`id_rsa.pub`と`id_rsa`というファイルが作成されているはずです。

作成した公開鍵をサーバに登録します。登録するのは`id_rsa.pub`の内容です。

```:console
$ mkdir .ssh ←もしなければ作成
$ vi .ssh/authorized_keys
（ssh-rsa で始まる長い文字列を張り付けて保存） 
```

「ローカル側にある`id_rsa.pub`の内容を、サーバの`.ssh/authorized_keys`に追加登録する」という作業なので、追加登録が終わった後は、ローカル側にある`id_rsa.pub`を消しても問題はありません。

プライベートキーである`id_rsa`ファイルは、わかりやすい名前に変更しておきます。

この時点で公開鍵をつかったログインができるか確認しておきましょう。さもないと、これ以降の作業でパスワードでのログインを禁止するため、リモートからログインできない環境が出来上がってしまう可能性があります。

問題なさそうならパーミッションも変更しておきます。

```:console
$ chmod 600 ~/.ssh/authorized_keys
$ chmod 700 ~/.ssh
```



# 公開鍵認証でのログインに限定し root でのログインを禁止する

パスワード認証を禁止し、公開鍵を利用したログインに限定します。

```:console
[root@centos ~]# vi /etc/ssh/sshd_config
#PermitRootLogin yes
↓
PermitRootLogin no ←コメントをはずし no に
#PasswordAuthentication yes
↓
PasswordAuthentication no ←コメントをはずし no に

[root@centos ~]# systemctl restart sshd.service ← sshd 再起動
```

上記設定後、これまで作成したアカウントでのパスワードログインができなくなっていることを確認しておいてください。同時に root での公開鍵ログインができないこと、作業ユーザーで公開鍵でのログインができることも確認しておきましょう。



# タイムゾーンの変更

`raspi-config`コマンドにて変更します。テキストによる簡易 GUI 表示となるので、ターミナルソフトによっては画面がチラつくことがあります。Windows の場合、`コマンドプロンプト`では問題ありませんでした。

* `4 Localisation Options`を選択する
* `I2 Change Timezone`を選択する
* `Asia`を選択する
* `Tokyo`を選択する
* `Finish`を選択する