ククログ

株式会社クリアコード > ククログ > PolicyKitを用いて適切に権限管理するには

PolicyKitを用いて適切に権限管理するには

はじめに

CentOS 7ではPolicyKitによりユーザーの権限昇格・拒否の方法を柔軟に指定することができます。 実際に、CentOS 7では/etc/polkit-1/rules.d/50-default.rulesにより、管理者の認証が必要になった時に必要となるメソッドを追加しています。

/* -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- */

// DO NOT EDIT THIS FILE, it will be overwritten on update
//
// Default rules for polkit
//
// See the polkit(8) man page for more information
// about configuring polkit.

polkit.addAdminRule(function(action, subject) {
    return ["unix-group:wheel"];
});

これにより、CentOS 7ではwheelグループにいるユーザーはrootのパスワードを用いることなく各自のパスワードにて管理操作用に認証されるようになりました。

CentOS 7では従来通りの.pkla, .confを用いる方法も引き続き利用できます。

PolicyKitを持ちいる権限管理の初歩

PolicyKitを用いて適切に権限管理するにはまず、void polkit.addRules(polkit.Result function(action, subject){..})void polkit.addAdminRules(string[] function(action, subject){..}) の働きを知る必要があります。他にもいくつか関数がありますが、ここでは解説しません。

返り値を見ると両方ともvoidとなっていることから内部で副作用を起こす関数となっていることが推測されます。

まず、一つ目の関数の polkit.addRules(polkit.Result function(action, subject){..}) ついてはあるアクション(subject)に対する認証・拒否の設定を行います。polkit.Result定数は以下から選択してfunctionオブジェクトの返り値とします。

polkit.Result = {
    NO              : "no",              // 無条件で拒否、アクションは実行されません。
    YES             : "yes",             // 無条件で認証、アクションを実行します。
    AUTH_SELF       : "auth_self",       // 認証が必要だが管理者ユーザーの必要なし。
    AUTH_SELF_KEEP  : "auth_self_keep",  // 認証が必要だが管理者ユーザーの必要なし。一定期間後無効。
    AUTH_ADMIN      : "auth_admin",      // 認証が必要で管理者ユーザーの必要あり。
    AUTH_ADMIN_KEEP : "auth_admin_keep", // 認証が必要で管理者ユーザーの必要あり。一定期間後無効。
    NOT_HANDLED     : null               // このルールでは何もしない
};

これらの値のうちどれかをfunctionオブジェクトの返り値にすることになります。

二つ目の void polkit.addAdminRules(string[] function(action, subject){..}) のfunctionオブジェクトではユーザーグループ、または、ユーザー名とその対になる文字列の配列を返すことになります。

例えば、はじめにの節で例に挙げていた /etc/polkit-1/rules.d/50-default.rules では以下のように使われています。

polkit.addAdminRule(function(action, subject) {
    return ["unix-group:wheel"];
});

これはつまり管理者としての認証を求められた時にはwheelグループに属するユーザーのパスワードを用いることで管理者として振る舞えるようにします、というルールを追加しています。

PolicyKitのルールはファイル名の辞書順に読み込まれるため、rulesファイルで優先して読み込みたいルールがある場合は10や20などの小さい数字をファイル名の先頭へつけると良いでしょう。

権限管理の実例

ここで、PolicyKitの権限管理のあらましを解説したところで実例を見ていきます。 シャットダウン・再起動などの電源に関わる操作について権限管理してみます。

GNOMEデスクトップ環境からwheelに属さない一般ユーザーに対してシャットダウン・再起動などの電源に関わる操作をGNOMEデスクトップ上での操作を禁止することを目標にルールを定めてみることにします。

まず、対象となるアクションIDを知る必要があります。 freedesktop.orgのlogindの項目 によると、シャットダウン・再起動などの電源に関わる操作については以下のアクションIDが該当します。

  • シャットダウン

    • org.freedesktop.login1.power-off

    • org.freedesktop.login1.power-off-multiple-sessions

    • org.freedesktop.login1.power-off-ignore-inhibit

  • 再起動

    • org.freedesktop.login1.reboot

    • org.freedesktop.login1.reboot-multiple-sessions

    • org.freedesktop.login1.reboot-ignore-inhibit

  • サスペンド

    • org.freedesktop.login1.suspend

    • org.freedesktop.login1.suspend-multiple-sessions

    • org.freedesktop.login1.suspend-ignore-inhibit

  • ハイバネート

    • org.freedesktop.login1.hibernate

    • org.freedesktop.login1.hibernate-multiple-sessions

    • org.freedesktop.login1.hibernate-ignore-inhibit

アクションIDがわかったところで、ルールを作成しします。 これらのルールをまとめると以下のようになります:

polkit.addRule(function(action, subject) {
    if ((action.id == "org.freedesktop.login1.power-off"
      || action.id == "org.freedesktop.login1.power-off-multiple-sessions"
      || action.id == "org.freedesktop.login1.power-off-ignore-inhibit"
      || action.id == "org.freedesktop.login1.reboot"
      || action.id == "org.freedesktop.login1.reboot-multiple-sessions"
      || action.id == "org.freedesktop.login1.reboot-ignore-inhibit"
      || action.id == "org.freedesktop.login1.suspend"
      || action.id == "org.freedesktop.login1.suspend-multiple-sessions"
      || action.id == "org.freedesktop.login1.suspend-ignore-inhibit"
      || action.id == "org.freedesktop.login1.hibernate"
      || action.id == "org.freedesktop.login1.hibernate-multiple-sessions"
      || action.id == "org.freedesktop.login1.hibernate-ignore-inhibit")
      && subject.isInGroup("wheel")) {
        return polkit.Result.YES;
    }
    else {
        return polkit.Result.NO;
    }
});

これを、 /etc/polkit-1/rules.d/55-disallow-power-related-rules-for-general-user.rules のような名前で保存します。その後、polkitを止め、再度起動させます。

$ sudo systemctl stop polkit
$ sudo systemctl start polkit

/var/log/messagesのようなsyslogのログに以下のようなログが出ていれば登録に成功しています。

Dec 26 16:37:50 localhost systemd: Stopped Authorization Manager.
Dec 26 16:37:50 localhost systemd: Starting Authorization Manager...
Dec 26 16:37:50 localhost polkitd[4129]: Started polkitd version 0.112
Dec 26 16:37:50 localhost dbus[686]: [system] Successfully activated service 'org.freedesktop.PolicyKit1'
Dec 26 16:37:50 localhost dbus-daemon: dbus[686]: [system] Successfully activated service 'org.freedesktop.PolicyKit1'
Dec 26 16:37:50 localhost systemd: Started Authorization Manager.
Dec 26 16:37:51 localhost gnome-session: PolicyKit daemon reconnected to bus.

このルールが適用されているかどうかを確認してみます。 一般ユーザーのnormaluser1ユーザーを作成します。

その後、GNOME環境にログインすると、シャットダウンや再起動操作関連のUIがなくなっていることがわかります。

一般ユーザーの電源管理画面: 一般ユーザーの電源管理画面

wheelユーザーの電源管理画面: wheelユーザーの電源管理画面

まとめ

PolicyKitのルールにより、一般ユーザーの電源管理の操作を禁止する実例を提示しました。このPolicyKitの仕組みはKDEでも一部利用されています。 この他利用用途としては、特権が要求される操作に対してのルールを作成し、一般ユーザーから操作できるようにすることもできます。 例えばドライブのマウントはハードウェアが絡むため、この操作はLinuxでは通常、管理者特権が要求されます。 これに対してもPolicyKitのルールにより一般ユーザーから操作可能にすることができます。例えば、udisksに対するPolkitのアクションのリストはここを参考にすると良いです。