web-dev-qa-db-ja.com

sysadminに対するCREATE DATABASE権限が拒否されました

ユーザーがデータベースを作成する権限を持っていないデータベースを作成するためのプロキシとして使用できるストアドプロシージャを作成しようとしています。詳細は データベースアクセス/機能をユーザーグループに制限しますか? を参照してください

ストアドプロシージャを実行しようとすると、SQL Serverがセキュリティエラーを生成します。

Msg 262, Level 14, State 1, Line 1
CREATE DATABASE permission denied in database 'master'.

これはコードです:

CREATE LOGIN DatabaseCreator WITH PASSWORD='Pa$$w0rd'; /* REPLACE WITH A SECURE PASSWORD! */
GO
CREATE USER DatabaseCreator FOR LOGIN DatabaseCreator;
GO
EXEC sys.sp_addsrvrolemember 'DatabaseCreator','sysadmin';
GO
CREATE PROCEDURE dbo.CreateDatabase
(
    @DatabaseName SYSNAME
)
WITH EXECUTE AS 'DatabaseCreator'
AS
BEGIN
    SET NOCOUNT ON;
    DECLARE @cmd NVARCHAR(max);
    IF COALESCE(@DatabaseName,'') <> ''
    BEGIN
        SET @cmd = 'CREATE DATABASE ' + QUOTENAME(@DatabaseName) + ';' 
        EXEC sys.sp_executesql @cmd;
    END
    ELSE
    BEGIN
        SET @cmd = 'INVALID DATABASE NAME';
        RAISERROR (@cmd, 0, 1);
    END
END;
GO
EXEC master.dbo.CreateDatabase 'MyDatabaseName';

msg 262は一般的なPermission Deniedメッセージのようです。 DatabaseCreatorにはsysadmin特権があるため、これは発生しません。私が何かを逃していない限り。

3
Max Vernon

EXECUTE ASCREATE PROCEDURE句は、(ログインではなく)ユーザーを偽装するためにのみ使用でき、偽装の範囲は現在のデータベースに制限されています。 sysadmin権限はユーザーではなくログインに関連付けられているため、権限エラーが発生します。

ここでCREATE DATABASEを付与する正しい方法は、プロシージャに署名することです。サーバーレベルのアクセス許可を付与する手順に署名する必要があるため、プロセスは少し複雑ですが、プロセスの各ステップはかなり単純です。

まず、証明書を作成し、masterCREATE ANY DATABASE権限でログインします。証明書は後でターゲットデータベースにコピーされ、プロシージャの署名が可能になります。

USE master;
GO
CREATE CERTIFICATE CreateDatabaseCert
   ENCRYPTION BY PASSWORD = 'password'
   WITH SUBJECT = 'Create Database',
   START_DATE = '20140101',
   EXPIRY_DATE = '20141231';
GO
CREATE LOGIN CreateDatabaseLogin 
FROM CERTIFICATE CreateDatabaseCert;
GO
DENY CONNECT SQL TO CreateDatabaseLogin;
GO
GRANT CREATE ANY DATABASE 
TO CreateDatabaseLogin;

次に、証明書を手順が実行されるデータベースにコピーする必要があります。これを行うにはいくつかの方法がありますが、最も互換性のある方法は、ファイルを介して証明書を読み書きすることです。次のステップでは、証明書を書き込みます。

BACKUP CERTIFICATE CreateDatabaseCert 
TO FILE = 'C:\Temp\CreateDatabase.cer'
WITH PRIVATE KEY 
(
    FILE = 'C:\Temp\CreateDatabase.pvk',
    ENCRYPTION BY PASSWORD = 'password',
    DECRYPTION BY PASSWORD = 'password'
);

次に、ターゲットデータベースに切り替え、証明書を復元し、一時ファイルを削除します。

USE Sandpit;
GO
CREATE CERTIFICATE CreateDatabaseCert
FROM FILE = 'C:\Temp\CreateDatabase.cer'
WITH PRIVATE KEY
(
    FILE = 'C:\Temp\CreateDatabase.pvk',
    ENCRYPTION BY PASSWORD = 'password',
    DECRYPTION BY PASSWORD = 'password'
);
GO
--EXECUTE sys.sp_configure 'show advanced options', 1;
--RECONFIGURE;
--EXECUTE sys.sp_configure 'xp_cmdshell', 1;
--RECONFIGURE;
EXECUTE sys.xp_cmdshell 'ERASE C:\Temp\CreateDatabase.*';

次に、プロシージャを作成し、証明書を使用してそれに署名します。

CREATE PROCEDURE dbo.CreateDatabase
(
    @DatabaseName SYSNAME
)
WITH EXECUTE AS CALLER
AS
BEGIN

    SET NOCOUNT ON;
    DECLARE @cmd NVARCHAR(max);
    IF COALESCE(@DatabaseName,'') <> ''
    BEGIN
        SET @cmd = 'CREATE DATABASE ' + QUOTENAME(@DatabaseName) + ';' 
        EXEC sys.sp_executesql @cmd;
    END
    ELSE
    BEGIN
        SET @cmd = 'INVALID DATABASE NAME';
        RAISERROR (@cmd, 0, 1);
    END
END;
GO
ADD SIGNATURE TO dbo.CreateDatabase
BY CERTIFICATE CreateDatabaseCert
WITH PASSWORD = 'password';

これが機能することをテストするために、プロシージャのみを実行する権限を持つ新しいログインとユーザーを作成します。

CREATE LOGIN test WITH PASSWORD = 'password';
CREATE USER test FROM LOGIN test;
GRANT EXECUTE ON dbo.CreateDatabase TO test;

テスト自体:

EXECUTE AS LOGIN = 'test';
EXECUTE dbo.CreateDatabase @DatabaseName = 'NewDB';
REVERT;

データベースが正常に作成されました。クリーンアップするには、次を実行します。

DROP DATABASE NewDB;
DROP USER test;
DROP LOGIN test;
DROP PROCEDURE dbo.CreateDatabase;
DROP CERTIFICATE CreateDatabaseCert;
GO
USE master;
DROP LOGIN CreateDatabaseLogin;
DROP CERTIFICATE CreateDatabaseCert;

アクセス許可の詳細については、 Erland Sommarskogの優れた記事 を参照してください。

5
Paul White 9