Aufruf von sp_start_job von einer gespeicherten Prozedur

8

Unsere Entwickler müssen in der Lage sein, einen SQL Server Agent-Job über ihren .NET-Code zu starten. Ich weiß, dass ich msdb..sp_start_job aufrufen kann , um genau das zu tun, aber ich möchte allgemeinen Benutzerkonten keinen direkten Zugriff zum Ausführen von Jobs gewähren.

Ich möchte eine gespeicherte Prozedur in der Datenbank der Anwendung erstellen, indem ich die WITH EXECUTE AS-Klausel verwende, um mich als Proxy-Konto auszugeben. Das Verfahren, wie wir es haben, ist:

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

Wenn wir dies ausführen, erhalten wir jedoch die folgende Meldung:

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

Irgendwelche Ideen? Ist dies überhaupt der beste Weg, dies in SQL2005 zu tun?

Ed Leighton-Dick
quelle
1
Gelöst. Die Lösung bestand aus drei Teilen: Die Eigentumsverkettung muss auf dem Server aktiviert sein. Der in der EXECUTE AS-Anweisung verwendete Benutzer muss sa oder ein Benutzer mit ähnlichen Berechtigungen sein, um die xp_sqlagent_ * -Jobs ausführen zu können. und der Job muss demselben Benutzer gehören, der in der EXECUTE AS-Anweisung aufgeführt ist.
Ed Leighton-Dick
Ein wenig mehr Experimentieren zeigte eine Variation dieser Lösung. Wenn Sie einen Nicht-SA-Proxy-Benutzer zum Ausführen des Jobs verwenden möchten, können Sie dem Proxy-Benutzer EXECUTE-Berechtigungen für die Prozeduren xp_sqlagent_ * in der Master-Datenbank erteilen. (Die anderen beiden Anforderungen - datenbankübergreifender Besitz und Jobbesitz - gelten weiterhin.)
Ed Leighton-Dick

Antworten:

5

Haben Sie das agentProxy-Login in die msdb-Datenbank gestellt und ihr die Berechtigung zum Ausführen von sp_start_job erteilt? Wenn nicht, müssen Sie die Verkettung von Datenbankberechtigungen für die msdb-Datenbank und Ihre Benutzerdatenbank aktivieren.

Sie sind wahrscheinlich besser dran, das Login in die msdb-Datenbank zu stellen und ihr die richtigen Rechte zu gewähren.

mrdenny
quelle
Ja - Ich habe es zunächst zur SQLAgentOperator-Rolle hinzugefügt und dann versucht, direkte EXECUTE-Berechtigungen für sp_start_job selbst auszuführen. Beides half nicht. Es scheint diesen Fehler unabhängig von den Berechtigungen des Proxys auszulösen - selbst ein Konto auf Systemadministratorebene schlägt fehl.
Ed Leighton-Dick
Verwenden Sie SQL Profiler und sehen Sie, welches Konto den Anruf tatsächlich tätigt. Jetzt, wo ich mehr darüber nachdenke, verwendet Execute As einen Datenbankbenutzer, der wahrscheinlich nicht korrekt in die andere Datenbank übersetzt wird. Aktivieren Sie die Datenbankverkettung und prüfen Sie, ob dies funktioniert.
Mrdenny
Die Verkettung der Eigentumsverhältnisse war ein großer Teil der Lösung, daher vergebe ich hier die Punkte. Es stellt sich auch heraus, dass es zwei andere Stücke gibt; Ich werde die oben notieren.
Ed Leighton-Dick
8

Ich bin froh, dass Sie dies gelöst haben, aber die Verkettung von Eigentumsrechten ist nicht die empfohlene Lösung. Da Sie anscheinend ernsthaft besorgt über die Sicherheit und die ordnungsgemäße Granularität der betreffenden Rechte sind, füge ich diese Antwort hinzu, obwohl sie zu spät ist, als Hinweis darauf, was passiert und wie diese Probleme gelöst werden können.

AUSFÜHREN ALS Identitätswechselbereich

Die EXECUTE AS-Klauseln gibt es in zwei Varianten: EXECUTE AS LOGIN und EXECUTE AS USER. Das EXECUTE AS LOGIN wird vom Server authentifiziert und ist ein Identitätswechselkontext, dem die gesamte SQL-Instanz vertraut (mit Serverbereich):

Wenn Sie sich als Principal ausgeben, indem Sie die EXECUTE AS LOGIN-Anweisung verwenden, oder innerhalb eines Moduls mit Serverbereich, indem Sie die EXECUTE AS-Klausel verwenden, ist der Umfang des Identitätswechsels serverweit. Dies bedeutet, dass nach dem Kontextwechsel auf jede Ressource innerhalb des Servers zugegriffen werden kann, für die die Identitätswechselberechtigung Berechtigungen hat.

EXECUTE AS USER wird von der Datenbank authentifiziert und ist ein Identitätswechselkontext, dem nur diese Datenbank vertraut (datenbankbezogen):

Wenn Sie sich jedoch als Principal ausgeben, indem Sie die EXECUTE AS USER-Anweisung verwenden, oder innerhalb eines Moduls mit Datenbankbereich, indem Sie die EXECUTE AS-Klausel verwenden, ist der Umfang des Identitätswechsels standardmäßig auf die Datenbank beschränkt. Dies bedeutet, dass Verweise auf Objekte außerhalb des Bereichs der Datenbank einen Fehler zurückgeben.

Eine gespeicherte Prozedur mit einer EXECUTE AS-Klausel erstellt einen Identitätswechselkontext mit Datenbankbereich und kann daher keine Objekte außerhalb der Datenbank referenzieren. In diesem Fall können Sie nicht referenzieren, msdb.dbo.sp_start_jobda sich in befindet msdb. Es stehen viele andere Beispiele zur Verfügung, z. B. der Versuch, auf eine DMV mit Serverbereich zuzugreifen, ein Verbindungsserver zu verwenden oder eine Service Broker-Nachricht in eine andere Datenbank zu übermitteln.

Um einem Identitätswechsel mit Datenbankbereich den Zugriff auf eine Ressource zu ermöglichen, die normalerweise nicht zulässig ist, muss dem Authentifikator des Identitätswechselkontexts vertraut werden. Bei einem Identitätswechsel mit Datenbankbereich ist der Authentifikator die Datenbank dbo. Dies kann auf zwei Arten erreicht werden:

  • Durch Aktivieren der TRUSTWORTHY-Eigenschaft in der Datenbank, die den Identitätswechselkontext authentifiziert hat (dh in der Datenbank, in der die EXECUTE AS-Klausel ausgegeben wurde).
  • Durch die Verwendung von Codesignaturen.

Diese Details werden in MSDN: Erweitern des Datenbankidentitätswechsels mithilfe von EXECUTE AS beschrieben .

Wenn Sie das Problem über eine datenbankübergreifende Verkettung behoben haben, haben Sie die datenbankübergreifende Verkettung auf der gesamten Serverebene aktiviert, was als Sicherheitsrisiko angesehen wird. Der am besten kontrollierte und feinkörnige Weg, um das gewünschte Ergebnis zu erzielen, ist die Verwendung der Codesignatur:

  • Erstellen Sie in der Anwendungsdatenbank ein selbstsigniertes Zertifikat
  • Unterschreiben Sie das dbo.StartAgentJobmit diesem Zertifikat
  • Löschen Sie den privaten Schlüssel des Zertifikats
  • Exportieren Sie das Zertifikat auf die Festplatte
  • Importieren Sie das Zertifikat in msdb
  • Erstellen Sie einen abgeleiteten Benutzer aus dem importierten Zertifikat in msdb
  • Erteilen Sie dem abgeleiteten Benutzer in die Berechtigung AUTHENTICATE msdb

Diese Schritte stellen sicher, dass dem EXECUTE AS-Kontext der dbo.StartAgentJobProzedur jetzt vertraut wird msdb, da der Kontext von einem Principal signiert ist, der über die Berechtigung AUTHENTICATE verfügt msdb. Dies löst die Hälfte des Puzzles. Die andere Hälfte besteht darin, die EXECUTE-Berechtigung msdb.dbo.sp_start_jobfür den jetzt vertrauenswürdigen Identitätswechselkontext zu erteilen . Dies kann auf verschiedene Arten geschehen:

  1. Ordnen Sie den imitierten Benutzer dem agentProxyBenutzer zu msdbund erteilen Sie ihm die Ausführungsberechtigung fürmsdb.dbo.sp_start_job
  2. Erteilen Sie dem vom msdbAuthentifizierungszertifikat abgeleiteten Benutzer die Ausführungsberechtigung
  3. Fügen Sie der Prozedur eine neue Signatur hinzu, leiten Sie einen Benutzer dafür ab msdbund erteilen Sie diesem abgeleiteten Benutzer die Ausführungsberechtigung

Option 1. ist einfach, hat aber einen großen Nachteil: Der agentProxyBenutzer kann das nun nach msdb.dbo.sp_start_jobeigenem Ermessen ausführen , erhält wirklich Zugriff auf msdbund verfügt über die Ausführungsberechtigung.

Option 3 ist durchaus richtig, aber ich halte es für unnötig übertrieben.

Daher wird Option 2 bevorzugt: Erteilen Sie msdb.dbo.sp_start_jobdem in Zertifikaten abgeleiteten Benutzer, der in erstellt wurde , die EXECUTE-Berechtigung msdb.

Hier ist das entsprechende 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

Mein Blog enthält einige Artikel zu diesem Thema, die im Zusammenhang mit von Service Broker aktivierten Prozeduren geschrieben wurden (da für sie eine EXECUTE AS-Klausel erforderlich ist):

Übrigens, wenn Sie versuchen, mein Skript zu testen und auf der östlichen Hemisphäre oder im Sommer in Großbritannien leben, lesen Sie auf jeden Fall den letzten Artikel, den ich vor dem Testen verlinkt habe.

Remus Rusanu
quelle
0

Da Sie versuchen, SQL Server Agent über .NET-Code zu starten, ist dies möglicherweise eine bessere Frage für StackOverflow.

http://www.stackoverflow.com

KPWINC
quelle
1
Ich denke, dies ist wahrscheinlich ein Problem mit der Datenbanksicherheit, aber ich werde StackOverflow ausprobieren, wenn wir hier keine Antwort finden.
Ed Leighton-Dick
0

Durch Überprüfen einer zufälligen SQL-Instanz im Netzwerk SQLAgentOperatorRole erhalten Sie keine direkten Berechtigungen für sp_start_job, sondern erben diese von SQLAgentUserRole.

Überprüfen Sie es mit:

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'

Führen Sie dies in MSDB aus und überprüfen Sie, ob Sie keinen expliziten Verweigerungszugriff geerbt haben.

hth.

Andrew
quelle
Der Benutzer ist explizit Mitglied von SQLAgentOperatorRole und SQLAgentUserRole.
Ed Leighton-Dick
0

Eine Möglichkeit, dies zu erreichen, ohne zusätzliche Berechtigungen zu erteilen: Lassen Sie den gespeicherten Prozess den Job nicht direkt starten, sondern lassen Sie den gespeicherten Prozess nur ein wenig in einer Tabelle (in der Anwendungsdatenbank) umblättern. Lassen Sie den Job dann jede Minute oder so laufen, prüfen Sie, ob das Bit gespiegelt ist, und führen Sie in diesem Fall die Arbeit aus und drehen Sie das Bit erneut zurück. Wenn der Job sieht, dass das Bit nicht gespiegelt ist, wird der Job einfach beendet.

Funktioniert wie ein Zauber, wenn Ihnen die Verzögerung nichts ausmacht (und der Job sehr oft ausgeführt wird).

Robert van den Berg
quelle