Raspberry PiのSDイメージにあらかじめ設定・ファイルを追加する

# 目的

Raspberry Piの標準的なディストリビューションであるRaspbian SDカードイメージは、そのままコピーするとSSHが有効にならなかったり、ディスプレイとキーボードを接続しないサーバー状態のRaspberry Piには少し手間が発生します。

SDに書き込む前のイメージを書き換えて、SSHを有効にしたり、ansibleを利用するため、あらかじめ .ssh/authorized_keys ファイルを配置するといった作業は手間ではないので手順だけ載せておきます。

最近は、Raspberry Pi 3/4 が普及して、64bit OSなUbuntuを利用するようになったので、記事を一部追記して、RaspbianとUbuntuについての記事としました。

## 環境

* SDカード (8GB以上、SLC/MLCや産業用グレードなど信頼性の高いものが望ましい)
* SDカードをddコマンドで書き込むLinuxマシン
* OSイメージ
  * 2018-04-18-raspbian-stretch.img 
  * ubuntu-20.04-preinstalled-server-arm64+raspi.img.xz

SDイメージを編集するため使用したのは、Xubuntu 18.04 LTS, Fujitsu TX100 S3P Xeon E3-1230v2 32GB なマシンでした。

# OSイメージを編集する基本的な手順

ここでは、あらかじめ *2018-04-18-raspbian-stretch.img* をダウンロードしたディレクトリに移動している前提で手順をまとめています。

```bash
$ sudo kpartx -a 2018-04-18-raspbian-stretch.img

$ ls -l /dev/mapper/
## 成功していれば、/dev/mapper/loop0p1 /dev/mapper/loop0p2 のように/bootと/の両パーティションを示すloopデバイスが表示される

## マウントポイントを作成する。他に適当なディレクトリがあれば以下、読み替えること
$ sudo mkdir /mnt/pi

## SSHをデフォルトで有効にするため、/boot/sshファイルを配置する
## 資料: https://www.raspberrypi.org/documentation/remote-access/ssh/
$ sudo mount /dev/mapper/loop0p1 /mnt/pi
$ sudo touch /mnt/pi/ssh
$ sudo umount /mnt/pi

## SSHで認証なしにログインするためにauthorized_keysを配置する
$ sudo mount /dev/mapper/loop0p2 /mnt/pi
$ sudo mkdir -p /mnt/pi/home/pi/.ssh
$ sudo cp ~/.ssh/authorized_keys /mnt/pi/home/pi/.ssh/

## SSHでPassword認証でのログインを無効にする
$ sudo sed -i '/^#PasswordAuthentication/s/^.*$/PasswordAuthentication no/' /mnt/pi/etc/ssh/sshd_config
## 補足: sed -i でsshd_configファイルを上書きしている

$ sudo umount /mnt/pi

## 最後にloopデバイスを開放する
$ sudo kpartx -d 2018-04-18-raspbian-stretch.img
## loop deleted: /dev/loopN (Nは数字) のような表示を確認する
## 直接デバイスを引数に与えることも可能だが、ディスクイメージファイルを指定した方が安全
## $ sudo losetup -l でloopデバイスの状況が確認できる
```

## SDカードへの書き込み前に確認すること

作成したイメージをSDカードに書き込む時には、SDカードのデバイス名を間違えないようにSDカードを差し込んでから、dmesgコマンドの最下行でデバイス名と容量を確認する。

```bash
$ dmesg | tail
[1300222.385680] sd 14:0:0:0: [sdf] 15759360 512-byte logical blocks: (8.07 GB/7.51 GiB)
```

ここから、8GBのSDカードを認識し、デバイス名として*sdf*が割り当てられた(/dev/sdf*) ことを確認する。

次にddコマンドで修正したSDカードイメージを書き込む

```bash
$ sudo dd if=2018-04-18-raspbian-stretch.img of=/dev/sdf bs=64M
```

*.imgファイルの名称はオリジナルから内容が分かるものに変更しておくこと。

# Ubuntu 20.04 64bit for Raspberry Pi4イメージの編集

前述の手順との差分で記述していきます。/bootと/(root)の2つのパーティションを含んでいる点はRaspbianと同じです。

## /dev/mapper/loopNp1 (/boot) のマウントと変更

Raspbianとは違い、sshサーバーを起動するために、sshファイルを配置する必要はありません。
/mnt/piにマウントした後、/mnt/pi/READMEファイルを確認すると分かりますが、ファイルの配置などは、/mnt/pi/user-dataファイルに記述することになっています。

サーバーとして利用するため、ubuntuユーザーのパスワードは複雑なものに変更した上で、sshログインを不可とし、authorized_keysファイルを配置するようにしています。

```yaml:user-data

# On first boot, set the (default) ubuntu user's password to "ubuntu" and
# expire user passwords
chpasswd:
  expire: false
  list:
  - ubuntu:f2b0a62d2502c08e

# Enable password authentication with the SSH daemon
ssh_pwauth: false

## Write arbitrary files to the file-system (including binaries!)
write_files:
- path: /home/ubuntu/.ssh/authorized_keys
  content: |
     ssh-ed25519 ....
  permissions: '0640'
  owner: ubuntu:ubuntu

## Run arbitrary commands at rc.local like time
runcmd:
- [ chown, ubuntu:ubuntu, /home/ubuntu ]
- [ chown, ubuntu:ubuntu, /home/ubuntu/.ssh ]
```

ここで書き込んだauthorized_keysファイル自体は問題なく作成されますが、途中に含めたディレクトリのパーミッションが所有者:rootで作成されてしまうためubuntuユーザーが読み込めず期待どおりに働いてくれません。

そのため、最後にruncmd:で権限の修正を行なっています。

副作用として、あらかじめディレクトリが存在することで、作成したubuntuユーザー用に/etc/skel/以下のファイルが展開されず、別の問題が発生する可能性があります。

作成したイメージはテストし、適宜変更を加えてください。

user-dataを利用する他に、/etc/skel/にファイル(/etc/skel/.ssh/authorized_keys)を作成することで、新規作成されるユーザー(この場合はubuntuユーザーを想定している)に、authorized_keysを与える方法もあります。

```bash
$ sudo mkdir -p /mnt/pi/etc/skel/.ssh
$ sudo cp ~/.ssh/authorized_keys /mnt/pi/etc/skel/.ssh/authorized_keys
```

自分以外のユーザーがRaspberry Piを利用しない場合には、こういった方法も考えられます。

以上