
管理者権限を持たないユーザーに管理者ユーザーのIDとパスワードを教えずに管理者権限を持たせる方法
ものすごく長いタイトルになってしまいましたが、今回は管理者権限を持たないユーザーにどのように管理者権限を持たせるか、というお話です。
実際の案件の中では以下のような状況が頻繁にあります。
- エンドユーザーの端末にソフトウェアをインストールさせたい、あるいは管理者権限が無いとできない設定変更をさせたい
- でも、エンドユーザーのアカウントには管理者権限がない
- エンドユーザーに操作をしてもらうことは可能だけど、管理者のID、パスワードは教えたくない(セキュリティ上の問題)
やりたいことは簡単なんですけど、「エンドユーザーには教えずに」ということを実現させようと思うと中々大変です。
理想の状況
このようなことは頻繁にあるものなので、これらを簡単に実現するツールが全端末に仕込まれている状況が理想的です。これを実現する製品は多数存在しています。有名なところだと以下のようなものでしょうか。(私が仕事でよく扱っているものなので、偏ってるかもしれません。)
- System Center Configuration Manager : ホーム
- IT資産管理 ツール QND Plus | クオリティ
- LanScope Cat6 トップページ
- BigFix, Inc. | Faster, Smarter Systems Management
もっとも、これらの製品は総合的な管理ツールになっているので、今回話題にしていることだけをしたいような時に導入するようなものでもないです。お値段も結構しますし…、ということでこういった製品が導入されていない企業も数多くあります。特に日本企業には多い印象です。話で聞くところによると米国企業はほとんどなにかしら導入しているらしいですけれども。
Active Directoryのグループポリシーを使う方法
製品が導入されていない状況でこれを実現する方法として、まずADのGPOを使う方法があります。
ソフトウェアインストール
例えばソフトウェア配布なら「ソフトウェアインストール」を使うことができます。
ただ、これがなかなか曲者でして、以下の制限事項があります。
- インストールできるのはmsiパッケージのみ(setup.exeなどは無理)
- 「コンピューターの構成」-「ソフトウェアインストール」で構成した場合ローカルのSYSTEM権限で実行される
- 「ユーザーの構成」-「ソフトウェアインストール」で構成した場合ログオンユーザーの権限で実行される(今回の場合使えない)
- インストールに成功したのか、失敗したのか、どの程度の進捗なのか等を管理者が把握できない
1.の制限により、そもそもこの機能では配布できないことが結構あります。2.の制限があるのでパッケージの置き場所はドメインユーザー以外もアクセス可能にしなくてはいけませんし、都合の悪いことにそもそもSYSTEM権限ではインストールが成功しないソフトウェアが結構存在します。そして、4の制限があるので、トラッキングができません。
というわけで、やってみてうまく動けばそれでいいのですが、結構なケースでこの方法が取れないことがあります。
スタートアップスクリプト
「ソフトウェアインストール」が使えない場合、あるいはそもそもソフトウェアインストールではない場合にはスタートアップスクリプトを使うこともできます。
これであれば自分でロジックを作り込めるのでsetup.exe等の実行ファイルであってもキックすることができます。また、成功、失敗等の把握はどうにでもできます。簡単にやるなら、例えばインストールログを共有フォルダに保存させるようなロジックにしてしまえばいいでしょう。
ですが、以下の制限事項は同じです。
- 「コンピューターの構成」-「ソフトウェアインストール」で構成した場合ローカルのSYSTEM権限で実行される
- 「ユーザーの構成」-「ソフトウェアインストール」で構成した場合ログオンユーザーの権限で実行される(今回の場合使えない)コンピューターの構成に仕込んでみて、ローカルのSYSTEM権限のみでうまく行くことを祈ることになります。
このようにADを使う方法はどのパターンでも確実に成功するわけではありません。そして、そもそも論としてはADに参加しているクライアントでなければこの方法は取れないわけです。
その他の方法
他の方法としては以下のようなものがあります。どれも完全なソリューションではないですが・・・。
- 右クリック→別のユーザーで実行→ID, Passを実行
- 自動化できない。WindowsのGUIを操作するツールを使って頑張ればできないこともないはずですが現実的ではないでしょう。
- タスクスケジューラーをセットし、実行ユーザーを指定
- やれば自動化までできますが、タスクスケジューラーを使う以上どうしても確実性に欠けます。実際にやる場合にはタスクスケジューラーに登録するコマンドを実行させる形になります。
- runasコマンドを使う
- runasコマンドは標準で別ユーザーとしてコマンドを実行できるのですが、コマンドライン引数にパスワードを渡すことができず、パスワードは別途入力する必要があります。これを無理やり入力させようと思うとGUI操作ツールやWSHのSendKeysメソッドを使うことになります。ですが、この方法だと、ユーザーにフォーカスを移されてしまえばすぐに失敗しますし、実行端末によって処理速度が違うので入力が速すぎて失敗してしまうという問題があります。そうするとスリープを適度に入れることになるのですが、この「適度」は端末固有なので…かなり失敗率が上がってしまうことになります。
- exec.vbsをつかう(リモートのみ)
- Windows 2000のResourceKitに入ってます。中ではWMIを使って別の資格情報で実行させているのですが、同一ホスト内で別のユーザーとして実行させることはできません。今回のケースに当てはめるのはちょっと難しいですね。
おすすめの方法
色々紹介してきましたが、私が色々試した結果個人的に一番おすすめできるのはpsexecを使う方法です。
このツールは本当に素晴らしいツールで、何も構成していないリモートコンピューター上のシェルをインタラクティブに叩くことすら出来てしまいます。もちろん、今回やりたいことも実現できます。
- コマンドラインオプションでIDとパスワードを指定して、任意のユーザーでのコマンド実行
- ローカルコンピューター上で別ユーザーとして実行
まず、やりたいことをバッチ、スクリプト等で書いておき、それをpsexecを使って別ユーザーで実行させてあげるような形が良いでしょう。あとはユーザーに配って叩いてもらうもよし、スタートアップスクリプトやログオンスクリプトに組み込んで自動で実行させるもよし、です。
実際のスクリプトの中身
実際には、以下のようにWScript.ShellのRunメソッドを使ってコマンドをキックするのがいいと思います。こうしておけばウインドウの状態のコントロールや、同期実行、非同期実行のコントロールもできるので一石二鳥です。
1: <job id="main">
2: <script language="VBScript">
3: Set objFSO = WScript.CreateObject("Scripting.FileSystemObject")
4: scriptpath = objFSO.GetParentFolderName(WScript.ScriptFullName)
5: Set objWshShell = WScript.CreateObject("WScript.Shell")
6: ReturnCode = objWshShell.Run(scriptpath & "\psexec.exe -accepteula -u test\admin -p password cmd /c hoge.bat", 0, true)
7: WScript.Quit(ReturnCode)
8: </script>
9: </job>
ちなみに上記の例ではスクリプトと同じ場所にpsexec.exeが置かれていることを想定しています。
あとはこれをwsfで保存しておき、スクリプトエンコーダーでエンコードしてあげれば出来上がりです。
暗号化
ここまでで、別ユーザー(管理者権限をもつユーザー)としてコマンドを実行させることはできたわけですが、このままですとユーザーにバッチ、スクリプトの中身を見られてしまうとIDとパスワードがバレてしまいます。「実行はできるけど、読めない」という権限設定はできないので、暗号化を行う必要があります。
暗号化する方法にも色々ありますが、手をかけずに必要最低限の目的を達成するにはスクリプトエンコーダーを利用するのが最も簡単です。
スクリプトエンコーダーはWSHのスクリプトを暗号化し、それをそのまま実行することができます。Windowsの標準機能で何も手を加えること無く実行させることができるので非常に楽です。
ただし、この方法で暗号化してあるだけだと、一般的なエンドユーザーには中身を見られませんが、悪意(あるいは好奇心)と知識を併せ持っている人には簡単に復号化されてしまいます。ちょっと探せばその手のツールなり、サイトなりみつかりますので、「これで絶対に安心」とは思わないで下さい。
本気でやるなら独自に暗号化、復号化の仕組みを作ってあげる必要があるでしょう。
ツールを作っておくと楽
私は毎回スクリプトを書くのも面倒なので、一連の作業を自動化して暗号化したスクリプトを作成するツールを作っておき、それを使うことにしました。仕事の時間で作ったものなので公開はできないのですが、イメージはこんな感じです。
この手のお手軽書き捨てツールはいくつか揃えておくと、このあたりを理解出来ない人にも簡単に使ってもらえるのでいいかもしれません。(よくない面もあるかとは思いますが・・・。)
まとめ
色々書きましたがまとめますとクライアントの統合的な管理ツールが導入されていない環境で簡易的にユーザー権限しか持たないユーザーに管理者権限でコマンドを実行させつつIDパスワードを教えないためには以下の方法がおすすめだということです。
- まず、目的を達成するスクリプト、バッチを書く。(結果のトラッキング処理も付けておきましょう)
- 上記のスクリプト、バッチをpsexecを使って別ユーザーで実行させるラッパーのWSFを書く(WScript.ShellのRunメソッドがお勧め)
- 上記のWSFをスクリプトエンコーダーで暗号化する
他にも色々やり方はあるかとは思います。お勧めの方法があったらコメント欄で教えていただければと思います!
- 右クリック→別のユーザーで実行→ID, Passを実行
「実際のスクリプトの中身」を参考にさせて頂き、大変助かりました。サンプルのスクリプト6行目ですが、psexec.exeの前に「\」が必要でした。
6: ReturnCode = objWshShell.Run(scriptpath & “psexec.exe -accepteula -u testadmin -p password cmd /c hoge
↓
ReturnCode = objWshShell.Run(scriptpath & “\psexec.exe -accepteula -u testadmin -p password cmd /c hoge