列と行のレベルのセキュリティを使用して認可を管理する
このトピックでは、Azure Synapse Analytics 内の列と行のレベルのセキュリティを使用して認可を管理する方法について説明します。 まず、Azure Synapse Analytics の列レベルのセキュリティについて説明し、次に行レベルのセキュリティについて説明します。
Azure Synapse Analytics での列レベルのセキュリティ
一般に、列レベルのセキュリティによって、アプリケーションのセキュリティの設計とコーディングが簡略化されます。 これにより、機密データを保護するために列アクセスを制限することができます。 たとえば、特定のユーザー "Leo" は特定の部門にいるため、テーブルの特定の列にしかアクセスできないようにする場合などがあります。 自分が働く部門に対して指定された列にのみアクセスできるという "Leo" のロジックは、アプリケーション レベルのデータ層ではなく、データベース層に配置されるロジックです。 どの層のデータにもアクセスする必要がある場合は、別の層のデータにアクセスしようとするたびに、データベースでアクセス制限を適用する必要があります。 これを行う理由はセキュリティの信頼性と堅牢性を確保するためです。なぜなら、ここではセキュリティ システム全体における外部からのアクセスを削減するためです。 列レベルのセキュリティでは、"Leo" へのアクセス制限を適用するために列をフィルターで除外するビューの導入も不要になります。
列レベルのセキュリティを実装するには、GRANT T-SQL ステートメントを使用します。 このステートメントを使用して、SQL と Microsoft Entra ID は認証をサポートしています。
構文
列レベルのセキュリティの実装に使用する構文は、次のようになります。
GRANT <permission> [ ,...n ] ON
[ OBJECT :: ][ schema_name ]. object_name [ ( column [ ,...n ] ) ] // specifying the column access
TO <database_principal> [ ,...n ]
[ WITH GRANT OPTION ]
[ AS <database_principal> ]
<permission> ::=
SELECT
| UPDATE
<database_principal> ::=
Database_user // specifying the database user
| Database_role // specifying the database role
| Database_user_mapped_to_Windows_User
| Database_user_mapped_to_Windows_Group
では、列レベルのセキュリティを使用するのはどのような場合でしょうか。 たとえば、金融サービス会社で、顧客の社会保障番号、電話番号、またはその他の個人を特定できる情報へのアクセスが許可されるのは、アカウント マネージャーだけだとします。 アカウント マネージャーと、アカウント マネージャーのマネージャーの役割を区別することが重要です。
また、医療業界に関連するユースケースもあります。 たとえば、特定の医療機関があるとします。 この医療機関では、医師と看護師のみが医療記録にアクセスできるようにする必要があります。 請求部門には、このデータを表示するアクセス権を持たせてはなりません。 列レベルのセキュリティを使用できるかもしれません。
では、列レベルのセキュリティは行レベルのセキュリティとどう違うのでしょうか。 これについて見てみましょう。
Azure Synapse Analytics での行レベルのセキュリティ
行レベルのセキュリティ (RLS) は、データベース テーブル内の列だけでなく、実際には行を制御するために、グループ メンバーシップまたは実行コンテキストを作成するのに役立ちます。 RLS は、列レベルのセキュリティと同様に、アプリケーションのセキュリティの設計とコーディングを単に容易にし、実現するのに役立ちます。 ただし、列 (パラメーター) に重点が置かれている列レベルのセキュリティと比較すると、RLS はデータ行へのアクセスへの制限を実装するのに役立ちます。 部門にとって重要なデータの行にのみ従業員がアクセスできると仮定すると、RLS を実装する必要があります。 たとえば、その会社に関係があるデータのみに顧客のアクセスを制限する場合、RLS を実装できます。 行のアクセスに対する制限は、アプリケーション レベルのデータ層ではなく、データベース層に配置されるロジックです。 "Leo" がどの層のデータにもアクセスする必要がある場合は、別の層のデータにアクセスしようとするたびに、データベースでアクセス制限を適用する必要があります。 これを行う理由はセキュリティの信頼性と堅牢性を確保するためです。なぜなら、ここではセキュリティ システム全体における外部からのアクセスを削減するためです。
RLS を実装するには、CREATE SECURITY POLICY[!INCLUDEtsql] ステートメントを使用します。 述語はインライン テーブル値関数として作成されます。 Azure Synapse ではフィルター述語のみがサポートされていることを理解しておくことが重要です。 ブロック述語を使用する必要がある場合、現時点では Azure Synapse 内でサポートされません。
フィルター述語に関連する行レベルのセキュリティの説明
Azure Synapse 内の RLS では、ブロック述語ではなくフィルター述語という 1 種類のセキュリティ述語がサポートされています。
フィルター述語の動作は、SELECT、UPDATE、DELETE などの読み取り操作で使用可能な暗黙的な行のフィルター処理です。
テーブル内の行レベルのデータへのアクセスは、セキュリティ述語であるインライン テーブル値関数として制限されます。 このテーブル値関数は、必要なセキュリティ ポリシーによって呼び出され、適用されます。 フィルター述語の結果セットからフィルター処理された行は、アプリケーションでは認識されません。 したがって、すべての行がフィルター処理されると、null のセットが返されます。
フィルター述語を使用するとき、ベース テーブルからデータを読み込むときに適用されます。 フィルター述語は、SELECT、DELETE、UPDATE などのすべての get 操作に影響します。 フィルター処理された行を選択または削除することはできません。 フィルター処理された行を更新することはできません。 実行できる操作は、後でフィルター処理されるように行を更新することです。
ユース ケース
RLS の一部のユース ケースについては既に説明しました。 別のユース ケースとして、あるテナントのデータ行と別のテナントのデータ行の論理的な分離を適用するポリシーが作成されたマルチテナント アプリケーションを作成する場合があります。 これを効率的に実装するには、多数のテナントのデータを 1 つのテーブルに格納することを強くお勧めします。
RLS フィルター述語を見た場合、機能的には WHERE 句を追加するのと同じです。
述語はビジネス プラクティスの規定と同じくらいに洗練されたものであり、句は WHERE TenantId = 42
と同じくらいに簡単です。
RLS をより改まって見た場合、RLS では述語ベースのアクセス制御が導入されているといえます。 RLS を述語アクセス制御に使用できる理由は、これが柔軟で一元化された述語ベースの評価であるためです。 フィルター述語は、メタデータまたは必要に応じて決定するその他の条件に基づくことができます。 述語は、ユーザーがその属性に基づいて適切にデータにアクセスできるかどうかを決定する条件として使用されます。 述語ベースのアクセス制御を使用することで、ラベルベースのアクセス制御を実装できます。
アクセス許可
セキュリティ ポリシーを作成、変更、または削除する場合は、 ALTER ANY SECURITY POLICY 権限を使用する必要があります。 その理由は、セキュリティ ポリシーを作成または削除するときに、スキーマに対する ALTER 権限が必要になるためです。
さらに、追加する各述語に対して、次のようなアクセス許可が必要です。
述語として使用しているインライン テーブル値関数に関するSELECT および REFERENCES 権限。
ポリシーにバインドする対象のテーブルに対する REFERENCES 権限。
引数として使用しているターゲット テーブルのすべての列に対するREFERENCES 権限。
セキュリティ ポリシーを設定すると、これはすべてのユーザーに適用されます (データベース内の dbo ユーザーを含む)。DBO ユーザーはセキュリティ ポリシーを変更または削除できますが、これらのユーザーによるセキュリティ ポリシーの変更は監査できます。 sysadmin や db_owner などの高い特権を持つユーザーが、トラブルシューティングやデータの検証のためにすべての行を表示する必要がある特殊な状況が発生した場合でも、それを許可するためにセキュリティ ポリシーを記述する必要があります。
SCHEMABINDING = OFF
というセキュリティ ポリシーを作成した場合、ターゲット テーブルにクエリを実行するには、ユーザーは述語関数に対する SCHEMABINDING = OFF
または EXECUTE 権限を持っている必要があります。
また、述語関数内で使用される追加のテーブル、ビュー、または関数に対する権限も必要です。
SCHEMABINDING = ON
(既定) でセキュリティ ポリシーが作成された場合、ユーザーが対象テーブルに対してクエリを実行すると、これらの権限チェックは迂回されます。
ベスト プラクティス
RLS を実装する場合は、いくつかのベスト プラクティスに注意する必要があります。 RLS オブジェクト用に別個のスキーマを作成することをお勧めします。 このコンテキストの RLS オブジェクトは述語関数およびセキュリティ ポリシーになります。 なぜこれがベスト プラクティスなのでしょうか。 これにより、これらの特殊なオブジェクトに必要な権限をターゲット テーブルから分離できます。 また、マルチテナント データベースでは、さまざまなポリシーと述語関数の分離が必要になる場合があります。 ただし、これはすべての事例についての標準ではありません。
注意すべきもう 1 つのベスト プラクティスとして、 ALTER ANY SECURITY POLICY 権限は、(セキュリティ ポリシー マネージャーなどの) 高い特権を持つユーザーのみを対象としていることがあります。 セキュリティ ポリシー マネージャーには、保護しているテーブルでは SELECT 権限は必要ありません。
潜在的なランタイム エラーを回避するには、記述する述語関数で型変換を考慮する必要があります。 また、述語関数の再帰を避けるようにしてください。 この理由は、パフォーマンスの低下を回避するためです。 クエリ オプティマイザーによって直接再帰の検出が試みられますが、間接再帰の検出は保証されません。 間接再帰とは、述語関数が別の関数から呼び出されることを意味します。
また、述語関数では過剰なテーブル結合を避けることをお勧めします。 これによりパフォーマンスが最大化されます。
一般に、述語のロジックに関しては、セッション固有の SET オプションに依存するロジックを避けることをお勧めします。 実用的なアプリケーションで使用されることは非常にまれですが、ロジックが特定のセッション固有の SET オプションに依存する述語関数では、ユーザーが任意のクエリを実行できる場合に情報が漏洩する可能性があります。 たとえば、文字列を datetime に暗黙的に変換する述語関数は、現在のセッションの SET DATEFORMAT オプションに基づいてさまざまな行をフィルター処理する可能性があります。