Fico feliz por você ter resolvido isso, mas o encadeamento de propriedade não é a solução recomendada. Como você parece validamente preocupado com a segurança e a granularidade adequada dos direitos envolvidos, estou adicionando essa resposta, embora atrasada, como uma referência ao que está acontecendo e como resolver esses problemas.
EXECUTAR como escopo de representação
As cláusulas EXECUTE AS vêm em dois tipos: EXECUTE AS LOGIN e EXECUTE AS USER. O EXECUTE AS LOGIN é autenticado pelo servidor e é um contexto de representação confiável por toda a instância do SQL (com escopo no servidor):
When impersonating a principal by
using the EXECUTE AS LOGIN statement,
or within a server-scoped module by
using the EXECUTE AS clause, the scope
of the impersonation is server-wide.
This means that after the context
switch, any resource within the server
that the impersonated login has
permissions on can be accessed.
EXECUTAR COMO O USUÁRIO é autenticado pelo banco de dados e é um contexto de representação confiável somente por esse banco de dados (escopo do banco de dados):
However, when impersonating a
principal by using the EXECUTE AS USER
statement, or within a database-scoped
module by using the EXECUTE AS clause,
the scope of impersonation is
restricted to the database by default.
This means that references to objects
outside the scope of the database will
return an error.
Um procedimento armazenado que tenha uma cláusula EXECUTE AS criará um contexto de representação com escopo de banco de dados e, como tal, não poderá referenciar objetos fora do banco de dados. Caso contrário, você não poderá referenciar msdb.dbo.sp_start_job
porque está em %código%. Há muitos outros exemplos disponíveis, como tentar acessar um DMV de escopo de servidor, tentar usar um servidor vinculado ou tentar entregar uma mensagem do Service Broker em outro banco de dados.
A habilitação de uma representação com escopo de banco de dados para acessar um recurso que normalmente não permitiria que o autenticador do contexto de representação fosse confiável. Para uma representação com escopo de banco de dados, o autenticador é o banco de dados dbo. Isto pode ser conseguido por dois meios possíveis:
- Ao ativar a propriedade TRUSTWORTHY no banco de dados que autenticou o contexto de representação (isto é, o banco de dados no qual a cláusula EXECUTE AS foi emitida).
- Usando assinaturas de código.
Esses detalhes são descritos no MSDN: Estendendo a representação de banco de dados usando EXECUTE AS .
Quando você resolveu o problema por meio do encadeamento de propriedade entre bancos de dados, ativou o encadeamento entre bancos de dados em todo o nível do servidor, o que é considerado um risco de segurança. A maneira mais controlada e refinada para obter o resultado desejado é usar a assinatura de código:
- No banco de dados do aplicativo, crie um certificado auto-assinado
- assine o
msdb
com este certificado
- largar a chave privada do certificado
- exporte o certificado para o disco
- importe o certificado para
dbo.StartAgentJob
- crie um usuário derivado do certificado importado em
msdb
- conceda permissão AUTHENTICATE ao usuário derivado em
msdb
Essas etapas garantem que o contexto EXECUTE AS do procedimento msdb
seja agora confiável em dbo.StartAgentJob
, porque o contexto é assinado por uma entidade com permissão AUTHENTICATE em msdb
. Isso resolve metade do quebra-cabeça. A outra metade é conceder a permissão EXECUTE em msdb
ao contexto de representação agora confiável. Existem várias maneiras de como isso pode ser feito:
- mapeie o usuário representado
msdb.dbo.sp_start_job
usuário em agentProxy
e conceda a ele permissão de execução em msdb
- conceda a permissão de execução ao usuário derivado do certificado
msdb.dbo.sp_start_job
authenticator
- adicione uma nova assinatura ao procedimento, deduza um usuário para ele em
msdb
e conceda a permissão de execução a esse usuário derivado
A opção 1. é simples, mas tem uma grande desvantagem: o usuário msdb
agora pode executar o agentProxy
por sua própria vontade, ele realmente recebe acesso a msdb.dbo.sp_start_job
e tem permissão de execução.
A opção 3 é positivamente correta, mas eu sinto que é um exagero desnecessário.
Portanto, minha opção preferida é a Opção 2: conceda a permissão EXECUTE em msdb
ao usuário derivado do certificado criado em msdb.dbo.sp_start_job
.
Aqui está o SQL correspondente:
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
Meu blog tem alguns artigos sobre esse tópico, escritos no contexto de procedimentos ativados pelo Service Broker (já que eles exigem uma cláusula EXECUTE AS):
BTW, se você estiver tentando testar meu roteiro e morar no hemisfério oriental, ou no horário de verão do Reino Unido, leia definitivamente esse último artigo que eu vinculei antes do teste.