行レベル セキュリティ ポリシー
お客様は、グループ メンバーシップや実行コンテキストを使用して、データベース テーブル内の行へのアクセスをコントロールすることができます。
行レベルセキュリティ (RLS) は、セキュリティの設計やコーディングを簡略化します。 これにより、アプリケーションのデータ行へのアクセスに制限をかけることができます。 たとえば、ユーザー自身が所属している部署に関する行にのみアクセスできるよう制限したり、お客様のアクセスを、ご自身が所属している企業に関連するデータに制限することなどができます。
アクセス制限のロジックは、別のアプリケーション層のデータから離れてではなく、データベース層にあります。 任意の層からデータへのアクセスが試行されるたびに、データベース システムにはアクセス制限が適用されます。 これによりセキュリティ システムの外部からのアクセスが減り、そのシステムの信頼性と堅牢性が向上します。
RLS を使用すると、テーブルの特定の部分にのみ、他のアプリケーションやユーザーへのアクセスを提供できます。 たとえば、次の操作を行います。
- 条件を満たす行にのみアクセス権を付与する
- 一部の列のデータを匿名化
- 上記すべて
Note
テーブルで RLS ポリシーが有効になっている場合、アクセスは、テーブルで定義されている RLS クエリによって完全に置き換えられます。 アクセス制限は、データベース管理者や RLS 作成者など、すべてのユーザーに適用されます。 RLS クエリには、アクセス権を付与するすべての種類のユーザーの定義が明示的に含まれている必要があります。
詳細については、「 行レベルのセキュリティ ポリシーを管理するための管理コマンドを参照してください。
ヒント
これらの関数は、多くの場合、row_level_security クエリに役立ちます。
制限事項
- 行レベルセキュリティ ポリシーを構成できるテーブルの数に制限はありません。
- 行レベルのセキュリティ ポリシーは、 External Tables で構成できません。
- 次の状況では、テーブルで RLS ポリシーを有効にすることはできません。
- 更新ポリシーがマネージド ID で構成されていないときに、 update ポリシー クエリによって参照される場合。
- 連続するエクスポートによって参照される場合偽装以外の認証方法を使用します。
- 表示アクセス ポリシーが構成されている場合テーブルに対して構成されます。
例
Sales テーブルへのアクセス制限
Sales
という名前のテーブルの各行には販売に関する詳細が含まれています。 列の 1 つは、販売員の名前を含んでいます。 販売員に Sales
のすべてのレコードへのアクセス権を付与するのではなく、このテーブルの行レベルセキュリティ ポリシーを有効にして、販売員が現在のユーザーであるレコードのみを返すようにします。
Sales | where SalesPersonAadUser == current_principal()
また、メール アドレスを追加することもできます。
Sales | where SalesPersonAadUser == current_principal() | extend EmailAddress = "****"
すべての営業担当者に特定の国/地域のすべての売上を表示する場合は、次のようなクエリを定義できます。
let UserToCountryMapping = datatable(User:string, Country:string)
[
"john@domain.com", "USA",
"anna@domain.com", "France"
];
Sales
| where Country in ((UserToCountryMapping | where User == current_principal_details()["UserPrincipalName"] | project Country))
マネージャーが含まれているグループがある場合は、すべての行へのアクセス権を付与することができます。 行レベルのセキュリティ ポリシーのクエリを次に示します。
let IsManager = current_principal_is_member_of('aadgroup=sales_managers@domain.com');
let AllData = Sales | where IsManager;
let PartialData = Sales | where not(IsManager) and (SalesPersonAadUser == current_principal()) | extend EmailAddress = "****";
union AllData, PartialData
異なる Microsoft Entra グループのメンバーに異なるデータを公開する
複数の Microsoft Entra グループがあり、各グループのメンバーに異なるデータのサブセットを表示する場合は、RLS クエリにこの構造を使用します。
Customers
| where (current_principal_is_member_of('aadgroup=group1@domain.com') and <filtering specific for group1>) or
(current_principal_is_member_of('aadgroup=group2@domain.com') and <filtering specific for group2>) or
(current_principal_is_member_of('aadgroup=group3@domain.com') and <filtering specific for group3>)
複数のテーブルに同じ RLS 関数を適用する
まず、テーブル名を文字列パラメーターとして受け取り、table()
演算子を使用してテーブルを参照する関数を定義します。
次に例を示します。
.create-or-alter function RLSForCustomersTables(TableName: string) {
table(TableName)
| ...
}
次に、次のようにして、複数のテーブルで RLS を構成します。
.alter table Customers1 policy row_level_security enable "RLSForCustomersTables('Customers1')"
.alter table Customers2 policy row_level_security enable "RLSForCustomersTables('Customers2')"
.alter table Customers3 policy row_level_security enable "RLSForCustomersTables('Customers3')"
未承認のアクセス時にエラーを生成する
認証されていないテーブル ユーザーが空のテーブルを返す代わりにエラーを受け取る場合は、 assert()
関数を使用します。 次の例は、RLS 関数でこのエラーを生成する方法を示しています。
.create-or-alter function RLSForCustomersTables() {
MyTable
| where assert(current_principal_is_member_of('aadgroup=mygroup@mycompany.com') == true, "You don't have access")
}
この方法を他の例と組み合わせることができます。 たとえば、異なる Microsoft Entra グループのユーザーに異なる結果を表示し、他のすべてのユーザーにエラーを生成できます。
フォロワー データベースに対する権限のコントロール
運用データベースで構成する RLS ポリシーも、フォロワーデータベースで有効になります。 運用データベースとフォロワー データベースで異なる RLS ポリシーを構成することはできません。 ただし、RLS クエリで current_cluster_endpoint()
関数を使用すれば、フォロワーテーブルで異なる RLS クエリを使用するのと同じ効果を得ることができます。
次に例を示します。
.create-or-alter function RLSForCustomersTables() {
let IsProductionCluster = current_cluster_endpoint() == "mycluster.eastus.kusto.windows.net";
let DataForProductionCluster = TempTable | where IsProductionCluster;
let DataForFollowerClusters = TempTable | where not(IsProductionCluster) | extend EmailAddress = "****";
union DataForProductionCluster, DataForFollowerClusters
}
Note
上記の RLS 関数は、リーダー クラスターに対するクエリにパフォーマンスに影響を与えることはありません。 フォロワー クラスターでのクエリのパフォーマンスへの影響は、 DataForFollowerClusters
の複雑さによってのみ影響を受けます。
ショートカット データベースのアクセス許可を制御する
運用データベースで構成する RLS ポリシーは、ショートカット データベースでも有効になります。 運用データベースとショートカット データベースで異なる RLS ポリシーを構成することはできません。 ただし、RLS クエリで current_cluster_endpoint()
関数を使用すると、ショートカット テーブルに異なる RLS クエリを使用する場合と同じ効果を得ることができます。
次に例を示します。
.create-or-alter function RLSForCustomersTables() {
let IsProductionCluster = current_cluster_endpoint() == "mycluster.eastus.kusto.windows.net";
let DataForProductionCluster = TempTable | where IsProductionCluster;
let DataForFollowerClusters = TempTable | where not(IsProductionCluster) | extend EmailAddress = "****";
union DataForProductionCluster, DataForFollowerClusters
}
Note
上記の RLS 関数は、ソース データベースに対するクエリにパフォーマンスに影響を与えるものではありません。 ショートカット データベースに対するクエリのパフォーマンスへの影響は、 DataForFollowerClusters
の複雑さによってのみ影響を受けます。
その他のユースケース
- たとえば、コール センターのサポート担当者は、社会保障番号やクレジット カード番号などの数桁から顧客を識別することがあります。 この番号はサポート担当者に完全に公開されるべきではありません。 RLS ポリシーをテーブルに適用すると、すべてのクエリの結果セットに含まれる社会保障番号の最後の 4 桁以外のすべての数字をマスクすることができます。
- 個人を特定できる情報 (PII) をマスクする RLS ポリシーを設定します。これにより、開発者は、コンプライアンス規制に違反することなく、運用環境にクエリを実行してトラブルシューティングを行うことができます。
- 病院では、看護師が自分の患者のデータ行のみを見ることができるようなセキュリティ ポリシーを作成できます。
- 銀行では、従業員のビジネス部門や会社における役割に基づき、財務データの行へのアクセスを制限するポリシーを作成できます。
- マルチテナント アプリケーションでは、多くのテナントのデータを 1 つの tableset (効率的) に格納できます。 RLS ポリシーを使用して、他のすべてのテナントの行から各テナントのデータ行を論理的に分離することにより、各テナントはそのデータ行のみを参照できます。
クエリにおけるパフォーマンスの影響
テーブルで RLS ポリシーが有効になっている場合、そのテーブルにアクセスするクエリのパフォーマンスに影響が生じる可能性があります。 テーブルへのアクセスは、そのテーブルで定義されている RLS クエリに置き換えられます。 RLS クエリのパフォーマンスへの影響は、通常、次の 2 つの部分から構成されます。
- Microsoft Entra ID のメンバーシップ チェック: チェックは効率的です。 クエリのパフォーマンスに大きな影響を与えることなく、数十または数百のグループのメンバーシップを確認できます。
- データに適用されるフィルター、結合、その他の操作: 影響は、クエリの複雑さに依存します。
次に例を示します。
let IsRestrictedUser = current_principal_is_member_of('aadgroup=some_group@domain.com');
let AllData = MyTable | where not(IsRestrictedUser);
let PartialData = MyTable | where IsRestrictedUser and (...);
union AllData, PartialData
ユーザーが some_group@domain.comの一部でない場合、 IsRestrictedUser
は false
評価されます。 評価されるクエリは次のようになります。
let AllData = MyTable; // the condition evaluates to `true`, so the filter is dropped
let PartialData = <empty table>; // the condition evaluates to `false`, so the whole expression is replaced with an empty table
union AllData, PartialData // this will just return AllData, as PartialData is empty
同様に、IsRestrictedUser
が true
に評価される場合は、PartialData
のクエリのみが評価されます。
RLS が使用されたときのクエリ パフォーマンスの向上
- フィルターが高カーディナリティの列 (DeviceID など) に適用されている場合は、パーティション分割ポリシーまたは行順序ポリシーの使用を検討してください
- フィルターが低中のカーディナリティの列に適用されている場合は、行順序ポリシーを使用することを検討してください
取り込みにおけるパフォーマンスへの影響
取り込みにおけるパフォーマンスへの影響はありません。