I'm attempting to create a stored procedure that can be used as a proxy for creating databases where users do not have rights for creating databases. See Restricting Database Access/Functions to User Groups? for more info
When I attempt to execute the stored proc, SQL Server generates a security error:
Msg 262, Level 14, State 1, Line 1
CREATE DATABASE permission denied in database 'master'.
This is the code:
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
appears to be a generic Permission Denied message. Since DatabaseCreator
has sysadmin
privileges, this should not be happening. Unless I'm missing something.
Best Answer
The
EXECUTE AS
clause ofCREATE PROCEDURE
can only be used to impersonate a user (not a login) and the scope of impersonation is restricted to the current database. Thesysadmin
permission is associated with the login, not the user, so you receive a permissions error.The correct way to grant
CREATE DATABASE
here is to sign the procedure. The process is a little involved because we want to sign the procedure to grant a server-level permission, but each step of the process is reasonably simple:First, create a certificate and login in
master
with theCREATE ANY DATABASE
permission. The certificate will later be copied to the target database to allow procedure signing.We now need to copy the certificate to the database where the procedure will be run. There are a couple of ways to do this, but the most compatible is to read and write the certificate via a file. This next step writes the certificate:
Now we switch to the target database, restore the certificate, and delete the temporary files:
Now create the procedure, and sign it using the certificate:
To test this works, we create a new login and user with permissions to execute the procedure only:
The test itself:
The database is created successfully. To clean up, run the following:
For more information on permissions, see Erland Sommarskog's excellent article.