背景と応用シナリオ
Salesforce アーキテクトとして、我々が対峙する最も重要かつ複雑な課題の一つが、データセキュリティと可視性の設計です。堅牢なセキュリティモデルの基盤は、Organization-Wide Defaults (OWD) (組織の共有設定) にあります。これは、特定のオブジェクトのレコードに対して、ユーザーがデフォルトで持つべき最も低いアクセス権限レベルを定義するものです。「非公開(Private)」や「公開/参照のみ(Public Read Only)」といった制限的な設定は、最小権限の原則(Principle of Least Privilege)を適用するためのベストプラクティスです。
しかし、ビジネスプロセスはしばしば、この厳格なベースラインを超えるアクセス権の拡張を要求します。例えば、ある営業担当者が所有する商談レコードを、同じ地域のチームメンバー全員が閲覧・編集できるようにしたい場合や、特定製品ラインに関するすべてのケースを、専門のサポートチームが共同で対応できるようにしたい場合があります。このような「水平方向」のアクセス権拡張を実現するために設計されたのが、Sharing Rules (共有ルール) です。
Sharing Rules は、OWD によって制限されたアクセス権を、特定の条件下で特定のユーザーグループに対して選択的に開放するための宣言的なツールです。アーキテクトの視点から見れば、これはデータアクセスモデルにおけるスケーラビリティと管理性を両立させるための重要なコンポーネントと言えます。
具体的な応用シナリオ:
- 地域ベースの共有:東日本営業チーム(ロールまたは公開グループで定義)に、取引先責任者の所有者が東日本チームのメンバーであるすべての商談レコードへの参照・更新アクセス権を付与する。
- 機能ベースの共有:製品カテゴリが「クラウドサービス」であるすべてのケースレコードを、「クラウドサポート」公開グループに所属する全ユーザーが参照・更新できるようにする。
- 部門横断プロジェクト:マーケティング部門と営業部門が共同で進めるキャンペーンに関連するカスタムオブジェクトレコードを、両部門のメンバーが含まれる公開グループに共有する。
これらのシナリオにおいて、Sharing Rules はコードを記述することなく、柔軟かつ予測可能な方法でデータ可視性を制御する手段を提供します。
原理説明
Sharing Rules の動作原理を理解することは、パフォーマンスとスケーラビリティを考慮したアーキテクチャを設計する上で不可欠です。宣言的な設定の背後で、Salesforce は非常に具体的なデータ構造を使用してアクセス権を管理しています。
すべての共有設定は、最終的に各オブジェクトに対応するShare Object (共有オブジェクト) にレコードとして格納されます。例えば、取引先 (Account) オブジェクトの共有設定は AccountShare
というオブジェクトに、カスタムオブジェクト Project__c
の場合は Project__share
というオブジェクトに保存されます。
Sharing Rule が作成され、条件に合致するレコードが存在すると、Salesforce はバックグラウンドでこの Share Object にレコードを自動的に挿入します。この AccountShare
レコードには、以下のような重要な項目が含まれています。
- AccountId: 共有される取引先レコードの ID。
- UserOrGroupId: アクセス権を付与されるユーザーまたは公開グループ (Public Group)、ロール (Role)、テリトリー (Territory) の ID。
- AccessLevel: 付与されるアクセスレベル(例:「Read」、「Edit」)。
- RowCause: なぜこの共有レコードが存在するのかを示す理由。Sharing Rule によって作成された場合、この値は
Rule
になります。手動共有の場合はManual
、所有者であることによるアクセスの場合はOwner
となります。
アーキテクトとして、この RowCause
を理解することは極めて重要です。なぜなら、データアクセスに関する問題のトラブルシューティングを行う際に、「なぜこのユーザーはこのレコードにアクセスできるのか?」という問いに答えるための直接的な手がかりとなるからです。
Sharing Rules には、主に2つのタイプが存在します。
1. 所有者に基づく共有ルール (Owner-based Sharing Rules)
このルールは、レコードの所有者に基づいて共有を決定します。特定の公開グループ、ロール、またはテリトリーに所属するユーザーが所有するレコードを、別の公開グループ、ロール、またはテリトリーのメンバーと共有します。例えば、「西日本営業ロールのメンバーが所有するすべての取引先を、東日本営業ロールのメンバーに参照のみで共有する」といった設定が可能です。
2. 条件に基づく共有ルール (Criteria-based Sharing Rules)
このルールは、レコードの項目の値に基づいて共有を決定します。所有者に関係なく、レコードが特定の条件を満たした場合に共有が実行されます。例えば、「取引先の `Industry` (業種) 項目が `Technology` であるすべてのレコードを、`Technology Specialist` 公開グループに参照・更新権限で共有する」といった設定です。このタイプは、ビジネスロジックに基づいて動的にアクセス権を付与する必要がある場合に非常に強力です。
重要な点として、Sharing Rules は常に追加的に機能します。つまり、アクセス権を付与することしかできず、OWD や他の共有メカニズムで既に許可されているアクセス権を奪うことはありません。また、ルールが作成・更新されたり、レコードの所有者や条件に合致する項目値が変更されたりすると、Salesforce は共有の再計算 (Sharing Recalculation) を実行します。大規模なデータボリュームを持つ組織では、この再計算プロセスがパフォーマンスに与える影響を十分に考慮する必要があります。
サンプルコード
Sharing Rules は主に宣言的に設定しますが、その背後にある Share Object は Apex を通じてプログラムで操作することも可能です。これは Apex Managed Sharing (Apex による共有管理) と呼ばれ、標準の共有ルールでは実現不可能な、より複雑な共有ロジックを実装する際に使用されます。アーキテクトは、この programmatic な選択肢の存在と、その適用シナリオを理解しておくべきです。
以下のコードは、特定の取引先レコード (Account) を、特定のユーザーに対してプログラムで共有する例です。これは Sharing Rule そのものではありませんが、同じ AccountShare
オブジェクトを操作することで、その基礎となるメカニズムを示しています。
Apex を使用した AccountShare レコードの作成
この例では、ある取引先レコードへの参照・更新アクセス権を、指定したユーザーに付与します。
// 共有したい取引先とユーザーを取得 Account acct = [SELECT Id FROM Account WHERE Name = 'My Target Account' LIMIT 1]; User usr = [SELECT Id FROM User WHERE Username = 'testuser@example.com' LIMIT 1]; // AccountShare オブジェクトの新しいインスタンスを作成 AccountShare newShare = new AccountShare(); // 共有するレコードの ID を設定 newShare.AccountId = acct.Id; // アクセス権を付与するユーザーまたはグループの ID を設定 newShare.UserOrGroupId = usr.Id; // 付与するアクセスレベルを設定 ('Read' または 'Edit') // CaseAccessLevel、ContactAccessLevel、OpportunityAccessLevel は取引先へのアクセス権に応じて設定 // 'None', 'Read', 'Edit' から選択 newShare.AccountAccessLevel = 'Edit'; newShare.CaseAccessLevel = 'None'; newShare.ContactAccessLevel = 'Read'; newShare.OpportunityAccessLevel = 'None'; // RowCause を設定。Apex Managed Sharing の場合、カスタムの RowCause を作成する必要がある // このカスタム RowCause は、Apex Sharing Reason としてオブジェクトの共有設定ページで事前に定義しておく // ここでは、'My_Custom_Reason__c' という API 名の理由を想定 newShare.RowCause = Schema.AccountShare.RowCause.My_Custom_Reason__c; // データベースに挿入 try { Database.SaveResult sr = Database.insert(newShare, false); // DML オプションを false に設定し、部分的な成功を許容 if (sr.isSuccess()) { System.debug('共有レコードが正常に作成されました。'); } else { for (Database.Error err : sr.getErrors()) { System.debug('共有レコードの作成中にエラーが発生しました: ' + err.getMessage()); } } } catch (DmlException e) { System.debug('DML 例外が発生しました: ' + e.getMessage()); }
コードの注釈:
- 1-2行目: 共有の対象となる取引先レコードと、アクセス権を付与するユーザーを取得しています。
- 5行目: 共有レコードを保持するための
AccountShare
オブジェクトのインスタンスを生成します。 - 8-19行目: 共有レコードの必須項目を設定します。
AccountId
とUserOrGroupId
は共有の「対象」と「相手」を定義します。AccountAccessLevel
はそのレコード自体へのアクセスレベルです。 - 23行目:
RowCause
は共有の理由を示します。Apex Managed Sharing を使用する場合、まず対象オブジェクトの「共有設定」から「Apex 共有の理由 (Apex Sharing Reasons)」を事前に作成しておく必要があります。これにより、なぜこのプログラムによる共有が存在するのかを追跡し、管理することが容易になります。 - 26-36行目:
Database.insert
を使用して Share レコードを挿入します。第二引数にfalse
を指定することで、All-or-None 動作を無効にし、エラーが発生しても他の処理が失敗しないようにしています。これは、バルク処理で一部の共有が既に存在する場合などに有効なエラーハンドリングです。
注意事項
Sharing Rules とその関連機能を設計・実装する際には、アーキテクトとして以下の点に細心の注意を払う必要があります。
1. パフォーマンスへの影響
Sharing Rules の最も重要な考慮事項はパフォーマンスです。特に数百万件以上のレコードを持つLarge Data Volumes (LDV) の組織では、共有の再計算がシステム全体に大きな影響を与える可能性があります。
- 再計算のトリガー:Sharing Rule の作成・変更、ロール階層の変更、公開グループのメンバー変更、レコード所有者の変更、ルール条件に含まれる項目値の変更など、多くの操作が再計算をトリガーします。
- ロック競合:共有再計算の実行中に、関連するレコードやグループメンバーシップに対して DML 操作(挿入、更新)を行うと、
UNABLE_TO_LOCK_ROW
というエラーが発生する可能性があります。これは、Salesforce がデータの一貫性を保つためにテーブルをロックするためです。データ移行やバッチ処理を計画する際は、再計算のタイミングを考慮に入れる必要があります。 - 遅延:再計算は非同期で実行されますが、完了までに数分から数時間かかる場合があります。この間、ユーザーのデータ可視性は古い状態のままかもしれません。
2. 制限
Salesforce には、オブジェクトごとに作成できる Sharing Rules の数に制限があります。通常、オブジェクトごとに最大300の共有ルール(うち、条件に基づくルールは最大50)を作成できますが、この制限はエディションや追加機能によって異なる場合があるため、常に最新の Salesforce ドキュメントで確認してください。制限に近づいている場合は、ルールの統合(複数のルールを1つの条件にまとめる、公開グループをより効果的に活用するなど)や、Apex Managed Sharing の利用を検討する必要があります。
3. ゲストユーザー共有ルール (Guest User Sharing Rules)
Experience Cloud (旧Community Cloud) サイトなどで認証されていないゲストユーザーにレコードへのアクセスを許可する場合、特別な「ゲストユーザー共有ルール」を使用する必要があります。これはセキュリティ上の理由から必須であり、条件ベースのルールのみが利用可能です。ゲストユーザーへのデータ公開は慎重に設計し、必要最小限のデータのみを公開するようにしてください。
4. アクセス権の相互作用
Sharing Rules は、Salesforce の多層的なセキュリティモデルの一部に過ぎません。ユーザーの最終的なアクセス権は、以下の要素が組み合わさって決定されます。
- オブジェクト権限:プロファイル (Profile) や権限セット (Permission Set) でオブジェクトへのアクセスが許可されていなければ、Sharing Rule でレコードへのアクセス権を付与しても、そのオブジェクト自体を操作することはできません。
- 項目レベルセキュリティ (Field-Level Security): 同様に、レコードへのアクセス権があっても、項目レベルで非表示に設定されていれば、その項目を閲覧・編集することはできません。
- ロール階層 (Role Hierarchy): ロール階層で上位のユーザーは、下位のユーザーがアクセスできるレコードに対して自動的にアクセス権を持ちます。Sharing Rules は、この垂直方向の共有を補完する水平方向の共有を提供します。
まとめとベストプラクティス
Sharing Rules は、Salesforce の宣言的なセキュリティモデルの中核をなす、強力で柔軟なツールです。OWD で設定された厳格なベースラインの上に、ビジネス要件に応じた例外的なアクセス権を安全かつスケーラブルに提供します。アーキテクトとしては、その機能だけでなく、背後にある原理とパフォーマンスへの影響を深く理解することが求められます。
アーキテクトのためのベストプラクティス:
- 最も制限的な OWD から始める:常に最小権限の原則に従い、OWD を可能な限り「非公開」または「公開/参照のみ」に設定し、Sharing Rules を使って必要なアクセス権を段階的に開放します。
- 宣言的アプローチを優先する:複雑な要件がない限り、Apex Managed Sharing よりも標準の Sharing Rules を優先してください。宣言的な設定は、メンテナンス性、透明性、アップグレードの安全性に優れています。
- 公開グループを戦略的に活用する:ユーザーの集合を公開グループで管理することで、Sharing Rules の数を最小限に抑え、管理を簡素化できます。役割や機能に基づいたグループ設計が鍵となります。
- 再計算のインパクトを評価する:特に LDV 環境では、新しい共有ルールを導入する前に、その影響を評価してください。データスキュー(特定のユーザーが大量のレコードを所有する状況)も再計算のパフォーマンスに影響を与えるため、所有権の分散を考慮することも重要です。
- 共有モデルを文書化する:「誰が、何を、なぜ見ることができるのか」を明確に示す設計ドキュメントを維持します。これには、OWD、ロール階層、各共有ルールの目的を含めるべきです。この文書は、将来のトラブルシューティングや機能拡張の際の貴重な資産となります。
- 全体像で考える:Sharing Rules を単独の機能としてではなく、プロファイル、権限セット、ロール階層といった他のセキュリティ機能と連携するエコシステムの一部として捉え、一貫性のある包括的なデータアクセス戦略を設計してください。
これらの原則に従うことで、Salesforce の共有機能を最大限に活用し、セキュアで、パフォーマンスが高く、ビジネスの成長に合わせてスケールできるアーキテクチャを構築することが可能になります。
コメント
コメントを投稿