あっきぃ日誌

鉄道ブログのような技術系ブログのようななにか

piユーザーが削除されたRaspberry Pi OSと公式ヘッドレスセットアップのやり方研究

一昨日くらいにRaspberry Pi OSのアップデートリリースがありました。

www.raspberrypi.com

が、今回もなかなかパワフルな変更が入っており、piユーザーおよびデフォルトパスワードが廃止されました。これはイギリスなどで決まった「IoT製品にデフォルトパスワードを設定するな」という法律に対する取り組みらしく、世界中のデフォルトパスワードで動作する監視カメラが云々みたいなネタが以前より存在していたことを考えると、必要なアップデートと言えるものです。

デフォルトパスワードの廃止だけではなくpiユーザーごと廃止されてしまったため、新しいリリースでは、初回起動時にユーザー名・パスワードの設定が必要になります。デスクトップ版の場合は、今まで起動していたウィザードが専用の背景上で起動して、セットアップを促すようになっています。Lite版のほうも、CUIで設定が出るようになっています。なので、手動でセットアップする分にはちょっと手間が増えただけですみますし、初心者からすれば「デフォルトユーザーとパスワードは?」とならなくなる可能性もあるので、とくに問題はなさそうです。

ヘッドレスでザクザクセットアップしたい勢はどうすればいいのかについては、ブログでも言及があるように、Raspberry Pi Imagerを使ってカスタマイズセットアップをするか、ユーザー名の設定については/boot/userconf(.txt)にユーザー情報を書けばOKのようです。

私個人的には、最近はRaspberry Pi Imagerを使う方向に切り替わってきたので、カスタマイズセットアップでいいかなと思っています。

我流RPi OS初期セットアップのアップデート

以前は、イメージを焼いたあとに/boot/sshを配置し、初回起動後に以下のスクリプト(をまとめたfunction化したもの)をリモートから叩いて、ある程度の初期設定をしていました。このあとさらにSSHでログインしてパスワードを設定したり、Ansible PlaybookでvimとNetworkManagerの導入をしたりしています。こうしてみるとまあまあ手間ですし、このスクリプトは何らかの理由でSSHできなかったときは盛大にコケます。

function first_ssh_to_pi(){
  export SSH_TO_PI="ssh pi@raspberrypi.local"
  # pubkey
  expect -c "
    spawn ssh-copy-id -i $HOME/.ssh/id_ed25519 pi@raspberrypi.local
    expect \"password:\"
    send \"raspberry\n\"
    expect \"$\"
    exit 0
  "
  # Locale
  ${=SSH_TO_PI} "sudo raspi-config nonint do_change_locale ja_JP.UTF-8 UTF-8"
  # Timezone
  ${=SSH_TO_PI} 'sudo timedatectl set-timezone Japan'
  # Wi-Fi
  ${=SSH_TO_PI} "sudo raspi-config nonint do_wifi_country JP"

  ${=SSH_TO_PI}
}

Raspberry Pi Imagerなら書き込むときに一通りカスタムでできるので、どうやっているのか/bootを覗いてみました。

/boot/cmdline.txtを見ると、以下の一文が追記されています。/boot/firstrun.shを実行するために、systemdのカーネルコマンドラインを活用しているようです。こんなのあるのね。べんり。

systemd.run=/boot/firstrun.sh systemd.run_success_action=reboot systemd.unit=kernel-command-line.target

/boot/firstrun.shはRaspberry Pi Imagerによって生成されたファイルで、カスタム内容が一通り記述されています。ユーザー名やパスワードやSSH鍵など個人的な内容がたくさん含まれるので貼れないですが、スクリプトの最後は自壊するようになっています。儚い。

rm -f /boot/firstrun.sh
sed -i 's| systemd.run.*||g' /boot/cmdline.txt
exit 0

……以上を踏まえて、Imagerを使わないでイメージを書き込んだときは、今まで使ってきたfirst_ssh_to_piを使わず、Imagerが吐いたfirstrun.shを拝借して、そいつをコピー&cmdlineの追記をするように変えれば良さそうです。こんな感じのfunctionを書いてみました。

function pi-firstrun(){
  # Macじゃない人は/Volumes/bootの部分は適当に書き換えるか$1とかで引数取ればいいと思う
  CMDLINE=/Volumes/boot/cmdline.txt
  TEST=`grep firstrun $CMDLINE`
  if [ "$TEST" = "" ] ; then
    echo -n " systemd.run=/boot/firstrun.sh systemd.run_success_action=reboot systemd.unit=kernel-command-line.target" >> $CMDLINE
    # 適当なところにfirstrun.shを配置しておくかんじ
    cp $HOME/Scripts/script-for-pi-firstrun/firstrun.sh /Volumes/boot/firstrun.sh
  fi
}

これで、イメージを書き込んだあとの作業はpi-firstrunの実行と、起動後のAnsible Playbookの実行だけになりました。手作業がかなり減っていいですね。

firstrun.sh実行時点でインターネットに繋がっているなら、ネットワークの接続を確認してaptを実行できるようにすれば、Ansible Playbookの実行すら不要にできる可能性はありそうです。未検証なのでできたらまたブログでもしましょ。

所感

piユーザー削除はなかなかドラスティックな変更ですが、一方で、それ以外で使い慣れたユーザー名を使えるようになる(以前からも手間をかければ使えましたが、手間なので誰もやってなかったと思う)ので、sshするときに「pi@」の打鍵が減ったのはアリかなと思っています。

セットアップ済みの環境でも、ユーザー名変更を実行できるコマンドが用意されているようなので、変更したい方は公式ブログの手順を参考に実行すると良いでしょう。

追記: ちなみに

ユーザー設定画面でpi/raspberryを設定することはできますが、設定時に警告されます。俺は大丈夫という正常性バイアスがバリバリの方のみ先に進むことができます。