I create a job. I add a single step with the following code:
insert joblog select getdate(),SUSER_NAME(),current_user
exec msdb.dbo.sp_send_dbmail ...
The job's owner is sa
. I, as a dev, do not have sa access, but I do have sysadmin.
So I change the job's owner to sa
.
The job runs fine and the email gets sent. The [joblog] table which I have created to help me understand things shows
suser_name=NT SERVICE\SQLSERVERAGENT
current_user=dbo
Now if I go to the agent's UI, edit the (single) job step, choose page "advanced", and fill the "Run as user" to "dbo", I receive EXECUTE denied on sp_send_dbmail. [joblog] gets one line with
susername=sa
current_user=dbo
What is the reason for the error? sa
obviously can run the proc. Not only that; NT SERVICE\SQLSERVERAGENT
also can!
My wild guess is that despite the suser_name inserted in my table, the "run as user" "chooses" dbo as a user in the target db but without any login associated with it, not even NT SERVICE\SQLSERVERAGENT
.
When impersonating a USER
, in this case dbo
, then any external database references will fail. A USER
is a database object, and so your impersonation is limited to being scoped within the database. As you are attempting to reference msdb.dbo.sp_send_dbmail
you are, presumably, using 3 part naming as your aren't in msdb
(which I wouldn't expect you do, as you are INSERT
ing into a table, and that shouldn't really be done in a system database).
As for why you get sa
, that's because that's the LOGIN
that the dbo
USER
is linked to. If the dbo
user was linked to a different LOGIN
you would get a different LOGIN
's name. This does not, however, mean that you can impersonate that LOGIN
by impersonating a USER
; you strictly cannot do this. As the OP mentions is the comments, this is documented.
The "fix" would be that if you need impersonation, you impersonate a LOGIN
, not a USER
, that has access to all the databases you need to access for the specific job.