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


8

開発者は、.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でこれを行うための最良の方法ですか?


1
解決しました。ソリューションには3つの要素がありました。サーバーで所有権の連鎖を有効にする必要があります。EXECUTE ASステートメントで使用されるユーザーは、saまたはxp_sqlagent_ *ジョブを実行するための同様の権限を持つユーザーである必要があります。また、ジョブは、EXECUTE ASステートメントにリストされているのと同じユーザーが所有している必要があります。
Ed Leighton-Dick

もう少し実験すると、このソリューションに対する1つのバリエーションが示されました。SA以外のプロキシユーザーを使用してジョブを実行する場合は、マスターデータベースのxp_sqlagent_ *プロシージャに対するEXECUTE権限をプロキシユーザーに付与できます。(他の2つの要件-データベース間の所有権とジョブの所有権-は引き続き適用されます。)
Ed Leighton-Dick

回答:


5

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

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


はい-私はそれをSQLAgentOperatorロールに追加することから始め、次にsp_start_job自体に直接EXECUTEパーミッションを試しました。どちらも役に立たなかった。プロキシの権限に関係なく、このエラーがスローされるようです。sysadminレベルのアカウントでも失敗します。
Ed Leighton-Dick、

SQLプロファイラーを使用して、実際に呼び出しを行っているアカウントを確認します。もう少し考えてみると、Execute Asはデータベースユーザーを使用していますが、おそらく他のデータベースに正しく変換されていません。データベースチェーンをオンにして、それが機能するかどうかを確認してください。
mrdenny、2009年

所有権の継承はソリューションの大部分を占めていたので、ここでポイントを授与します。これには他にも2つの要素があることがわかります。上記に注意します。
Ed Leighton-Dick、

8

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

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.dbo.sp_start_jobことはできませんmsdb。サーバースコープDMVへのアクセスの試行、リンクサーバーの使用の試行、Service Brokerメッセージの別のデータベースへの配信の試行など、利用可能な他の多くの例があります。

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

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

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

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

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

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

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

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

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

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

対応する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句が必要なため)のコンテキストで記述された、このトピックに関する記事がいくつかあります。

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


0

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

http://www.stackoverflow.com


1
これはおそらくデータベースのセキュリティ問題だと思いますが、ここで答えが見つからない場合はStackOverflowを試してみます。
Ed Leighton-Dick、

0

ネットワーク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。


ユーザーは明示的にSQLAgentOperatorRoleおよびSQLAgentUserRoleのメンバーです。
Ed Leighton-Dick

0

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

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.