rootで動作するシェルスクリプトで一般ユーザーとして実行する
Live With Linux::technique
- TOP
- Articles
- Live With Linux
- rootで動作するシェルスクリプトで一般ユーザーとして実行する
序
この記事はRedHatのブログであるsystemd serviceから呼ぶシェルではsudoではなくsetprivを使うを受けてのものである。
当該記事に間違いはないが、言葉足らずであまり良い説明ではないと思ったためだ。
この記事の話題はプロセスの権限降格にあり、タイトルに反してシェルスクリプトに限らない。
そもそもsudo
sudoを他のユーザー権限でコマンドを実行するものと考えるのは仕方ないことではあるし、実際本人も “execute a command as another user” と言っているのだが、困ったことに既に言葉足らずである。
sudoは認証を経てプログラムを実行する。 単純に権限だけを変更するわけではない。認証が行われること、ログイン相当の処理を行うことなども含まれており、単純に権限のために使うには支障がある。
プロセスの権限
そもそもプロセスの情報はプロセスの構造体に入っている。 ここにUID, EUID, GID, EGIDが含まれている。 ユーザーは複数のグループに所属するが、プロセスはひとつのGIDしか持たない。
このあたりはLinuxなら/proc/$pid/status
を読むと分かりやすい。
そして、この情報は書き換え可能である。
だが、もちろん自由に書き換えられるわけではない。 もしそんなことができてしまえば、権限管理なんて成立しないからだ。
GIDを書き換えられるのは、このプロセスの所有者(UID)が所属しているグループに限られる。 EGIDも同様にEUIDに依存する。
UIDおよびEUIDを書き換えられるのは原則rootだけである。
つまり、rootから権限を落とすことに関しては、単純にプロセスのUID/GIDを書き換えることで実現できる。
例えばRubyだと、Process.uid=
, Process.euid=
,
Process.gid=
,
Process.egid=
というメソッドがあり、これらによってプロセスを書き換えることができる。
一般ユーザーでUIDを変更しようとした場合など、変更できないケースではErrno::EPERM
が発生する。
Zshで権限降格
Zshには$UID
, $EUID
, $GID
,
$EGID
といった変数があり、これらがプロセスの権限になっている。
これらを書き換えることで権限を変更可能だ。
ただ、$GID
,
$EGID
は$UID
を書き換えてしまうと、たとえそのユーザーが所属するグループであっても書き換えられなくなってしまい、必ずグループから先に書き換える必要がある。
この問題をより簡単に解決するのが$USERNAME
だ。
この変数は書き換えると、UIDとGIDの両方が変更される。
つまり、USERNAME=foo
とすれば、foo
ユーザーのUIDとなり、GIDに関してはfoo
ユーザーのプライマリグループになる。
ほとんどの場合、この$USERNAME
変数を使って降格を行う。
setpriv
はコマンドを実行するだけだが、$USERNAME
を使えば単純に降格して実行したい部分をカッコで囲むことで実現できるほか、関数の呼び出しも可能であるため、シェルスクリプトにおける権限降格としてはsetpriv
よりもかなり使いやすい。
# ROOT script
: ...
(
# USER script
USERNAME=http
logcheck
update_webdb
)
Bashでの事情とsetpriv
Bashにも同様の変数は存在するのだが、readonlyになっており、書き換えることができない。 BashにはBash内で完結する権限降格の方法が用意されていないのだ。
そのため、setpriv
のような外部コマンドを使うのだが、コマンド呼び出しにしか使えないのと、setpriv
はLinux固有であるため、いまひとつ潰しが効かない。
元記事で示された内容に誤りはないが、こうした事情や仕組みも併せて理解しておいたほうが良いだろう。