libvirtを更新したらlibvirtd.confに記載した通りに/run/libvirt/libvirt-sockの権限が設定されなくなった

# 概要

* `/etc/libvirt/libvirtd.conf`に設定を行なっているはずなのに、`/run/libvirt/libvirt-sock`のグループ・パーミッションが変わらない現象が発生した
* libvirtdでsystemd socket activationを使用している場合、`libvirtd.conf`に記載した一部オプション(`unix_sock_rw_perms`等)は無視される
* `libvirtd.conf`で無視されるオプションはUnitファイルに記載するように変更されているので、systemdのdrop-in機能などで設定を行う

# 環境

* libvirtdを動かしているホスト: Gentoo Linux
* libvirtのバージョン: =app-emulation/libvirt-6.8.0-r2:0/6.8.0::gentoo
* libvirtdへの接続方法: `qemu+ssh://username@hostname/system?socket=/var/run/libvirt/libvirt-sock`のようなURIを指定してvirt-managerから接続

# 現象

* どのタイミングからこの現象が発生したのかはっきりしたことはわからないが、この一ヶ月の間くらいでvirt-managerからlibvirtdに接続しようとした時にvirt-managerが落ちてしまうようになった。[^1]
* `virt-manager --debug`が出力したログを見ると権限周りの問題のようだったので、libvirtdホストの`/run/lib/libvirt-sock`の権限を確認したところ、以下の表の通り意図したものと異なっていた。

| | 期待値 | 実際の値 |
|:--|:--|:--|
| グループ | libvirt | root |
| パーミッション | 770 | 600 |

[^1]: virt-managerが落ちるのは恐らくmacでvirt-managerを使ってるせいで、Linux上であれば落ちることはなくエラーが表示されるだけだと思います。

## libvirt-sockの権限について補足

他のサイトでよく紹介されているので詳細は省きますが、一般ユーザからlibvirtdに接続できるようにするため、`/etc/libvirt/libvirtd.conf`にはこれまで以下の設定を行なっていました。

```:/etc/libvirt/libvirtd.conf
unix_sock_group = "libvirt"
unix_sock_rw_perms = "0770"
```

この設定により、`/run/lib/libvirt-sock`の権限が上記表の通りになり、一般ユーザからも接続できるようになるはずでしたが、この設定が反映されていないようでした。

# 原因

`libvirt-sock`の権限が正しく設定されない理由を調べたところ、libvirt 5.6.0以降[^2]systemd socket activationを使用する場合はlibvirtd.confに書いた設定は無視されるという情報が見つかりました。

[^2]: これまで5.6.0以降も使ったことがあるはずなのに今まで遭遇しなかったのがよくわからない・・・

その記載があった[公式ページ](https://libvirt.org/daemons.html#monolithic-systemd-integration)から抜粋すると、systemd socket activationが有効な場合、以下の設定はsystemd側で行う必要があるみたいでした。

| libvirtd.confでの設定 | 対応するsystemdのUnitファイル | 対応するUnitファイルでのパラメータ名 |
|:--|:--|:--|
| listen_tcp | libvirtd-tcp.socket | |
| listen_tls | libvirtd-tls.socket | |
| tcp_port | libvirtd-tcp.socket | ListenStream |
| tls_port | libvirtd-tls.socket | ListenStream |
| listen_addr | libvirtd-tcp.socket<br>libvirt-tls.socket | ListenStream |
| unix_sock_group | libvirtd.socket<br>libvirtd-ro.socket | SocketGroup |
| unix_sock_ro_perms | libvirtd-ro.socket | SocketMode |
| unix_sock_rw_perms | libvirtd.socket | SocketMode |
| unix_sock_admin_perms | libvirtd-admin.socket | SocketMode |
| unix_sock_dir | libvirtd.socket<br>libvirtd-ro.socket<br>libvirtd-admin.socket | ListenStream |

# 解決方法

今回の場合、`unix_sock_group`, `unix_sock_rw_perms`の設定をsystemd側で行うようにすればわかったので、そのように設定します。

Systemdにはdrop-inという仕組みがあり、この仕組みで/usr/lib/systemd/system/以下に作られたUnitファイルの設定の一部を上書きすることができます。`systemctl edit libvirtd.socket`を実行すると設定内容を記述するためのテキストエディタが起動するので、そこに以下の内容を入力して上書き設定を行いました。[^3] [^4]

[^3]: systemctlコマンドを使わず`/etc/systemd/system/libvirtd.socket.d/(任意の名前).conf`を直接作成しても良いようです
[^4]: パーミッションが上に記載したlibvirtd.confでは770でこちらでは660になっているのは、特にそうしないといけないわけではないです (実行権限はなくてもいいかと思い削りました)

```
[Socket]
SocketGroup=libvirt
SocketMode=0660
```

この設定を行なった後、`systemctl restart libvirtd libvirtd.socket`でソケットファイルを作り直したら、期待していた通りの権限になり、virt-managerから接続できるようになりました。

# 参考ページ

* [[SOLVED] libvirtd - incorrect permission on socket files / Newbie Corner / Arch Linux Forums](https://bbs.archlinux.org/viewtopic.php?id=256258)
* [libvirt: Libvirt Daemons](https://libvirt.org/daemons.html)
* [systemd - ArchWiki](https://wiki.archlinux.org/index.php/Systemd#Drop-in_files)