カスタムロール

Ultimateのお客様は、カスタムロールを作成し、特定の能力を割り当ててロールを定義することができます。

たとえば、ユーザーは、read code およびadmin merge requests の能力を持ち、admin issuesのような能力を持たない「エンジニア」ロールを作成できます。

この文脈では、「権限」と「能力」という用語はしばしば同じ意味で使われます。

  • 「能力」はユーザーができるアクションです。これらはDeclarative Policyの能力にマッピングされ、ee/app/policies/* のPolicyクラスに存在します。
  • “権限 “は、ユーザー向けのドキュメントで能力を参照する方法です。権限に関する文書は手動で生成されるため、文書に記載されている権限と Policy クラスに定義されている能力は必ずしも 1 対 1 で対応付けられるわけではありません。

カスタム・ロールと静的ロール

GitLab 15.9以前では、GitLabには権限システムとして静的ロールしかありませんでした。このシステムでは、特定の能力に静的に割り当てられるいくつかの定義済みのロールがあります。これらの静的ロールは顧客がカスタマイズすることはできません。

カスタムロールでは、どの能力を特定のユーザーグループに割り当てるかを顧客が決めることができます。例えば

  • 静的ロールシステムでは、脆弱性の読み取りは開発者ロールに制限されています。
  • カスタムロールシステムでは、顧客はこの能力を、任意の静的ロールに基づく新しいカスタムロールに割り当てることができます。

静的ロールのように、カスタムロールはグループ階層内で継承されます。ユーザーがグループのカスタム・ロールを持つ場合、そのユーザーはグループ内のプロジェクトやサブグループのカスタム・ロールも持つことになります。

技術的な概要

  • 個々のカスタムロールはmember_roles テーブル (MemberRole モデル) に格納されます。
  • member_roles レコードは、namespace_id 外部キーを介してトップレベルのグループ(サブグループではない)に関連付けられます。
  • グループまたはプロジェクトメンバーシップ(members レコード)は、member_role_id 外部キーを介してカスタムロールに関連付けられます。
  • グループまたはプロジェクト・メンバーシップは、グループまたはプロジェクトのルートレベル・グループに定義されているカスタム・ロールに関連付けることができます。
  • member_roles テーブルには、内部権限とbase_access_level 値が含まれます。
  • base_access_level有効なアクセス・レベルでなければなりません。はbase_access_level カスタム・ロールに含まれる能力を決定 base_access_levelします。例えば、10base_access_level 場合 base_access_level、カスタム・ロールには静的なゲスト・ロールが受け取る権限に加え、read_codeのような属性をtrueに設定することでmember_roles のレコードが有効にする追加権限が含まれます。
  • カスタムロールはbase_access_level の追加能力を有効にすることはできますが、権限を無効にすることはできません。結果として、カスタム・ロールは「追加のみ」です。この選択の根拠はこのコメントにあります。
  • 今のところ、カスタムロールの能力はプロジェクトレベルでのみサポートされています。カスタムグループ能力のサポートを追加するイシューがあります。

カスタム・ロールの新しい能力を実装する方法

通常、新しい能力のために2-3個のマージリクエストを作成する必要があります。大まかなガイダンスは以下のとおりです:

  1. カスタムロールに能力を追加したい機能を選んでください。
  2. 機能のリファクタリングとアビリティの統合 (機能の複雑さに応じて1-2回のマージリクエスト)
  3. 新しい能力の実装 (1 マージリクエスト)

能力のリファクタリング

既存の能力チェックの検索

一つのエンドポイントやウェブリクエストに対して、複数の場所でアビリティがチェックされることがよくあります。そのため、特定のエンドポイントに対して実行される作成者チェックのリストを見つけるのは難しいかもしれません。

これを支援するために、内部でGITLAB_DEBUG_POLICIES=true を設定することができます。

これは、あなたが実行するどの仕様のリクエストでどの能力がチェックされたかという情報を出力します。出力には、作成者チェックが行われたコード行も含まれます。呼び出し元の情報は、メタプログラミングが使用されている場合に特に役に立ちます。

使用例:

# example spec run

GITLAB_DEBUG_POLICIES=true bundle exec rspec spec/controllers/groups_controller_spec.rb:162

# permissions debug output when spec is run; if multiple policy checks are run they will all be in the debug output.

POLICY CHECK DEBUG -> policy: GlobalPolicy, ability: create_group, called_from: ["/gitlab/app/controllers/application_controller.rb:245:in `can?'", "/gitlab/app/controllers/groups_controller.rb:255:in `authorize_create_group!'"]

リファクタリング中の作成者チェックについて詳しく知りたい場合は、この設定を使用します。デフォルトブランチの仕様では、この設定を有効にしておくべきではありません。

個々の能力に関するロジックの理解

ある能力への参照は、DeclarativePolicy クラス内に何度も出現し、他の能力を参照する条件やルールに依存する場合があります。そのため、どの条件が特定の能力に適用されるかを正確に知ることは困難な場合があります。

DeclarativePolicy は、各ポリシークラスに対して、ability_map を提供し、能力のすべてのルールを配列に取り込みます。

使用例:

> GroupPolicy.ability_map.map.select { |k,v| k == :read_group_member }
=> {:read_group_member=>[[:enable, #<Rule can?(:read_group)>], [:prevent, #<Rule ~can_read_group_member>]]}

> GroupPolicy.ability_map.map.select { |k,v| k == :read_group }
=> {:read_group=>
  [[:enable, #<Rule public_group>],
   [:enable, #<Rule logged_in_viewable>],
   [:enable, #<Rule guest>],
   [:enable, #<Rule admin>],
   [:enable, #<Rule has_projects>],
   [:enable, #<Rule read_package_registry_deploy_token>],
   [:enable, #<Rule write_package_registry_deploy_token>],
   [:prevent, #<Rule all?(~public_group, ~admin, user_banned_from_group)>],
   [:enable, #<Rule auditor>],
   [:prevent, #<Rule needs_new_sso_session>],
   [:prevent, #<Rule all?(ip_enforcement_prevents_access, ~owner, ~auditor)>]]}

DeclarativePolicy にもdebug メソッドがあり、特定のオブジェクトとアクターのロジック ツリーを理解するために使用できます。出力は、ability_map からのルールのリストと似ています。しかし、DeclarativePolicy は、prevent アビリティの後にルールの評価を停止するので、すべての条件が呼び出されない可能性があります。

使用例:

policy = GroupPolicy.new(User.last,  Group.last)
policy.debug(:read_group)

- [0] enable when public_group ((@custom_guest_user1 : Group/139))
- [0] enable when logged_in_viewable ((@custom_guest_user1 : Group/139))
- [0] enable when admin ((@custom_guest_user1 : Group/139))
- [0] enable when auditor ((@custom_guest_user1 : Group/139))
- [14] prevent when all?(~public_group, ~admin, user_banned_from_group) ((@custom_guest_user1 : Group/139))
- [14] prevent when needs_new_sso_session ((@custom_guest_user1 : Group/139))
- [16] enable when guest ((@custom_guest_user1 : Group/139))
- [16] enable when has_projects ((@custom_guest_user1 : Group/139))
- [16] enable when read_package_registry_deploy_token ((@custom_guest_user1 : Group/139))
- [16] enable when write_package_registry_deploy_token ((@custom_guest_user1 : Group/139))
  [21] prevent when all?(ip_enforcement_prevents_access, ~owner, ~auditor) ((@custom_guest_user1 : Group/139))

=> #<DeclarativePolicy::Runner::State:0x000000015c665050
 @called_conditions=
  #<Set: {
   "/dp/condition/GroupPolicy/public_group/Group:139",
   "/dp/condition/GroupPolicy/logged_in_viewable/User:83,Group:139",
   "/dp/condition/BasePolicy/admin/User:83",
   "/dp/condition/BasePolicy/auditor/User:83",
   "/dp/condition/GroupPolicy/user_banned_from_group/User:83,Group:139",
   "/dp/condition/GroupPolicy/needs_new_sso_session/User:83,Group:139",
   "/dp/condition/GroupPolicy/guest/User:83,Group:139",
   "/dp/condition/GroupPolicy/has_projects/User:83,Group:139",
   "/dp/condition/GroupPolicy/read_package_registry_deploy_token/User:83,Group:139",
   "/dp/condition/GroupPolicy/write_package_registry_deploy_token/User:83,Group:139"}>,
 @enabled=false,
 @prevented=true>

アビリティの統合

カスタムロールに追加されるすべての機能は最小限の能力を持つべきです。ほとんどの機能については、read_*admin_* があれば十分です。すべてを統合すべきです:

  • read_* 。例えば、リストや詳細の表示。
  • admin_* にあるオブジェクトの更新。例えば、オブジェクトの更新、担当者の追加、オブジェクトのクローズなど。通常、admin_ を有効にするロールは、read_ の能力も有効にしなければなりません。これはMemberRole モデルのALL_CUSTOMIZABLE_PERMISSIONS ハッシュのrequirement オプションで定義されています。

追加の能力を必要とする機能があるかもしれませんが、それらを最小限にするようにしてください。いつでもAuthentication and Authorizationグループのメンバーに意見や助けを求めることができます。

また、ここから作業を始めるべきです。作業する機能のすべての能力を取り出し、それらの能力をread_admin_ 、または必要であれば追加能力に統合してください。

GroupPolicy およびProjectPolicy クラスの多くの能力には、多くの冗長なポリシーがあります。これらのポリシークラスを統合するためのエピックがあります。これらのクラスで同じような権限に遭遇した場合、同じ名前を持つようにリファクタリングすることを検討してください。

たとえば、GroupPolicy にはread_group_security_dashboard という権限があり、ProjectPolicy にはread_project_security_dashboard という権限があります。両方ともカスタマイズ可能にしたいでしょう。member_roles それぞれの能力についてテーブルに member_roles行を追加するよりも、member_roles 名前を変更してテーブルにread_security_dashboard 追加 read_security_dashboardすることを検討して member_rolesください。これは、親グループでread_security_dashboard を有効にすると、カスタムが有効になることを意味するので、より期待されます。例えば、GroupPolicy にはread_group_security_dashboard という能力があり、ProjectPolicy にはread_project_security_dashboardという能力があります。両方をカスタマイズ可能にしたい場合、member_roles 各能力の member_roles行をmember_roles テーブルに追加するのではなく、それらの名前を member_roles変更してテーブルにmember_roles read_security_dashboard 追加 read_security_dashboard member_rolesすることをmember_roles 検討して member_rolesください。この規約は、親グループでread_security_dashboard を有効にすると、カスタムロールがそのグループ内の各プロジェクトのグループセキュリティダッシュボードとプロジェクトセキュリティダッシュボードにアクセスできるようになることを意味します。特定のプロジェクトで同じ権限を有効にすると、そのプロジェクトのセキュリティダッシュボードにアクセスできるようになります。

新しい機能の実装

カスタム・ロールに新しい能力を追加します:

  • 例えば、マージリクエスト114734のこの変更ではmember_roles テーブルに新しい列を追加します。
  • MemberRole モデルにALL_CUSTOMIZABLE_PERMISSIONS ハッシュ ALL_CUSTOMIZABLE_PERMISSIONS機能を追加しました(ALL_CUSTOMIZABLE_PERMISSIONS マージリクエスト 121534ALL_CUSTOMIZABLE_PERMISSIONSの変更例)。ALL_CUSTOMIZABLE_PERMISSIONS ハッシュには以下のキーが ALL_CUSTOMIZABLE_PERMISSIONSあります:

    • description - 能力の説明。
    • minimal_level - ユーザーが能力に割り当てられるために必要な最小レベル。
    • requirement - ハッシュで定義された能力に必要な能力。要件がfalse である場合、その能力はtrue できません。
  • 例えば、マージリクエスト114734のこの変更では、それぞれのポリシーに能力を追加します。
  • 仕様を更新しました。

カスタムロールに新しい能力を追加するマージリクエストの例:

  • コードを読む
  • 脆弱性を読む
  • 管理者の脆弱性- これは新しいカスタムロール機能を実装した最新のMRです。以前のMRからのいくつかの変更はもう必要ありません(例えば、プリローダー・クエリの変更やUser モデルへのメソッドの追加)。

新しいカスタムロール機能が機能フラグの下にあることを確認する必要があります。

シートの消費

ロールGuest を持つ新規ユーザーが、CUSTOMIZABLE_PERMISSIONS_EXEMPT_FROM_CONSUMING_SEAT 配列にない能力を有効にすることを含むメンバーロールに追加された場合、シートが消費されます。単純に、”昇格 “した能力を持つゲスト・ユーザーに対して、アルティメット・カスタマーに課金していることを確認したいだけです。これは、SaaSの課金対象ユーザー(ネームスペース・サブスクリプションにカウントされる課金対象ユーザー)にのみ適用されます。このトピックの詳細については、このイシューを参照してください。