以下に示すクエリがあります。
select count(*) as Count, datepart(yyyy, [LogDate]) as [Year]
from ViewAssociate..Auth_Log
where ActionCode = 12
group by datepart(yyyy, [LogDate])
order by [Year]
このクエリは、ReadAssociateデータベースに基づくストアドプロシージャの一部です。 ViewAssociate dbからデータを取得しようとしています。ストアドプロシージャを実行しようとしているユーザーはViewAssociateデータベースにアクセスできないため、クエリがエラーをスローします。
私の質問は、クエリを何らかの方法で変更し、実行するユーザー名のパスワードを指定して、ViewAssociate DBからデータを取得できるかどうかです。誰かがExecute As
を提案しましたが、うまくいかないようです。
execute as login = 'viewassociate'
次のエラーが表示されます:
プリンシパル「viewassociate」が存在しないか、このタイプのプリンシパルが偽装できないか、または権限がないため、サーバープリンシパルとして実行できません。
そのviewassociateは、ViewAssociateデータベースのdb_owner
であるSQLログインです。
接続しようとしているデータベースが別のインスタンスにある場合は、データを取得するために使用できるリンクサーバーを設定することをお勧めします。これにより、接続先のインスタンスに存在する認証情報を明示的に使用できます。また、4部構成の名前を使用してテーブルを参照するように調整するだけでよいため、クエリを比較的簡単に保つことができます。
-- create a linked server
USE [master]
GO
EXEC master.dbo.sp_addlinkedserver
@server = '.\INSTANCE_NAME',
@srvproduct=N'SQL Server' ;
GO
-- add a login to the linked server
EXEC master.dbo.sp_addlinkedsrvlogin
@rmtsrvname = '.\INSTANCE_NAME',
@locallogin = NULL,
@useself = N'False',
@rmtuser = 'user_name_from_other_instance',
@rmtpassword = 'password_for_remote_user';
GO
-- now you can query the server
SELECT *
FROM [.\INSTANCE_NAME].master.sys.databases;
GO
これらのストアドプロシージャで使用できるオプションは他にもあり、SQL Server Management Studioを使用して同じアクションを実行することもできます。以下のドキュメントへのリンクをいくつか含めました。
これは、デフォルトでは、セキュリティのためにデータベースが他のDBから分離されているという単純な問題です。 SQL Server 2005より前のバージョンでは、データベース間の所有権の連鎖機能を有効にすることでこの問題を解決できました。ただし、そのオプションは、だれがそれを利用できるかを調整することができないため、かなり広く開かれています。 SQL Server 2005以降、 Module Signing が導入され、この問題を解決するためのきめ細かなセキュリティメカニズムを提供します。
ここにいくつかの例(DBA.SE)があり、これを行う方法をすでに示しています。
これにはトリガーが含まれるため、以下に示すように、この質問のために簡略化しました。
[〜#〜]クリーンアップ[〜#〜]
USE [master];
GO
IF EXISTS (SELECT 1 FROM [sys].[databases] WHERE [name] = N'DatabaseA')
BEGIN
PRINT 'Dropping [DatabaseA] DB...';
ALTER DATABASE [DatabaseA] SET OFFLINE WITH ROLLBACK IMMEDIATE;
ALTER DATABASE [DatabaseA] SET ONLINE;
DROP DATABASE [DatabaseA];
END;
IF EXISTS (SELECT 1 FROM [sys].[databases] WHERE [name] = N'DatabaseB')
BEGIN
PRINT 'Dropping [DatabaseB] DB...';
ALTER DATABASE [DatabaseB] SET OFFLINE WITH ROLLBACK IMMEDIATE;
ALTER DATABASE [DatabaseB] SET ONLINE;
DROP DATABASE [DatabaseB];
END;
IF (SUSER_ID(N'JohnnyLunchbucket') IS NOT NULL)
BEGIN
PRINT 'Dropping [JohnnyLunchbucket] Login...';
DROP LOGIN [JohnnyLunchbucket];
END;
[〜#〜]セットアップ[〜#〜]
USE [master];
EXECUTE AS LOGIN = N'sa';
PRINT 'Creating databases...';
CREATE DATABASE [DatabaseA] COLLATE Latin1_General_100_CI_AS_SC;
CREATE DATABASE [DatabaseB] COLLATE Latin1_General_100_CI_AS_SC;
REVERT;
GO
-- Default for both options should be OFF, but just to be sure:
ALTER DATABASE [DatabaseA] SET DB_CHAINING OFF, TRUSTWORTHY OFF, RECOVERY SIMPLE;
ALTER DATABASE [DatabaseB] SET DB_CHAINING OFF, TRUSTWORTHY OFF, RECOVERY SIMPLE;
GO
CREATE LOGIN [JohnnyLunchbucket] WITH PASSWORD = 'OhSoSecure;)';
USE [DatabaseA];
CREATE USER [JohnnyLunchbucket] FOR LOGIN [JohnnyLunchbucket];
GO
CREATE PROCEDURE dbo.SelectFromDatabaseB
AS
SET NOCOUNT ON;
SELECT *
FROM [DatabaseB].dbo.SomeTable;
GO
GRANT EXECUTE ON dbo.SelectFromDatabaseB TO [JohnnyLunchbucket];
GO
USE [DatabaseB];
CREATE TABLE dbo.SomeTable (Col1 INT);
INSERT INTO dbo.SomeTable ([Col1]) VALUES (111);
GO
TEST 1(アクセスなし)
USE [DatabaseA];
EXECUTE AS LOGIN = N'JohnnyLunchbucket';
SELECT * FROM [DatabaseB].dbo.SomeTable;
/*
Msg 916, Level 14, State 1, Line XXXXX
The server principal "JohnnyLunchbucket" is not able to access the database "DatabaseB" under the current security context.
*/
EXECUTE dbo.[SelectFromDatabaseB];
/*
Msg 916, Level 14, State 1, Procedure dbo.SelectFromDatabaseB, Line XXXXX [Batch Start Line YYYYY]
The server principal "JohnnyLunchbucket" is not able to access the database "DatabaseB" under the current security context.
*/
REVERT;
モジュール署名を追加
CREATE CERTIFICATE [PermissionsCert]
AUTHORIZATION [dbo]
ENCRYPTION BY PASSWORD = 'WeakPassword'
WITH SUBJECT = 'Used to test granting permissions to code',
EXPIRY_DATE = '2099-12-31';
ADD SIGNATURE TO [dbo].[SelectFromDatabaseB]
BY CERTIFICATE [PermissionsCert]
WITH PASSWORD = 'WeakPassword';
-- Copy Certificate (public key only) to DatabaseB
DECLARE @SQL NVARCHAR(MAX);
SET @SQL = N'USE [DatabaseB];
CREATE CERTIFICATE [PermissionsCert] AUTHORIZATION [dbo] FROM BINARY = '
+ CONVERT(NVARCHAR(MAX), CERTENCODED(CERT_ID(N'PermissionsCert')), 1)
+ N';'
EXEC (@SQL);
USE [DatabaseB];
CREATE USER [PermissionsUser] FROM CERTIFICATE [PermissionsCert];
GRANT SELECT ON [dbo].[SomeTable] TO [PermissionsUser];
GO
TEST 2(アクセスは許可されますが、署名されたモジュールを介してのみ)
USE [DatabaseA];
EXECUTE AS LOGIN = N'JohnnyLunchbucket';
SELECT * FROM [DatabaseB].dbo.SomeTable;
/*
Msg 916, Level 14, State 1, Line XXXXX
The server principal "JohnnyLunchbucket" is not able to access the database "DatabaseB" under the current security context.
*/
EXECUTE dbo.[SelectFromDatabaseB];
-- 111
REVERT;
署名されたモジュールのみが、証明書から作成されたログインやユーザーにアクセスを許可されます。また、ユーザーは、自分がアクセスを許可したモジュールにのみアクセスできます。