Ausführungsberechtigung für Objekt sp_start_job verweigert

8

Ich muss einem Benutzer erlauben, einen bestimmten Agentenjob zu kündigen, ohne andere starten zu können. Um dies zu erreichen, habe ich das folgende Verfahren (vereinfacht) erstellt:

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

Wenn ich diese Prozedur aufrufe (nachdem ich überprüft habe, dass sie über "sysadminaccount" ausgeführt wird), wird folgende Fehlermeldung angezeigt:

Nachricht 229, Ebene 14, Status 5, Prozedur sp_start_job, Zeile 1 Die EXECUTE-Berechtigung wurde für das Objekt 'sp_start_job', Datenbank 'msdb', Schema 'dbo' verweigert.

Der Account ist ein Mitglied der Sysadmin-Rolle, daher sollte es meines Wissens keine Probleme geben, Jobs zu starten. Ich habe überprüft, dass es ein Mitglied der drei sqlagent-Rollen in msdb ist, und diese Rollen haben alle Ausführungsberechtigung für sp_start_job.

Wie kann ich diesem Konto die entsprechenden Berechtigungen erteilen? Gibt es noch etwas, das wegen des Identitätswechsels getan werden muss?

Mansfield
quelle

Antworten:

12

Ich mag die TRUSTWORTHYOption nicht, weil sie Ihre Exposition gegenüber einer Vielzahl von Dingen erheblich erhöht. Wie Remus in dieser Antwort erklärt , erhöht es im Wesentlichen jede db_ownerzu sysadmin. Einige andere lesenswerte Dinge sind eine Reihe TRUSTWORTHYvon Sebastian Meine , das BOL-Thema, und ein KB-Artikel (auch wenn die Baugruppenteile in diesem Szenario für Sie möglicherweise nicht relevant sind):

(Und es gibt Unmengen anderer Posts, die vor der blinden Nutzung dieser Eigenschaft warnen - nur weil sie funktioniert und einfach ist, heißt das nicht, dass es das Richtige ist - in der Tat sollten Sie sie noch mehr in Frage stellen.) Daher würde ich einen anderen Ansatz vorschlagen (und es gibt noch andere, z. B. das Signieren mit einem Zertifikat, aber das hat bei mir immer funktioniert):

  1. Erstellen Sie die Prozedur in msdb.
  2. Erstellen Sie einen Benutzer für die Anmeldung dieses Benutzers msdb:

    USE msdb;
    GO
    CREATE USER floobarama FROM LOGIN floobarama;
  3. Gewähren Sie dem Benutzer Ausführungsberechtigungen für die gespeicherte Prozedur:

    GRANT EXECUTE ON [dbo].[RunJob] TO floobarama;
  4. Testen Sie es - entweder indem Sie die Prozedur aus einer anderen Datenbank aufrufen:

    USE tempdb;
    GO
    EXECUTE AS LOGIN = N'floobarama';
    GO
    EXEC msdb.dbo.RunJob @job_name = N'whatever';
    GO
    REVERT;

    Oder ein einfacher Test, falls Sie jetzt keinen Job ausführen möchten und nicht warten möchten, bis dieser Benutzer ihn ausführt, um herauszufinden, ob er über ausreichenden Zugriff verfügt auf 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;

    Ergebnis sollte sein:

    I am really...
    ---------------
    sysadminaccount
  5. Stellen Sie sicher, dass msdbdiesem Benutzer dadurch nichts anderes angezeigt wird:

    USE tempdb;
    GO
    EXECUTE AS LOGIN = N'floobarama';
    GO
    SELECT job_id FROM msdb.dbo.sysjobs;
    GO
    REVERT;

    Ergebnis sollte sein ...

    Nachricht 229, Ebene 14,
    Status 5, Zeile 21 Die SELECT-Berechtigung wurde für das Objekt 'sysjobs', Datenbank 'msdb', Schema 'dbo' verweigert.

    ... da das Erstellen eines Benutzers in einer Datenbank ihm keine automatischen Rechte für irgendetwas in dieser Datenbank gewährt; Sie müssen dies explizit entweder für diesen Benutzer oder für eine Rolle oder Gruppe tun, in der er sich befindet (einschließlich public).

Aaron Bertrand
quelle
2

Kann nicht kommentieren, da ich nicht genug Punkte habe, also schreibe ich eine Antwort. Dies scheint ein datenbankübergreifendes Problem bei der Verkettung von Eigentumsrechten zu sein. Wenn diese Prozedur außerhalb von msdb erstellt wird, hat sie keinen Zugriff auf Objekte in der referenzierten Datenbank, selbst wenn "EXECUTE AS" den Benutzer als Mitglied der Sysadmin-Rolle ausgibt.

Die wahrscheinliche Lösung ist also:

  1. Machen Sie Ihre Datenbank TRUSWORTHY:

    ALTER DATABASE dbname SET TRUSTWORTHY ON;
  2. Aktivieren Sie die datenbankübergreifende Besitzverkettung für die Datenbank (möglicherweise nicht erforderlich).

    ALTER DATABASE dbname SET DB_CHAINING ON;
yahor
quelle
Die Datenbank vertrauenswürdig zu machen, hat den Trick getan. Vielen Dank!
Mansfield
2
Warum nicht vorschlagen, die Prozedur in msdb zu erstellen? Dies scheint viel weniger Belichtung zu sein als von Ihnen empfohlen.
Aaron Bertrand
@AaronBertrand Ich möchte dem Endbenutzer keinen besonderen Zugriff auf msdb gewähren. Welche andere Belichtung gebe ich, indem ich die Datenbank vertrauenswürdig mache?
Mansfield
2
Sie können ihnen ziemlich sicher den Verbindungszugriff und die Rechte für genau dieses Verfahren gewähren. Ohne ausdrückliche Rechte werden sie sonst nicht viel tun können. @SebastianMeine hat eine großartige Serie geschrieben über TRUSTWORTHY: sqlity.net/de/1653/… sqlity.net/de/1701/… sqlity.net/de/1710/… - Die Baugruppenteile sind wahrscheinlich nicht relevant, überprüfen Sie jedoch auch diese KB- Unterstützung. microsoft.com/kb/2183687 & dba.stackexchange.com/a/25894/1186
Aaron Bertrand
@ AaronBertrand Aaron, du hast recht. Die Implementierung hängt stark davon ab, ob Sie "nicht vertrauenswürdigen" Benutzern das Recht einräumen, Objekte in einer vertrauenswürdigen Datenbank zu erstellen / ändern. In der Implementierung, mit der ich bisher gearbeitet habe, ist dies nicht der Fall, daher ist Ihr Kommentar sehr wertvoll.
yahor
0

Ich stimme voll und ganz zu, dass TRUSTWORTHY einem Ansatz nicht allzu vertrauenswürdig ist. Sie sollten einen anderen Weg wählen, um das gewünschte Ergebnis zu erzielen.

Ich habe kürzlich eine Möglichkeit veröffentlicht, einem anderen Benutzer oder einer Gruppe von Benutzern den Start eines SQL Agent-Jobs zu gewähren. Sie können es sehen bei:

Erlauben Sie Nicht-Sysadmin, Nicht-Eigentümer eines SQL Server-Agent-Jobs, ihn auszuführen

Die dritte Option, eine Sicherheitstabelle und eine gespeicherte Prozedur, bietet Ihnen die größte Flexibilität und die geringste Gefährdung.

RLF
quelle
-1

In SQL Server:

Gehen Sie einfach zu Sicherheit-> Schema-> dbo. Doppelklicken Sie auf dbo ... und klicken Sie dann auf die Registerkarte Berechtigung -> (blaue Schrift), um die Datenbankberechtigung anzuzeigen, und scrollen Sie nach den erforderlichen Feldern wie "Ausführen" mit der Auswahl .... und gewähren, mit gewähren oder Kontrollen verweigern .... hoffe, dies wird helfen

Suhail Mumtaz Awan
quelle
3
Dies beantwortet die Frage nicht.
Colin 't Hart