これは、モジュール署名を使用して非常に安全な方法で簡単に実行できます。これは、次の2つの私の答えと似ていますが、ここでもDBA.StackExchangeで、これを行う例を示しています。
実行方法、クロスデータベースクエリ、モジュール署名によるストアドプロシージャのセキュリティ
クロスデータベース証明書を使用する場合のトリガーの権限
この特定の質問の違いは、ビューを処理することと、ビューに署名できないことです。したがって、ビューをマルチステートメントのテーブル値関数(TVF)に変更する必要があります。署名付きで、ビューと同じようにアクセスできます(SELECT
アクセス用)。
次のコード例は、ログイン/ユーザー「RestrictedUser」が「DatabaseA」にのみアクセスでき、「DatabaseB」からデータを取得できるという点で、質問で要求されていることを正確に実行することを示しています。これは、この1つのTVFから選択することによってのみ機能し、署名されているためです。
ビューを使用しながら、ユーザーに追加のアクセス許可を与えずに、このタイプのクロスデータベースアクセスを実現するには、クロスデータベース所有権の連鎖を有効にする必要があります。両方のデータベース間のすべてのオブジェクトに対して完全に制限がないため、安全性ははるかに低くなります(特定のオブジェクトやユーザーに制限することはできません)。モジュール署名により、この1つのTVFだけがクロスDBアクセスを許可され(ユーザーには権限がなく、TVFは許可されます)、SELECT
TVFからアクセスできないユーザーは「データベースB」にアクセスできません。
USE [master];
CREATE LOGIN [RestrictedUser] WITH PASSWORD = 'No way? Yes way!';
GO
---
USE [DatabaseA];
CREATE USER [RestrictedUser] FOR LOGIN [RestrictedUser];
GO
CREATE FUNCTION dbo.DataFromOtherDB()
RETURNS @Results TABLE ([SomeValue] INT)
AS
BEGIN
INSERT INTO @Results ([SomeValue])
SELECT [SomeValue]
FROM DatabaseB.dbo.LotsOfValues;
RETURN;
END;
GO
GRANT SELECT ON dbo.[DataFromOtherDB] TO [RestrictedUser];
GO
---
USE [DatabaseB];
CREATE TABLE dbo.[LotsOfValues]
(
[LotsOfValuesID] INT IDENTITY(1, 1) NOT NULL
CONSTRAINT [PK_LotsOfValues] PRIMARY KEY,
[SomeValue] INT
);
INSERT INTO dbo.[LotsOfValues] VALUES
(1), (10), (100), (1000);
GO
---
USE [DatabaseA];
SELECT * FROM dbo.[DataFromOtherDB]();
EXECUTE AS LOGIN = 'RestrictedUser';
SELECT * FROM dbo.[DataFromOtherDB]();
/*
Msg 916, Level 14, State 1, Line XXXXX
The server principal "RestrictedUser" is not able to access
the database "DatabaseB" under the current security context.
*/
REVERT;
上記のすべての手順で現在の状況が再現されます。ユーザーにはDatabaseAへのアクセス権があり、DatabaseAのオブジェクトと対話する権限がありますが、DatabaseAのオブジェクトがDatabaseBの何かにアクセスしているため、ユーザーがアクセスできないため、エラーが発生します。
以下の手順では、モジュールの歌唱を設定します。次のことを行います。
- DatabaseAに証明書を作成します
- 証明書でTVFに署名する
- 証明書(秘密キーなし)をデータベースBにコピーします。
- 証明書からDatabaseBにユーザーを作成します
SELECT
証明書ベースのユーザーにDatabaseBのテーブルへのアクセス許可を付与します
モジュール署名設定:
CREATE CERTIFICATE [AccessOtherDB]
ENCRYPTION BY PASSWORD = 'SomePassword'
WITH SUBJECT = 'Used for accessing other DB',
EXPIRY_DATE = '2099-12-31';
ADD SIGNATURE
TO dbo.[DataFromOtherDB]
BY CERTIFICATE [AccessOtherDB]
WITH PASSWORD = 'SomePassword';
---
DECLARE @CertificatePublicKey NVARCHAR(MAX) =
CONVERT(NVARCHAR(MAX), CERTENCODED(CERT_ID(N'AccessOtherDB')), 1);
SELECT @CertificatePublicKey AS [Cert / PublicKey]; -- debug
EXEC (N'USE [DatabaseB];
CREATE CERTIFICATE [AccessOtherDB] FROM BINARY = ' + @CertificatePublicKey + N';');
---
EXEC (N'
USE [DatabaseB];
CREATE USER [AccessOtherDbUser] FROM CERTIFICATE [AccessOtherDB];
GRANT SELECT ON dbo.[LotsOfValues] TO [AccessOtherDbUser];
');
---
EXECUTE AS LOGIN = 'RestrictedUser';
SELECT * FROM dbo.[DataFromOtherDB]();
-- Success!!
SELECT * FROM [DatabaseB].[dbo].[LotsOfValues];
/*
Msg 916, Level 14, State 1, Line XXXXX
The server principal "RestrictedUser" is not able to access
the database "DatabaseB" under the current security context.
*/
REVERT;
何らかの理由でアクセスがビューを経由する必要がある場合は、上記のTVFから選択するビューを作成するだけです。そして、そのような状況では、以下に示すように、TVF SELECT
へのアクセスを許可する必要はなく、ビューへのアクセスのみを許可する必要があります。
GO
CREATE VIEW dbo.[DataFromTVF]
AS
SELECT [SomeValue]
FROM dbo.DataFromOtherDB();
GO
-- Remove direct access to the TVF as it is no longer needed:
REVOKE SELECT ON dbo.[DataFromOtherDB] FROM [RestrictedUser];
GRANT SELECT ON dbo.[DataFromTVF] TO [RestrictedUser];
そして今それをテストする:
EXECUTE AS LOGIN = 'RestrictedUser';
SELECT * FROM dbo.[DataFromOtherDB]();
/*
Msg 229, Level 14, State 5, Line XXXXX
The SELECT permission was denied on the object 'DataFromOtherDB',
database 'DatabaseA', schema 'dbo'.
*/
SELECT * FROM [OwnershipChaining].[dbo].[LotsOfValues];
/*
Msg 916, Level 14, State 1, Line XXXXX
The server principal "RestrictedUser" is not able to access
the database "DatabaseB" under the current security context.
*/
SELECT * FROM dbo.[DataFromTVF];
-- Success!!
REVERT;
モジュール署名の詳細については、https://ModuleSigning.Info/をご覧ください。