SONiC-VSのイメージファイルに公開鍵を書き込む

# はじめに

仮想マシン用SONiCであるSONiC-VSは、`QCOW2`フォーマットのディスクイメージとして提供されます。オフィシャルイメージであれば、ユーザ`admin`、パスワード`YourPaSsWoRd`でsshログインできるようになっていますが、どうせなら公開鍵を登録して、公開鍵認証でログインしたいと思い、試してみました。

# 方法1 ログインしてから鍵を登録する

`$HOME/.ssh/authorized_keys` に公開鍵を登録すれば、秘密鍵を持ってる人が公開鍵認証でsshログインできるようになります。Linux/BSD/...ではごくふつうのセットアップですが、いちいち人間が一度手でやらなければいけないのは煩わしく感じます。

# 方法2 仮想イメージ用ツールを利用する

起動させずに登録する方法です。

## ツールのインストール

`libguestfs-tools`をインストールすると、仮想マシンイメージの中をいろいろ出来るツール類が使えるようになります。

```sh
# Debian, Ubuntu
sudo apt install libguestfs-tools
# RHEL, Fedora, CentOS
sudo yum install libguestfs-tools
```

## イメージファイルの中身を確認する

ひとまず、イメージの中身を見ることができるかやってみます。

```shell-session
$ sudo virt-ls -a ./sonic-vs.img /
virt-ls: no operating system was found on this disk

If using guestfish ‘-i’ option, remove this option and instead
use the commands ‘run’ followed by ‘list-filesystems’.
You can then mount filesystems you want by hand using the
‘mount’ or ‘mount-ro’ command.

If using guestmount ‘-i’, remove this option and choose the
filesystem(s) you want to see by manually adding ‘-m’ option(s).
Use ‘virt-filesystems’ to see what filesystems are available.

If using other virt tools, this disk image won’t work
with these tools.  Use the guestfish equivalent commands
(see the virt tool manual page).
$ 
```

OSが見つからない?

んー。`/etc/fstab`でも見ようとしているみたいです。SONiCでは実機でも仮想マシンでもそこらのファイルはqeuashfsの中で圧縮されてるので直接参照はできないんですよね。じゃあ直接パーティション指定できたらいいのかな、と思い調べてみます。

まずはデバイスの確認。

```shell-session
$ sudo virt-filesystems -a ./sonic-vs.img
/dev/sda2
/dev/sda3
$ 
```

`virt-ls`のヘルプを見ていると `-m|--mount dev[:mnt[:opts[:fstype]]]` なんてのがあります。これを使ってみましょう。

```shell-session
$ sudo virt-ls -a ./sonic-vs.img -m /dev/sda2 / 
grub
lost+found
onie
$ sudo virt-ls -a ./sonic-vs.img -m /dev/sda3 / 
grub
image-master.192124-3740f1efb
lost+found
machine.conf
$ 
```

`sda2`がGRUB/ONIE用、`sda3`がSONiC用でした。(両方に`grub`があるのは、GRUBの多段ブートの関係です)

`/dev/sda3`の中をもう少し見てみましょう。`image`から始まるディレクトリの中を覗いてみます。

```shell-session
$ sudo virt-ls -a ./sonic-vs.img -m /dev/sda3 /image-master.192124-3740f1efb
boot
docker
fs.squashfs
onie-support-kvm_x86_64.tar.bz2
platform
$ 
```

## 公開鍵をコピーする

最初の方で、SONiCの各種ファイルはsquashfsに入ってて圧縮されていると書きました。が、公開鍵をその中に仕込む必要はありません。SONiCはoverlayfsを使い、squashfsの上にかぶせるように読み書き可能領域を`mount`する構造になっています。

先ほど確認した`image`から始まるディレクトリに`rw/DIREFTORY/FILE`を置けば、squashfsの上にかぶさる形でファイルが扱えるようになります。

最初は`virt-copy-in`が使えるかと思って試すもうまく逝かず、調べてみると`virt-copy-in`はシェルスクリプトでした。`guestfish -i`を固定で呼び出しているので、冒頭の`virt-ls`のように`-m`指定しても無視されるようです。そこで、`guestfish`を直接動かしてみることにします。

```shell-session
$ sudo guestfish -a ./sonic-vs.img -m /dev/sda3 copy-in $HOME/.ssh/id_rsa.pub /image-master.192124-3740f1efb/rw/home/admin/.ssh/
libguestfs: error: target ‘/image-master.192124-3740f1efb/rw/home/admin/.ssh/’ is not a directory
$ 
```

あー。やっぱり`mkdir`しないとだめか。`mkdir-p`サブコマンドがあるのでそれを使います。あといちいち`image`から始まるディレクトリを手打ちしてるとしんどいので、引っ張ってきて使うことにします。

```shell-session
$ IMAGEDIR=$(sudo virt-ls -a ./sonic-vs.img -m /dev/sda3 / | grep image)
$ sudo guestfish -a ./sonic-vs.img -m /dev/sda3 mkdir-p /$IMAGEDIR/rw/home/admin/.ssh
$ sudo guestfish -a ./sonic-vs.img -m /dev/sda3 copy-in $HOME/.ssh/id_rsa.pub /$IMAGEDIR/rw/home/admin/.ssh/
$ 
```

無事書き込むことができました。

今回は試しに自分の公開鍵(`$HOME/.ssh/id_rsa.pub`)をコピーしましたが、`authorized_keys`をそのまま写す、メンテナンス担当の公開鍵リストを用意してそれをコピーするなど、状況に合わせてやっていただければと思います。

# 方法2の応用

今回は公開鍵を書き込みましたが、他のものでも普通に書き込めます。たとえば`/etc/resolv.conf`。
`/etc/ssh/sshd_config`を上書きすれば、パスワード認証を無効化することもできます。

# おわりに

手元で`ssh-agent`を動かすと、パスワードレスでログインできたりして便利です。Ansibleで制御するのにもやりやすくなるんじゃないかと思います。別のファイルを置くこともできるので、イメージの初期状態を比較的自由にコントロールできると思います。ご活用いただければ幸いです。