「一般ユーザ権限だけでは出来ないシステム操作を、ユーザごとにできることを制約して許可したい」という用途はUnixでは結構あり、全てがcapabilityのようなシステム提供の機能では制御できないため、Unix系OSではその多くがsetuidという仕組みを通じて実現されています。例えば、passwdコマンドでは「全員のパスワードが書かれたデータベースの内、自分のパスワードだけを変更できる」とか、そういう類のものです。
そして、もうかなりの昔語りですが、かつて Perl には suidperl という setuid をサポートする仕組みがありました。Unixのセキュリティ上の欠点を克服してスクリプトのsetuidをシミュレートする仕組みでしたが、なかなかkernelの支援なしに安全に作るのは難しく、2010年に削除されてしまいました。
Perlのマニュアルを見ると、
Use of suidperl is highly discouraged. If you think you need it, try alternatives such as sudo first.
「suidperl」の使用はお勧めしないよ。もし必要だと思ったら、sudoとか別のものを先に試してね!
と書いてあります……なんといい加減な。
というのは、sudo は実行できるコマンドは厳しく制限できるのですが、コマンドそのものは root 権限などでそのまま実行されるので、例えば上の passwd コマンドでいうと、「特定の人だけが全員のパスワードを変更できる」とか「AさんがAさんのパスワードを変更できる(それぞれ自分の、ではない)」のような制限しか出来ないのです。手元では suidperl script を置き換える段階で、この性質にかなり困りました。
というわけで、「じゃぁ sudo でちゃんとユーザ別の分岐処理できる環境を作るか」といって書き始めたところ、結構巨大なライブラリになってしまいました。
セキュリティ的には、実行可能なコマンドが「sudoの設定が許したコマンド」に限定されていて、「権限を落とすだけ」のライブラリなので、suidperlよりは随分楽で、確かに suidperl の better alternative にはなっていますが、それにしても結構複雑な処理が必要でした。
「自分で自分をsudoで呼ぶ」辺りは、できるだけユーザの使い勝手が悪くならないように工夫をしたところです。必要があったら参考にしてくれると良いなと思います。
ちなみに、技術的にこのヘルパーの内部実装で一番セキュリティ的に面倒なところは、「誰が起動したか」をきちんとsudoと連携して把握するところです。sudo は環境変数に「誰」の情報をセットしてくれるのですが、「本当にsudoがセットしたものなのか」がそう簡単にはわからない。その辺りをチェックするために、かなりシステムのいろいろな情報を調べています。それでも root だと色々微妙な判定しきれないケースを作れるので、その辺りは安全サイドに倒しています。(そのせいで、元からrootのときだけ使い勝手がちょっと悪い。)
0 件のコメント:
コメントを投稿