ユーザーが他のジョブを開始することができなくても、特定のエージェントジョブを開始できるようにする必要があります。これを実現するために、次の手順を作成しました(簡略化)。
ALTER PROCEDURE [dbo].[RunJob]
@job_name nvarchar(200)
WITH EXECUTE AS 'sysadminaccount'
AS
BEGIN
--SET NOCOUNT ON;
BEGIN TRY
EXEC msdb.dbo.sp_start_job @job_name = @job_name
-- Wait for job to finish
DECLARE @job_history_id AS INT = NULL
DECLARE @job_result AS INT = NULL
WHILE 1=1
BEGIN
SELECT TOP 1 @job_history_id = activity.job_history_id
FROM msdb.dbo.sysjobs jobs
INNER JOIN msdb.dbo.sysjobactivity activity ON activity.job_id = jobs.job_id
WHERE jobs.name = @job_name
ORDER BY activity.start_execution_date DESC
IF @job_history_id IS NULL
BEGIN
WAITFOR DELAY '00:00:01'
CONTINUE
END
ELSE
BREAK
END
-- Check exit code
SET @job_result = (SELECT history.run_status
FROM msdb.dbo.sysjobhistory history
WHERE history.instance_id = @job_history_id)
RETURN @job_result;
END TRY
BEGIN CATCH
THROW;
RETURN;
END CATCH
END
しかし、このプロシージャを呼び出すと( "sysadminaccount"を介して実行されていることが確認されている場合)、次のエラーメッセージが表示されます。
メッセージ229、レベル14、状態5、プロシージャsp_start_job、行1 EXECUTE権限は、オブジェクト 'sp_start_job'、データベース 'msdb'、スキーマ 'dbo'で拒否されました。
アカウントはsysadminロールのメンバーであるため、ジョブの開始に問題はないはずです。 msdbの3つのsqlagentロールのメンバーであることを確認しました。これらのロールはすべてsp_start_job
に対する実行権限を持っています。
このアカウントに適切な権限を与えるにはどうすればよいですか?なりすましのために他に必要なことはありますか?
TRUSTWORTHY
オプションは、さまざまなものへの露出を大幅に増やすため、私は好きではありません。 Remusが この答え で説明しているように、本質的にdb_owner
からsysadmin
へ。他に読む価値のあるものとして、TRUSTWORTHY
のシリーズ Sebastian Meine によるシリーズ、BOLトピック、およびKB記事があります(このシナリオでは、アセンブリの部分は関係がない場合もあります)。 :
(そして、このプロパティの盲目的な使用を警告する他の投稿がたくさんあります-それが機能し、それが簡単だからといって、それが正しいことを意味するわけではありません-実際、それはあなたにさらに疑問を抱かせるはずです。)だから私は別のアプローチを提案するでしょう(そして、証明書で署名するなど、他にもまだありますが、これは常に私にとってはうまくいきました):
msdb
にプロシージャを作成します。このユーザーのログイン用のユーザーをmsdb
に作成します。
USE msdb;
GO
CREATE USER floobarama FROM LOGIN floobarama;
ストアドプロシージャの実行権限をユーザーに付与します。
GRANT EXECUTE ON [dbo].[RunJob] TO floobarama;
それをテストします-別のデータベースからプロシージャを呼び出すことによって:
USE tempdb;
GO
EXECUTE AS LOGIN = N'floobarama';
GO
EXEC msdb.dbo.RunJob @job_name = N'whatever';
GO
REVERT;
または、より簡単なテスト。ジョブをすぐに実行したくなく、このユーザーがmsdb
への十分なアクセス権を持っているかどうかを確認するためにこのユーザーがジョブを実行するまで待機したくない場合:
USE msdb;
GO
CREATE PROCEDURE dbo.whatever
WITH EXECUTE AS N'sysadminaccount'
AS
BEGIN
SET NOCOUNT ON;
SELECT [I am really...] = SUSER_SNAME();
END
GO
GRANT EXECUTE ON dbo.whatever TO floobarama;
USE tempdb;
GO
EXECUTE AS LOGIN = N'floobarama';
GO
EXEC msdb.dbo.whatever;
GO
REVERT;
結果は次のようになります。
I am really...
---------------
sysadminaccount
これがmsdb
の他の何もこのユーザーに公開しないことを確認します。
USE tempdb;
GO
EXECUTE AS LOGIN = N'floobarama';
GO
SELECT job_id FROM msdb.dbo.sysjobs;
GO
REVERT;
結果は...
メッセージ229、レベル14、状態5、行21
オブジェクト 'sysjobs'、データベース 'msdb'、スキーマ 'dbo'に対するSELECT権限が拒否されました。
...データベースにユーザーを作成しても、そのデータベース内のすべてに対する自動権限は付与されません。そのユーザー、またはユーザーが属しているロールまたはグループ(public
を含む)に対して明示的に行う必要があります。
ポイントが足りないのでコメントできないので回答を書きます。これはデータベース間の所有権の連鎖の問題のようです。このプロシージャがmsdbの外部で作成された場合、 "EXECUTE AS"がsysadminロールのメンバーとしてユーザーを偽装しても、参照されるデータベースのオブジェクトにはアクセスできません。
したがって、考えられる解決策は次のとおりです。
データベースをTRUSWORTHYにします。
ALTER DATABASE dbname SET TRUSTWORTHY ON;
データベースの複数データベースの組み合わせ所有権を有効にします(必要でない場合があります)
ALTER DATABASE dbname SET DB_CHAINING ON;
私は、トラストワーシーがアプローチにそれほど信頼できるわけではないことに完全に同意します。必要な結果を得るには、別の方法を選択する必要があります。
最近、SQLエージェントジョブの開始を別のユーザーまたはユーザーグループに許可する方法を投稿しました。あなたはそれを見ることができます:
sysadmin以外、SQL Serverエージェントジョブの非所有者に実行を許可
3番目のオプションであるセキュリティテーブルとストアドプロシージャは、柔軟性を最大化し、危険性を最小限に抑えます。