SQL 对 运行 作业的证书权限

SQL Certificate Permissions to Run Jobs

我们需要权限较低的用户可以通过 proc 启动 1 个作业。所以,我们:

  1. 创建了一个 proc(在 master db 中)来启动作业
  2. 创建了一个证书并用证书签署了过程
  3. 从证书创建了一个登录名并授予了对该登录名更高级别的访问权限
  4. 在 master 数据库中创建了一个角色,并为该角色授予了 EXECUTE 权限
  5. 将权限较低的初始用户放入这个新角色

我的问题 为什么这行不通?我们使用类似的东西来允许用户在我们的一台服务器上恢复数据库。现在让这个为我工作的唯一方法是在 msdb db 中为低权限用户提供更高的权限。这显然是不理想的,并且完全取消了我们试图避免的事情。

下面是示例权限代码,下面是 proc 代码。

USE [master];
GO

CREATE CERTIFICATE [TestCert]
    ENCRYPTION BY PASSWORD = N'ComplicatedPassword'
    WITH SUBJECT = N'Certificate to allow user to kick off one job';
GO

ADD SIGNATURE
    TO [dbo].[ProcThatCallsJob] 
    BY CERTIFICATE [TestCert]
    WITH PASSWORD = N'ComplicatedPassword';
GO

CREATE LOGIN [TestLoginFromCert] FROM CERTIFICATE [TestCert]
GO

ALTER SERVER ROLE [sysadmin] ADD MEMBER [TestLoginFromCert]
GO

CREATE ROLE [RoleToExecuteProc]

GO

GRANT EXECUTE ON OBJECT::[dbo].[ProcThatCallsJob]
    TO [RoleToExecuteProc];
GO

CREATE USER [TestUser_LowPermissions]  
FOR LOGIN [TestUser]
GO

ALTER ROLE [RoleToExecuteProc] ADD MEMBER [TestUser_LowPermissions]
GO

USE [msdb]
GO

CREATE USER [TestUserFromCert]  
FOR LOGIN [TestLoginFromCert]
GO  

ALTER ROLE [db_datareader] ADD MEMBER [BDWReportUserRunJobs]
GO
ALTER ROLE [SQLAgentOperatorRole] ADD MEMBER [BDWReportUserRunJobs]
GO

进程,[dbo].[ProcThatCallsJob]:

USE [master]
GO

CREATE PROCEDURE [dbo].[ProcThatCallsJob]
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;

    DECLARE @sql NVARCHAR(MAX);

    SET @sql = N'USE msdb
                 EXEC msdb.dbo.sp_start_job @job_name = ''10171_TestJob''
                '
    EXECUTE sp_executesql @sql;

END

问题是否与 proc 使用 master db 中的证书签名(与具有 sysadmin 权限的登录相关联)这一事实有关?我可以将证书放在 msdb 数据库中,但我没有任何东西可以在那里签名。

编辑 - 我在 msdb db 中创建了 proc 和证书,以测试我的假设,即更改数据库引起了一些担忧。没有运气。 [TestUser_LowPermissions] 仍然收到无法执行 sp_start_job 的错误。所以,我仍然不知道为什么签名的过程没有继承 sysadmin 的 [TestLoginFromCert] 权限。

来自MSDN forum

到目前为止你所做的一切本身都是正确的。问题出在嵌套系统存储过程本身。

事情是:sp_start_job 正在做另一个 permission/role 检查,hard-coded:

-- 检查超出 sysjobs_view 检查的权限 -- SQLAgentReader 角色可以看到所有作业,但是 -- 不能 start/stop 他们不拥有的工作 IF (@job_owner_sid <> SUSER_SID() -- 不拥有该工作 AND (ISNULL(IS_SRVROLEMEMBER(N'sysadmin'), 0) = 0) -- 不是系统管理员 AND (ISNULL(IS_MEMBER(N'SQLAgentOperatorRole'), 0) = 0)) -- 不是 SQLAgentOperatorRole 开始 RAISERROR(14393, -1, -1);
RETURN(1) -- 失败 结束

既然不想乱系统代码,那么剩下的选项不多了: 1. 使用 Impersonation to sa: 高风险 2. 使用可信赖的数据库——我个人不太喜欢公开这么说,因为很难教育普通用户不要使用这个概念。但如果它是您自己的 code-only 数据库,您可以保护它 3. 结合使用 [SQLAgentOperatorRole] 和您自己的过程。含义:使用户成为该角色的成员,然后拒绝在 sp_startjob(和其他过程)上执行。这样你就可以通过你自己的 proc 授予执行并通过给他 [SQLAgentOperatorRole].

来绕过 hard-coded 检查