Salesforce Sharing Rules の理解:データアクセス制御のためのコンサルタントガイド

概要とビジネスシーン

Salesforce Sharing Rules(共有ルール)は、組織の共有設定(OWD: Organization-Wide Defaults)で設定されたデフォルトのアクセス権限を補完し、特定のレコードへのアクセスを柔軟に拡張するための強力なメカニズムです。これにより、ビジネス要件に基づいたきめ細やかなデータセキュリティを実現し、情報共有とコラボレーションを促進しながら、不要な情報開示を防ぐことができます。

実際のビジネスシーン

シーンA - 金融業界:あるプライベートバンキング部門では、顧客の機密性の高い投資ポートフォリオ情報が、担当のプライベートバンカーとその直属のマネージャー、そして特定のコンプライアンスチームのみに共有される必要があります。OWDで顧客アカウントがPrivateに設定されているため、共有ルールを使用して、各プライベートバンカーが担当する顧客レコードを、そのバンカーとマネージャー、そしてコンプライアンス公開グループに「Read/Write」アクセスで共有します。

  • ビジネス課題:機密性の高い顧客情報への不適切なアクセスを防ぎつつ、必要な関係者間の連携を円滑にすること。
  • ソリューション:OWDをPrivateに設定し、ロールに基づく共有ルールと、コンプライアンスチーム用の公開グループに基づく共有ルールを組み合わせる。
  • 定量的効果:情報漏洩リスクを50%低減し、コンプライアンス監査の指摘事項を20%削減。

シーンB - 製造業:大規模な製造プロジェクトでは、複数の部署(設計、生産、品質管理、営業)が関与します。特定のプロジェクトに関連する商談(Opportunity)やケース(Case)レコードは、プロジェクトマネージャーを含む特定の公開グループのメンバー全員が参照・更新できる必要があります。OWDがPrivateまたはPublic Read Onlyの場合、各プロジェクトに紐づくレコードを、プロジェクト公開グループに対して「Read/Write」で共有する共有ルールを設定します。

  • ビジネス課題:プロジェクト情報のサイロ化を防ぎ、部門横断的なチーム間の情報共有とコラボレーションを促進すること。
  • ソリューション:オブジェクトをPublic Read Onlyに設定し、公開グループとレコード所有者に基づく共有ルールを設定。
  • 定量的効果:プロジェクトチーム内の情報検索時間を30%短縮し、プロジェクトの遅延発生率を15%改善。

シーンC - 医療業界:特定の専門外来では、患者の治療計画や履歴が、担当医と看護師のチーム、そして関連する薬剤師チームのみにアクセス可能である必要があります。OWDで患者レコードがPrivateに設定されている場合、患者を担当する医師のロールと、関連する看護師・薬剤師の公開グループに基づいた共有ルールを作成し、患者レコードへの「Read/Write」アクセスを許可します。

  • ビジネス課題:患者データのプライバシー保護と同時に、治療チーム内での迅速かつ正確な情報共有のバランスを取ること。
  • ソリューション:OWDをPrivateに設定し、ロールに基づく共有ルールと公開グループに基づく共有ルールを組み合わせる。
  • 定量的効果:HIPAAなどの規制遵守違反リスクを大幅に低減し、治療チームの連携による患者ケアの質を向上。

技術原理とアーキテクチャ

Salesforceのデータアクセスモデルは、組織の共有設定 (OWD)、ロール階層 (Role Hierarchy)、Sharing Rules(共有ルール)、Manual Sharing(手動共有)、そしてApex Managed Sharing(Apexによる共有)という複数のレイヤーで構成されます。Sharing Rulesは、OWDによって設定された最も制限的なアクセスレベル(PrivateまたはPublic Read Only)を緩めるために使用されます。つまり、「共有ルールは、ユーザーに付与されたアクセス権をさらに制限することはできないが、アクセス権を拡張することはできる」という原則に基づきます。

基礎的な動作メカニズム

Sharing Rulesは、レコード所有者、ロール、ロール&サブordinates(下位ロールのユーザーを含む)、公開グループ、特定のユーザーのいずれかに基づいて、他のユーザーやグループに特定のオブジェクトのレコードへの追加アクセスを付与します。Salesforceの内部では、これらのルールが評価され、共有オブジェクト(例: AccountShare, OpportunityShare, CustomObject__Share)にレコードが作成されることでアクセス権が付与されます。このプロセスはバックグラウンドで自動的に行われます。

主要コンポーネントと依存関係

  • OWD (Organization-Wide Defaults):データアクセスのベースラインを設定します。共有ルールはOWDがPrivateまたはPublic Read Onlyの場合にのみアクセスを拡張できます。
  • Role Hierarchy (ロール階層):上位のロールを持つユーザーは、下位のロールを持つユーザーが所有するレコードに対して、自動的にアクセス権(通常はRead/Edit)を持ちます。共有ルールはロール階層の水平方向のアクセスを補完します。
  • Public Groups (公開グループ):ユーザー、ロール、ロール&サブordinates、その他の公開グループをまとめた集合です。共有ルールは公開グループをターゲットにすることで、一貫したアクセス権を効率的に付与できます。
  • Sharing Objects (__Share):各標準オブジェクトおよび共有が有効なカスタムオブジェクトには、関連する共有オブジェクトが存在します(例: Accountに対してAccountShare)。Salesforceの共有モデルの根幹であり、共有ルールによって間接的に、またはApex Managed Sharingによって直接、これらのオブジェクトのレコードが作成されます。

データフロー

ステップ 説明 関連コンポーネント
1. デフォルトアクセス ユーザーのレコードへのアクセス権をOWDで評価します。 OWD (Organization-Wide Defaults)
2. 所有者アクセス レコード所有者はそのレコードに対してフルアクセスを持ちます。 レコード所有者
3. ロール階層 ユーザーがロール階層の上位にいる場合、下位ロールのレコードへのアクセス権が付与されます。 Role Hierarchy (ロール階層)
4. 共有ルール 定義された共有ルールに基づいて、追加のアクセス権が評価・付与されます。 Sharing Rules (共有ルール)
5. 手動共有 必要に応じて、個別のレコードに対して手動でアクセス権が付与されます。 Manual Sharing (手動共有)
6. Apex共有 Apex Managed Sharingによって付与されたアクセス権が評価されます。 Apex Managed Sharing (Apexによる共有)

ソリューション比較と選定

Salesforceのレコードレベルセキュリティは多様なツールを提供しており、要件に応じて最適なものを選択することが重要です。Sharing Rulesは、その中でも特に宣言的に、広範囲なアクセス制御を効率的に管理するための中心的な役割を担います。

ソリューション 適用シーン パフォーマンス Governor Limits 複雑度
Sharing Rules 特定のロールや公開グループに対して、ルールベースで一貫したアクセス権を付与する場合(OWDがPrivate/Public Read Onlyの場合)。 システムで最適化されており、比較的良好。ただし、多数の複雑なルールは再計算に影響。 直接的なApexガバナ制限は少ない。オブジェクトあたり最大500個、組織全体で最大2000個の共有ルール。 設定UIから簡単に定義可能。宣言的。
Manual Sharing (手動共有) 個別のレコードに対して、特定のユーザーに一時的または例外的なアクセス権を付与する場合。 レコード単位での処理のためオーバーヘッドは低い。ただし、大量になると管理が困難。 レコードの共有数に直接的な制限はないが、所有権変更などで共有再計算が発生。 レコード詳細ページから手動で設定。
Apex Managed Sharing (Apexによる共有) 複雑なビジネスロジックに基づいて動的にアクセス権を付与する必要がある場合。標準機能では実現できない要件。 カスタムロジックに依存。適切に実装すれば高いパフォーマンス。不適切だとパフォーマンス問題を引き起こす可能性。 Apexガバナ制限に従う(DML操作、SOQLクエリなど)。__Shareオブジェクトの挿入/更新/削除も制限される。 Apexコーディングが必要。高度な開発スキルが要求される。

sharing rules を使用すべき場合

  • ✅ 組織全体の共有設定(OWD)でPrivateまたはPublic Read Onlyに設定されているオブジェクトがあり、特定のユーザーセットに対してアクセスを拡張したい場合。
  • ✅ 特定のロール、ロール&サブordinates、公開グループ、または部門全体に一貫したアクセス権を付与する必要がある場合。
  • ✅ 大量のレコードに対してルールベースで共有を適用したい場合(手動共有では管理が困難)。
  • ✅ Apex開発のコストと複雑さを避け、宣言的な設定で要件を満たしたい場合。
  • ❌ レコードの特定フィールドの値に基づいて動的に共有ロジックを適用する必要がある場合(Apex Managed Sharingが適しています)。
  • ❌ 個々のレコードに対して、アドホックな一時的な共有を適用する場合(手動共有が適しています)。

実装例

Sharing Rules自体はSalesforceの設定UIを通じて宣言的に定義されるため、直接的なApexコードの実装例は存在しません。しかし、Salesforceの共有モデルをより深く理解するために、Sharing Rulesが舞台裏で管理している共有レコード(例:AccountShare)をApexで直接操作する、いわゆるApex Managed Sharingの概念の一部をご紹介します。これはSharing Rulesとは異なりますが、共有の仕組みを理解する上で非常に重要です。

以下のコード例では、特定の取引先(Account)レコードを、特定のユーザーまたは公開グループと共有する方法を示します。これは、Sharing Rulesの背後にある「共有」という概念をApexで明示的に制御するものです。

public class AccountSharingUtility {

    /**
     * @description 特定の取引先を特定のユーザーまたは公開グループと共有します。
     * @param accountId 共有する取引先のID
     * @param shareWithId 共有相手のユーザーまたは公開グループのID
     * @param accessLevel 付与するアクセスレベル (例: 'Read', 'Edit')
     * @return 成功した場合はtrue、それ以外はfalse
     */
    public static Boolean shareAccount(Id accountId, Id shareWithId, String accessLevel) {
        // 共有レコードを作成する前に、無効なIDをチェック
        if (accountId == null || shareWithId == null || String.isBlank(accessLevel)) {
            System.debug('Error: Invalid input parameters for sharing.');
            return false;
        }

        // 共有オブジェクトのインスタンスを作成
        AccountShare newShare = new AccountShare();
        newShare.AccountId = accountId;             // 共有対象の取引先ID
        newShare.UserOrGroupId = shareWithId;       // 共有相手のユーザーまたは公開グループID
        newShare.AccessLevel = accessLevel;         // アクセスレベル ('Read', 'Edit')
        // 行レベルのアクセス権の理由(Apex Managed Sharingでは 'Manual' ではない点に注意)
        // Apex Managed Sharingでは 'Apex' かカスタム理由(CustomObject__Share.RowCause)を使用
        newShare.RowCause = Schema.AccountShare.RowCause.Manual; // マニュアル共有として設定 (※Apex Managed Sharingでは通常 'Apex' を使用すべきだが、ここでは標準フィールドのデモのためManual)

        try {
            Database.SaveResult sr = Database.insert(newShare, false); // 部分成功を許可しない
            if (sr.isSuccess()) {
                System.debug('Account ' + accountId + ' successfully shared with ' + shareWithId);
                return true;
            } else {
                for(Database.Error err : sr.getErrors()) {
                    System.debug('Error sharing Account: ' + err.getMessage());
                }
                return false;
            }
        } catch (DmlException e) {
            System.debug('DML Exception during account sharing: ' + e.getMessage());
            return false;
        }
    }

    /**
     * @description 特定の取引先の共有レコードを削除します。
     * @param accountId 共有解除する取引先のID
     * @param shareWithId 共有解除相手のユーザーまたは公開グループのID
     * @return 成功した場合はtrue、それ以外はfalse
     */
    public static Boolean unshareAccount(Id accountId, Id shareWithId) {
        List<AccountShare> sharesToDelete = [
            SELECT Id
            FROM AccountShare
            WHERE AccountId = :accountId
            AND UserOrGroupId = :shareWithId
            AND RowCause = :Schema.AccountShare.RowCause.Manual // 削除する共有のRowCauseを指定
        ];

        if (sharesToDelete.isEmpty()) {
            System.debug('No matching shares found to delete.');
            return false;
        }

        try {
            Database.DeleteResult[] drs = Database.delete(sharesToDelete, false);
            Boolean allSuccess = true;
            for (Database.DeleteResult dr : drs) {
                if (!dr.isSuccess()) {
                    allSuccess = false;
                    for (Database.Error err : dr.getErrors()) {
                        System.debug('Error deleting share: ' + err.getMessage());
                    }
                }
            }
            if (allSuccess) {
                System.debug('Shares for Account ' + accountId + ' with ' + shareWithId + ' successfully deleted.');
            }
            return allSuccess;
        } catch (DmlException e) {
            System.debug('DML Exception during share deletion: ' + e.getMessage());
            return false;
        }
    }
}

// 実行例 (Developer Console の Execute Anonymous から実行)
// Id targetAccountId = '001XXXXXXXXXXXXXXXX'; // 実際の取引先IDに置き換える
// Id targetUserId = '005XXXXXXXXXXXXXXXX';    // 実際のユーザーIDまたは公開グループIDに置き換える
// Id targetGroupId = '00GX000000XXXXX';    // 実際の公開グループIDに置き換える

// AccountSharingUtility.shareAccount(targetAccountId, targetUserId, 'Edit');
// AccountSharingUtility.shareAccount(targetAccountId, targetGroupId, 'Read');
// AccountSharingUtility.unshareAccount(targetAccountId, targetUserId);

このコードは、AccountShareオブジェクトを直接操作することで、Salesforceの共有モデルの基本である共有レコードがどのように作成・削除されるかを示しています。Sharing Rulesは、この共有レコードの作成と管理を自動化する宣言的な方法と考えることができます。


注意事項とベストプラクティス

Sharing Rulesの実装と管理においては、システム全体のパフォーマンスとセキュリティを最適化するために、いくつかの重要な考慮事項とベストプラクティスがあります。

権限要件

  • プロファイル/権限セット:共有設定を管理するには、「Manage Sharing」権限が必要です。これは通常、システム管理者のプロファイルに含まれています。また、「View Setup and Configuration」権限も必要です。
  • オブジェクト権限:共有ルールを適用するオブジェクトに対する適切なオブジェクト権限(例: 読み取り、編集)が必要です。共有ルールはあくまでレコードレベルのアクセスを制御し、オブジェクトレベルのアクセス(プロファイル/権限セットで付与)を上書きするものではありません。

Governor Limits

  • 共有ルールの総数:Salesforce組織には、オブジェクトごとに最大500個、組織全体で最大2,000個の共有ルールという制限があります(2025年時点の一般的な認識。⚠️ 公式ドキュメントの確認が必要)。この制限を超えると、新しいルールを作成できません。
  • 共有の再計算:組織の共有設定(OWD)の変更、ロール階層の変更、または大量の共有ルール変更は、共有の再計算を引き起こします。これは大規模な組織ではかなりの時間を要し、システムパフォーマンスに影響を与える可能性があります。
  • 共有テーブルのサイズ:大量の共有レコード(__Shareオブジェクトのレコード)は、データベースのパフォーマンスに影響を与える可能性があります。

エラー処理

Sharing Rulesの設定自体には、設定時にUIレベルでの検証がありますが、実行時のエラー処理メカニズムは直接存在しません。意図しないアクセスや設定ミスを防ぐためには、以下の点に注意が必要です。

  • ルールの競合:複数の共有ルールが同じユーザーまたはグループに異なるアクセスレベルを付与しようとする場合、最も寛容なアクセスレベルが適用されます。
  • テストと検証:共有ルールをデプロイする前に、サンドボックス環境で徹底的なテストを行い、想定通りのアクセスレベルが付与されていることを確認することが不可欠です。

パフォーマンス最適化

  • OWDの厳格化:可能な限りOWDを最も制限的な設定(PrivateまたはPublic Read Only)にし、必要な場合にのみSharing Rulesでアクセスを拡張します。これにより、共有計算の負荷を軽減できます。
  • 公開グループの活用:個別のユーザーではなく、公開グループを使用して共有ルールを設定します。これにより、ルールの数を減らし、管理を簡素化できます。ユーザーの追加・削除は公開グループを通じて行われ、共有ルール自体を変更する必要がなくなります。
  • 不要なルールの削除:使用されていない、または冗長な共有ルールは定期的に見直し、削除します。
  • ロール階層の最適化:ロール階層を簡素化し、深い階層や複雑な構造を避けることで、共有の再計算時間を短縮できます。
  • 遅延共有計算 (Deferred Sharing Calculation):大規模なOWD変更やロール階層変更を行う際は、Salesforceサポートに連絡して遅延共有計算を有効にすることを検討します。これにより、営業時間外に共有の再計算を行うことができます。

よくある質問 FAQ

Q1:Sharing RulesとRole Hierarchy (ロール階層) の違いは何ですか?

A1:Role Hierarchyは、組織の上位ロールのユーザーが下位ロールのユーザーが所有するレコードにアクセスできるようにする、垂直方向のアクセス拡張メカニズムです。一方、Sharing Rulesは、同じロール階層内のユーザーや異なるブランチのユーザーに対して、水平方向または任意の方向にアクセスを拡張するために使用されます。

Q2:Sharing Rulesが意図した通りに機能しない場合、どのようにデバッグしますか?

A2:まず、共有ルールの設定自体を再確認し、条件と共有先が正しいかを確認します。次に、「Sharing Settings」ページで「Recalculate」ボタンをクリックし、共有設定を再評価させることができます。また、特定のレコードの「Sharing」ボタン(手動共有が有効な場合)をクリックすると、そのレコードへのアクセス権を持つユーザーと、そのアクセスがどの共有メカニズム(OWD、ロール、共有ルールなど)によって付与されたかを確認できます。

Q3:Sharing Rulesのパフォーマンスを監視するにはどうすればよいですか?

A3:Salesforceは共有ルールの直接的なパフォーマンス監視ツールを提供していませんが、共有ルールの変更履歴は「Setup Audit Trail」で確認できます。大規模なOWDやロール階層の変更が行われた後、共有の再計算に異常に時間がかかっている場合は、Salesforceサポートに連絡して内部の共有再計算ジョブの状態を確認してもらうことができます。パフォーマンス問題が疑われる場合は、簡素化されたロール階層や公開グループの効率的な使用などのベストプラクティスを再検討してください。


まとめと参考資料

Salesforce Sharing Rulesは、OWDとロール階層を補完する形で、レコードレベルのアクセス権を柔軟に拡張するための不可欠なツールです。コンサルタントとして、ビジネス要件を正確に理解し、OWD、ロール階層、公開グループ、そして共有ルールを組み合わせて最適なデータセキュリティモデルを設計することが求められます。効率的な共有ルールの設計は、システムパフォーマンスを維持しつつ、ユーザーの生産性を最大化するために不可欠です。

  • 宣言的で設定ベースの強力なアクセス制御メカニズム。
  • OWDがPrivateまたはPublic Read Onlyの場合にアクセスを拡張する。
  • ロール、ロール&サブordinates、公開グループ、ユーザーに基づいて共有。
  • Governor Limitsとパフォーマンス最適化のベストプラクティスを常に考慮する。
  • 複雑な要件にはApex Managed Sharingも検討する。

公式リソース

コメント