web-dev-qa-db-ja.com

ストアドプロシージャからのsp_start_jobの呼び出し

開発者は、.NetコードからSQL Serverエージェントジョブを開始できる必要があります。 msdb..sp_start_jobを呼び出してそれを実行できることはわかっていますが、一般的なユーザーアカウントにジョブを実行するための直接アクセス権を付与したくありません。

私がやりたいのは、WITH EXECUTE AS句を使用してアプリケーションのデータベースにストアドプロシージャを作成し、プロキシアカウントを偽装することです。現在の手順は次のとおりです。

CREATE PROCEDURE dbo.StartAgentJob 
    WITH EXECUTE AS 'agentProxy'
AS
BEGIN
    EXEC msdb.dbo.sp_start_job N'RunThisJob';
END

ただし、これを実行すると、次のメッセージが表示されます。

The EXECUTE permission was denied on the object 'sp_start_job', database 'msdb', schema 'dbo'.

何か案は?これはSQL2005でこれを行うための最良の方法ですか?

8

MsProデータベースにagentProxyログインを置き、sp_start_jobを実行する権限を与えましたか?そうでない場合は、msdbデータベースとユーザーデータベースのデータベース権限チェーンを有効にする必要があります。

ログインをmsdbデータベースに入れて、適切な権限を付与する方がよいでしょう。

5
mrdenny

これを解決してよかったですが、所有権の継承は推奨されるソリューションではありません。関係する権利のセキュリティと適切な細分性について正当に懸念しているように思われるので、この返信を遅らせながら、何が起こっているのか、およびこの問題を解決する方法への参照として追加します。

EXECUTE AS偽装スコープ

EXECUTE AS句には、EXECUTE AS LOGINとEXECUTE AS USERの2種類があります。 EXECUTE AS LOGINはサーバーによって認証され、SQLインスタンス全体(サーバースコープ)によって信頼される偽装コンテキストです。

EXECUTE AS LOGINステートメントを使用してプリンシパルを偽装する場合、またはEXECUTE AS句を使用してサーバースコープのモジュール内で偽装する場合、偽装のスコープはサーバー全体に及びます。これは、コンテキストの切り替え後、偽装ログインが権限を持っているサーバー内のすべてのリソースにアクセスできることを意味します。

EXECUTE AS USERはデータベースによって認証され、そのデータベースによってのみ信頼される偽装コンテキストです(データベーススコープ):

ただし、EXECUTE AS USERステートメントを使用してプリンシパルを偽装する場合、またはEXECUTE AS句を使用してデータベーススコープのモジュール内で偽装する場合、偽装のスコープはデフォルトでデータベースに制限されます。つまり、データベースのスコープ外のオブジェクトを参照すると、エラーが返されます。

EXECUTE AS句を含むストアドプロシージャは、データベーススコープの偽装コンテキストを作成します。そのため、msdbにあるため、msdb.dbo.sp_start_jobを参照できないので、データベース外のオブジェクトを参照することはできません。 。サーバースコープDMVへのアクセスの試行、リンクサーバーの使用の試行、Service Brokerメッセージの別のデータベースへの配信の試行など、利用可能な他の多くの例があります。

データベーススコープの偽装を有効にして、通常は許可されないリソースにアクセスできるようにして、偽装コンテキストのauthenticatorを信頼する必要があります。データベーススコープの偽装の場合、オーセンティケーターはデータベースdboです。これは、次の2つの方法で実現できます。

  • 偽装コンテキストを認証したデータベース(つまり、EXECUTE AS句が発行されたデータベース)でTRUSTWORTHYプロパティをオンにする。
  • コード署名を使用する。

これらの詳細はMSDNで説明されています: EXECUTE ASを使用したデータベース偽装の拡張

データベース間の所有権の連鎖を介して問題を解決すると、サーバーレベル全体でクロスDBの連鎖が有効になり、セキュリティリスクと見なされます。目的の結果を達成するための最も制御された細かい方法は、コード署名を使用することです。

  • アプリケーションデータベースで自己署名証明書を作成します
  • この証明書でdbo.StartAgentJobに署名します
  • 証明書の秘密鍵を削除する
  • 証明書をディスクにエクスポートする
  • 証明書をmsdbにインポートします
  • msdbにインポートされた証明書から派生ユーザーを作成する
  • msdbの派生ユーザーにAUTHENTICATE権限を付与します

これらの手順により、dbo.StartAgentJobプロシージャのEXECUTE ASコンテキストがmsdbで信頼されるようになります。これは、コンテキストがmsdbでAUTHENTICATE権限を持つプリンシパルによって署名されているためです。これでパズルの半分が解けます。残りの半分は、実際にmsdb.dbo.sp_start_jobに対するEXECUTE権限を、現在信頼されている偽装コンテキストに付与することです。これを行う方法はいくつかあります。

  1. 偽装ユーザーagentProxyのユーザーをmsdbにマッピングし、msdb.dbo.sp_start_jobに対する実行権限を付与します
  2. msdbオーセンティケーター証明書から派生したユーザーに実行権限を付与する
  3. プロシージャに新しいシグネチャを追加し、msdbでそのシグネチャのユーザーを派生させ、この派生ユーザーに実行権限を付与します

オプション1.は単純ですが、大きな欠点があります。agentProxyユーザーは自分の意志でmsdb.dbo.sp_start_jobを実行できるようになり、msdbへのアクセスが本当に許可され、実行権限が付与されます。

オプション3は正解ですが、不必要にやりすぎだと思います。

したがって、私が優先するのは、オプション2:msdbで作成された証明書から派生したユーザーにmsdb.dbo.sp_start_jobに対するEXECUTE権限を付与することです。

以下は対応するSQLです。

use [<appdb>];
go

create certificate agentProxy 
    ENCRYPTION BY PASSWORD = 'pGFD4bb925DGvbd2439587y'
    with subject = 'agentProxy'
   , start_date='01/01/2009';
go

ADD SIGNATURE TO OBJECT::[StartAgentJob]
      BY CERTIFICATE [agentProxy]
        WITH PASSWORD = 'pGFD4bb925DGvbd2439587y';
go

alter certificate [agentProxy] 
  remove private key;
go

backup certificate [agentProxy] 
 to file='c:\temp\agentProxy.cer';
go

use msdb
go

create certificate [agentProxy] 
  from file='c:\temp\agentProxy.cer';
go

create user [agentProxyAuthenticator] 
 from certificate [agentProxy];
go

grant authenticate to [agentProxyAuthenticator];
grant execute on msdb.dbo.sp_start_job to [agentProxyAuthenticator];
go

use [<appdb>];
go

exec dbo.StartAgentJob;
go

私のブログには、Service Brokerでアクティブ化されたプロシージャ(EXECUTE AS句が必要なため)のコンテキストで記述された、このトピックに関する記事がいくつかあります。

ところで、私のスクリプトをテストしようとしていて、東半球または英国の夏に住んでいる場合は、テストする前にリンクした最後の記事を必ず読んでください。

8
Remus Rusanu

ネットワークSQLAgentOperatorRoleでランダムなSQLインスタンスを確認しても、sp_start_job権限は直接付与されず、SQLAgentUserRoleから継承されます。

を使用してそれを再確認してください:

select dp.NAME AS principal_name,
                 dp.type_desc AS principal_type_desc,
                 o.NAME AS object_name,
                 p.permission_name,
                 p.state_desc AS permission_state_desc 
    from    sys.database_permissions p
    left    OUTER JOIN sys.all_objects o on p.major_id = o.OBJECT_ID
    inner   JOIN sys.database_principals dp on p.grantee_principal_id = dp.principal_id
    where o.name = 'sp_start_job'

これをMSDBで実行し、明示的な拒否アクセスを継承していないことを再確認します。

hth。

0
Andrew

SQL Serverエージェントを.NETコードから起動しようとしているので、これはStackOverflowのより良い質問ですか?

http://www.stackoverflow.com

0
KPWINC

追加の権限を付与せずにこれを実現する1つの方法:ストアドプロシージャにジョブを直接開始させず、ストアドプロシージャが(アプリケーションデータベース内の)テーブルのビットを反転できるようにします。次に、ジョブを1分ごとに実行し、ビットが反転するかどうかを確認します。そうである場合は、作業を実行してビットを再度反転します。ジョブがビットが反転していないことを確認した場合、ジョブは終了します。

遅延(およびジョブが頻繁に実行される)を気にしない場合は、魅力のように機能します。

0