Je dois autoriser un utilisateur à lancer un travail d'agent spécifique sans avoir la possibilité d'en démarrer d'autres. Pour ce faire, j'ai créé la procédure suivante (simplifiée):
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
Cependant, lorsque j'appelle cette procédure (après avoir vérifié qu'elle s'exécute via "sysadminaccount"), j'obtiens le message d'erreur suivant:
Msg 229, niveau 14, état 5, procédure sp_start_job, ligne 1 L'autorisation EXECUTE a été refusée sur l'objet 'sp_start_job', base de données 'msdb', schéma 'dbo'.
Le compte est membre du rôle sysadmin, donc je comprends qu'il ne devrait pas y avoir de problèmes pour démarrer des emplois. J'ai vérifié qu'il est membre des trois rôles sqlagent dans msdb, et ces rôles ont tous une autorisation d'exécution sur sp_start_job
.
Comment puis-je donner à ce compte les autorisations appropriées? Y a-t-il autre chose à faire à cause de l'emprunt d'identité?
Je n'aime pas l'option TRUSTWORTHY
car elle augmente considérablement votre exposition à une variété de choses. Comme Remus l'explique dans cette réponse , cela élève essentiellement tout db_owner
à sysadmin
. Certaines autres choses qui valent la peine d'être lues sont une série sur TRUSTWORTHY
par Sebastian Meine , la rubrique BOL et un article de la base de connaissances (même si les portions d'assemblage peuvent ne pas vous concerner dans ce scénario) :
(Et il y a des tonnes d'autres messages qui mettent en garde contre l'utilisation aveugle de cette propriété - ce n'est pas parce que cela fonctionne et que c'est facile que c'est la bonne chose à faire - en fait, cela devrait vous inciter à le remettre en question encore plus.) Je suggère donc une approche différente (et il y en a encore d'autres, comme la signature avec un certificat, mais cela a toujours fonctionné pour moi):
msdb
.Créez un utilisateur pour la connexion de cet utilisateur dans msdb
:
USE msdb;
GO
CREATE USER floobarama FROM LOGIN floobarama;
Accordez à l'utilisateur des privilèges d'exécution sur la procédure stockée:
GRANT EXECUTE ON [dbo].[RunJob] TO floobarama;
Testez-le - soit en appelant la procédure à partir d'une autre base de données:
USE tempdb;
GO
EXECUTE AS LOGIN = N'floobarama';
GO
EXEC msdb.dbo.RunJob @job_name = N'whatever';
GO
REVERT;
Ou un test plus simple, au cas où vous ne voudriez exécuter aucune tâche maintenant et ne voudriez pas attendre que cet utilisateur l'exécute pour savoir s'il a un accès suffisant à 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;
Le résultat doit être:
I am really...
---------------
sysadminaccount
Validez que cela n'expose rien d'autre dans msdb
à cet utilisateur:
USE tempdb;
GO
EXECUTE AS LOGIN = N'floobarama';
GO
SELECT job_id FROM msdb.dbo.sysjobs;
GO
REVERT;
Le résultat devrait être ...
Msg 229, niveau 14, état 5, ligne 21
L'autorisation SELECT a été refusée sur l'objet 'sysjobs', base de données 'msdb', schéma 'dbo'.
... puisque la création d'un utilisateur dans une base de données ne leur donne pas de droits automatiques sur quoi que ce soit dans cette base de données; vous devez le faire explicitement soit pour cet utilisateur, soit pour un rôle ou un groupe dans lequel il se trouve (y compris public
).
Je ne peux pas commenter car je n'ai pas assez de points, alors écrivez la réponse. On dirait que c'est un problème de chaînage de propriété de base de données croisée. Si cette procédure est créée en dehors de msdb, elle n'a aucun accès aux objets de la base de données référencée, même si "EXECUTE AS" emprunte l'identité de l'utilisateur en tant que membre du rôle sysadmin.
La solution la plus probable est donc:
Rendez votre base de données TRUSWORTHY:
ALTER DATABASE dbname SET TRUSTWORTHY ON;
Activer le chaînage de propriété croisée de la base de données (peut ne pas être nécessaire)
ALTER DATABASE dbname SET DB_CHAINING ON;
Je suis totalement d'accord avec le fait que TRUSTWORTHY n'est pas du tout digne de confiance d'une approche. Vous devez choisir une autre façon d'obtenir le résultat dont vous avez besoin.
J'ai récemment publié un moyen d'accorder le démarrage d'un travail d'agent SQL à un autre utilisateur ou groupe d'utilisateurs. Vous pouvez le voir sur:
La troisième option, une table de sécurité et une procédure stockée, vous offre le plus de flexibilité et le moins d'exposition.