THE SQL Server Blog Spot on the Web

Welcome to SQLblog.com - The SQL Server blog spot on the web Sign in | Join | Help
in Search

Tibor Karaszi

SQL Server Agent jobs and user contexts

In what user context does a job run? I recently found myself in a forum discussion and gave my stock reply, later realizing that I haven't actually tested this for a long time (I used to demo this in class during 6.5 courses - when we actually had time for slight diversions). Lets start with my assumptions:

  1. Job owned by sysadmin, TSQL jobsteps:
    Agent log in to SQL Server using its own credential (windows authentication from service account) and execute the TSQL commands - no impersonation performed.
  2. Job owned by sysadmin, other jobsteps:
    Agent starts a process using its service account - no impersonation performed.
  3. Job owned by non-sysadmin, TSQL jobstep:
    Agent log in to SQL Server using its own credential (windows authentication from service account), then uses EXECUTE AS LOGIN = '<job_owner_login>' to "impersonate" the login who owns the job. I.e., the TSQL commands will be executed in the security context of the job owner's login.
  4. Job owned by non-sysadmin, other jobsteps:
    Agent starts a process using the service account as specified by the Agent proxy selected for this jobstep. (See Books Online "sp_add_proxy" and "CREATE CREDENTIAL" and this for more information about Agent Proxies and credentials in SQL Server.)

So, how to prove above? Lets use a combination of jobstep output file and a Profiler trace. The ouput files will be used to catch the login/user names, and the Profiler trace to verify what TSQL commands will be submitted by Agent (for TSQL jobstep). For the TSQL jobsteps, we execute:

SET NOCOUNT ON
SELECT 
 
CAST(ORIGINAL_LOGIN() AS VARCHAR(20)) AS Original_login
,
CAST(SUSER_SNAME() AS VARCHAR(20)) AS Effective_login
,
CAST(USER_NAME() AS VARCHAR(20)) AS Db_user
 

And to test the other jobsteps, where we will be using a CmdExec jobstep as example (we are interested in what Windows account the process will be started as), and use whoami.exe which returns the windows user name. Each jobstep is configured to output the result to a file.

  • I change my real machine name to "Machine" in this text.
  • I'm not in a domain.
  • I'm logged in interactively (to Windows) as Windows account "Tibor".
  • I'm logged in to SQL Server using Windows authentication.
  • I'm sysadmin.
  • My service account for both Agent and SQL Server services is "SQLService".

Here's the result from having the job owned by me (being sysadmin):

Original_login       Effective_login       Db_user            
-------------------- -------------------- --------------------
MACHINE\SqlService   MACHINE\SqlService   dbo

machine\sqlservice

As you see, no attempted impersonation performed. Steps 1 - 2 in above list confirmed.

We now going to test this for somebody who isn't sysadmin:

  • Create SQL Server login named "Kalle"
  • Create user in msdb for above
  • Assign Kalle permission to create jobs (SQLAgentUser role in msdb)
  • Create account "MySqlProxy" in Windows.
  • Creade credential "c_MySqlProxy" in SQL Server for above.
  • Create proxy "p_MySqlProxy" for above, and allow login "Kalle" to use this for CmdExec jobsteps.

Now we modify the job and set the owner to Kalle, and also specify for the CmdExec jobstep to use the proxy p_MySqlProxy. Also, since non-sysadmins can't use output files (I didn't know that), we instead configure each step's output to go to table. Execute job. No, finally we can check each job step output for result:

Original_login       Effective_login       Db_user            
-------------------- -------------------- --------------------
MACHINE\SqlService   Kalle                guest

machine\mysqlproxy

The first section above confirms that Agent uses it's own login, but then changes login context to Kalle (verified by Profiler trace capturing the "EXECUTE AS LOGIN = N'Kalle' WITH NO REVERT" command). The job step was configured to run in the master database; since I didn't add Kalle as a user to master, you see the user name guest.

The second section verifies that The CmdExec step started a process using the mysqlproxy windows account, and specified using our SQL Server Agent Proxy and SQL Server credential object.

(I will not reply to support questions here. For support, I recommend you visit a forum, for instance this. Other discussions, comments and corrections are of course very welcome!)

Finally, I scripted out the job (as owned by me - being sysadmin), if you want to re-create it and play with it. Use at own risk, do apropriate modifications etc.

USE [msdb]
GO

/****** Object:  Job [CredTest]    Script Date: 09/19/2009 12:12:47 ******/
BEGIN TRANSACTION
DECLARE 
@ReturnCode INT
SELECT 
@ReturnCode 0
/****** Object:  JobCategory [[Uncategorized (Local)]]]    Script Date: 09/19/2009 12:12:47 ******/
IF NOT EXISTS (SELECT name FROM msdb.dbo.syscategories WHERE name=N'[Uncategorized (Local)]' AND category_class=1)
BEGIN
EXEC 
@ReturnCode msdb.dbo.sp_add_category @class=N'JOB'@type=N'LOCAL'@name=N'[Uncategorized (Local)]'
IF (@@ERROR <> OR @ReturnCode <> 0GOTO QuitWithRollback

END

DECLARE 
@jobId BINARY(16)
EXEC @ReturnCode =  msdb.dbo.sp_add_job @job_name=N'CredTest'
       
@enabled=1
       
@notify_level_eventlog=0
       
@notify_level_email=0
       
@notify_level_netsend=0
       
@notify_level_page=0
       
@delete_level=0
       
@description=N'No description available.'
       
@category_name=N'[Uncategorized (Local)]'
       
@owner_login_name=N'MACHINE\Tibor'@job_id @jobId OUTPUT
IF (@@ERROR <> OR @ReturnCode <> 0GOTO QuitWithRollback
/****** Object:  Step [A_TSQL]    Script Date: 09/19/2009 12:12:48 ******/
EXEC @ReturnCode msdb.dbo.sp_add_jobstep @job_id=@jobId@step_name=N'A_TSQL'
       
@step_id=1
       
@cmdexec_success_code=0
       
@on_success_action=3
       
@on_success_step_id=0
       
@on_fail_action=2
       
@on_fail_step_id=0
       
@retry_attempts=0
       
@retry_interval=0
       
@os_run_priority=0@subsystem=N'TSQL'
       
@command=N'SET NOCOUNT ON 
SELECT  
 CAST(ORIGINAL_LOGIN() AS VARCHAR(20)) AS Original_login
,CAST(SUSER_SNAME() AS VARCHAR(20)) AS Effective_user
,CAST(USER_NAME() AS VARCHAR(20)) AS Db_user'

       
@database_name=N'master'
       
@flags=8
IF (@@ERROR <> OR @ReturnCode <> 0GOTO QuitWithRollback
/****** Object:  Step [B_OS]    Script Date: 09/19/2009 12:12:48 ******/
EXEC @ReturnCode msdb.dbo.sp_add_jobstep @job_id=@jobId@step_name=N'B_OS'
       
@step_id=2
       
@cmdexec_success_code=0
       
@on_success_action=1
       
@on_success_step_id=0
       
@on_fail_action=2
       
@on_fail_step_id=0
       
@retry_attempts=0
       
@retry_interval=0
       
@os_run_priority=0@subsystem=N'CmdExec'
       
@command=N'whoami.exe'
       
@flags=16
IF (@@ERROR <> OR @ReturnCode <> 0GOTO QuitWithRollback
EXEC @ReturnCode msdb.dbo.sp_update_job @job_id @jobId@start_step_id 1
IF (@@ERROR <> OR @ReturnCode <> 0GOTO QuitWithRollback
EXEC @ReturnCode msdb.dbo.sp_add_jobserver @job_id @jobId@server_name N'(local)'
IF (@@ERROR <> OR @ReturnCode <> 0GOTO QuitWithRollback
COMMIT TRANSACTION
GOTO 
EndSave
QuitWithRollback:
    
IF (@@TRANCOUNT 0ROLLBACK TRANSACTION
EndSave:

GO
Published Saturday, September 19, 2009 11:57 AM by TiborKaraszi

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

 

SQL Server said:

In what user context does a job run? I recently found myself in a forum discussion and gave my stock

September 19, 2009 6:27 AM
 

Twitter Trackbacks for Tibor Karaszi : SQL Server Agent jobs and user contexts [sqlblog.com] on Topsy.com said:

September 19, 2009 6:54 AM
 

Andy said:

A helpful summary. For the testing of the CmdExec / XP_Cmdshell, I find that running the following is helpful to determine the context that you are running in.

Net Config Workstation

We normally have these issues and then throw some linked servers into the equation which gets us really confused.

February 10, 2010 12:51 PM
 

TiborKaraszi said:

Good tip, Andy. Thanks.

February 11, 2010 2:38 AM
 

Microsoft – SQLServer – Database Job Failed – ‘EXECUTE AS LOGIN’ failed for the requested login | Daniel Adeniji's Trail said:

July 19, 2011 4:14 PM
 

Kishore Surana said:

Hi Tibor, thanks a lot for this blog!!!. This is the first blog which I have run into which exactly details how the SQL job is executed when the job owner is not sysadmin. I have a requirement where a job owner (who is not sysadmin) should be able to access linked server, but I am finding that it doesnt work... I will really appreciate if you can provide some tips... I am stuck in this for a week now without success....

I have an user who is a member of SQLAgentUserRole in a SQL instance on SQL Server 2008 R2 SQL server. As per my requirement, this SQLAgentUserRole should be able to create SQL jobs and execute a query with linked server in the SQL job( see linked server - ServerLink  as in query below):

select top 10 * from ServerLink.DBTest.dbo.OnlineFact

But if the SQLAgentUserRole user creates a SQL job, and executes the above query(containing the linked server) the SQL job fails with error (see error message below). I investigated the issue and find that a “SQLAgentUserRole member cannot execute linked server query in SQL job” is by design as per this this MSDN KB Article http://support.microsoft.com/kb/811031 . I do not want to grant Operating System Command using a SQL Proxy for  SQLAgentUserRole members as listed as workAround in the MSDN KB Article. What are my options in order to enable a SQLAgentUserRole query linked servers in the SQL job?

Error Message 1

Executed as user: <domain>\<user>. Shared Memory Provider: Either a required impersonation level was not provided, or the provided impersonation level is invalid. [SQLSTATE 42000] (Error 1346)  OLE DB provider "SQLNCLI10" for linked server "ServerLink" returned message "Unspecified error". [SQLSTATE 01000] (Error 7412)  OLE DB provider "SQLNCLI10" for linked server "ServerLink" returned message "Communication link failure". [SQLSTATE 01000] (Error 7412)  OLE DB provider "SQLNCLI10" for linked server "ServerLink" returned message "Communication link failure". [SQLSTATE 01000] (Error 7412)  OLE DB provider "SQLNCLI10" for linked server "ServerLink" returned message "Communication link failure". [SQLSTATE 01000] (Error 7412).  The step failed.

Error Message 2 - I get this error message sometimes as well.

Executed as user: <domain>\<user>. SQL Server Network Interfaces: Error getting enabled protocols list from registry [xFFFFFFFF]. [SQLSTATE 42000] (Error 65535)  OLE DB provider "SQLNCLI10" for linked server "ServerLink" returned message "Login timeout expired". [SQLSTATE 01000] (Error 7412)  OLE DB provider "SQLNCLI10" for linked server "ServerLink" returned message "A network-related or instance-specific error has occurred while establishing a connection to SQL Server. Server is not found or not accessible. Check if instance name is correct and if SQL Server is configured to allow remote connections. For more information see SQL Server Books Online.". [SQLSTATE 01000] (Error 7412).  The step failed.

Items I have tried unsuccessfully:

1. OPENQUERY also uses a LINKED SERVER, but as I detail in my original problem, the SQLAgentUserRole user is unable to query a LINKED SERVER in a SQL job. Hence the OPENQUERY execution using LINKED SERVER fails.

2. I have tried EXECUTE AS CALLER, SELF, OWNER and a SPECIFIC LOGIN. None of these work.

3. I also tried setting the "Run AS" option in the SQL Job Step Advanced Section, but that didnt help as well.

4. It is almost the SQL JOB owner's credentials is unable to pass over when trying to "reach/recognize" the linked server just locally. I also tried the SECURITY impersonation in linked server, but it looks like the issue is when just trying to reach the linked server locally, and not connecting to the linked server yet.

Note:

1. The SQL job owner is a sysadmin in the target server of the link server connection. Therefore SQL job owner already has permissions to access the target  server of the link server connection. The issue seems that the SQL Job Owner's credentials do not propagated when reaching the linked server, and hence the network protocols issue (see error message #2).

2. Also, currently when I build the Credential for a Proxy, I provide the same account as the job owner, to build the SQL credential. Using this proxy/credential, I can get the SQL job to work. This implementation where the Credential for the Proxy is the same account as the job owner proves that the SQL job owner can connect to the linked server, if the job owner's credentials is correctly passed by SQL server when accessing the linked server.

February 8, 2012 9:55 AM

Leave a Comment

(required) 
(optional)
(required) 
Submit
Powered by Community Server (Commercial Edition), by Telligent Systems
  Privacy Statement