chkbuild を動かすのに chkbuild 自体を動かすのと git pull は別権限で動かしたかったので、 systemd.exec(5)User= では指定できなさそうだったので、 runuser を使いました。

動作確認環境

  • Debian GNU/Linux 10 (buster)
  • systemd 241-7~deb10u4

su での失敗

service unit ファイルで ExecStartPre=/bin/su -l uucp -c pwd と指定すると、以下のような感じでエラーになりました。 (uucp ユーザーは適当に使っていないシステムユーザーを選んだだけで深い意味はありません。)

su[327]: (to uucp) root on none
su[327]: pam_unix(su-l:session): session opened for user uucp by (uid=0)
su[327]: pam_systemd(su-l:session): Runtime directory '/run/user/10' is not owned by UID 10, as it should.
su[327]: pam_systemd(su-l:session): Not setting $XDG_RUNTIME_DIR, as the directory is not in order.

エラーメッセージから推測すると session optional pam_systemd.so で失敗しているようでした。 /etc/pam.d/common-session で設定されていて、 /etc/pam.d/su-l/etc/pam.d/su からは @include で参照していました。

util-linux: /sbin/runuser

runuser コマンドは util-linux パッケージに入っていて、 Linux 依存のようでしたが、 systemd を使っている時点で Linux 依存なので気にせず使うことにしました。

パスワード認証などに対応していなくて、 root 権限から他の権限でコマンドを実行することに特化したコマンドのようです。 さらに細かく制御できる setpriv というコマンドもあるようですが、今回はそこまで細かい制御は必要なかったので、使いませんでした。

/etc/pam.d/runuser には pam_systemd.so はなく、 /etc/pam.d/runuser-l-session optional pam_systemd.so となっていました。

頭の -pam.d(5) によると以下のような意味のようです。

If the type value from the list above is prepended with a - character the PAM library will not log to the system log if it is not possible to load the module because it is missing in the system. This can be useful especially for modules which are not always installed on the system and are not required for correct authentication and authorization of the login session.

ということで -l は使わずに ExecStartPre=/sbin/runuser -u chkbuild-owner -- git pull origin master という設定にしました。

chkbuild.service

最終的にテスト実行中の chkbuild.service 全体は以下のようになりました。

WorkingDirectoryExecStartPre にも影響していたので、 sh -c "cd ... && git ... にしていた cd は止めて、 git を直接使うようにしました。

[Unit]
Description=Run chkbuild

[Service]
Type=oneshot
PermissionsStartOnly=true
ExecStartPre=/sbin/runuser -u chkbuild-owner -- git pull origin master
ExecStart=/home/chkbuild/chkbuild/start-build
User=chkbuild
Group=chkbuild
WorkingDirectory=/home/chkbuild/chkbuild
PrivateTmp=true

本番環境用では start-build の代わりに start-rubyci にして、 EnvironmentFile=-/etc/systemd/system/chkbuild.env も指定して別ファイルも組み合わせて、 環境変数 RUBYCI_NICKNAME, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY を指定しています。

chkbuild.timer

参考のため、 timer ユニットの設定ものせておくと、 今のところ実行間隔は、起動直後は 10 分待って、前回の終了後 1 時間あけて次を実行にしています。

[Unit]
Description=Run chkbuild

[Timer]
OnBootSec=10min
OnUnitInactiveSec=1h
Persistent=true

[Install]
WantedBy=timers.target

感想

他の環境では動いていた ExecStartPre=/bin/su - chkbuild-owner -c "cd /home/chkbuild/chkbuild && git pull origin master" が動かなかったのをきっかけに、 runuser コマンドや setpriv コマンドを知ることができました。

今までは runit パッケージの chpst を使っていることもあったのですが、 追加でインストールせずに使える可能性が高い runusersetpriv で足りるときは、 そちらを使うようにしたいと思いました。

Disqus Comments

Kazuhiro NISHIYAMA

Ruby のコミッターとかやってます。 フルスタックエンジニア(って何?)かもしれません。 About znzに主なアカウントをまとめました。

znz znz


Published