Sql server 从SQL Server Service broker使用SSIDB实现调用SSIS
要求是通过SSI调用web服务,并从SQL Server service Broker激活的存储过程调用SSI 以下是我目前正在做的事情: 排队 我的存储过程:Sql server 从SQL Server Service broker使用SSIDB实现调用SSIS,sql-server,ssis,service-broker,Sql Server,Ssis,Service Broker,要求是通过SSI调用web服务,并从SQL Server service Broker激活的存储过程调用SSI 以下是我目前正在做的事情: 排队 我的存储过程: ALTER PROCEDURE [schema].[usp_ProccessingQueueActivation] WITH EXECUTE AS CALLER AS BEGIN SET NOCOUNT ON; <snip declaration> BEGIN BEGIN TRAN
ALTER PROCEDURE [schema].[usp_ProccessingQueueActivation]
WITH EXECUTE AS CALLER
AS
BEGIN
SET NOCOUNT ON;
<snip declaration>
BEGIN
BEGIN TRANSACTION;
WAITFOR
(
RECEIVE TOP (1)
@ConversationHandle = conversation_handle,
@MessageBody = CAST(message_body AS XML),
@MessageTypeName = message_type_name
FROM [schema].[ProccessingQueue]
), TIMEOUT 5000;
<snip awasome stuff>
EXEC dbo.RunSSIS <param>
DECLARE @ReplyMessageBody XML = @MessageBody;
SEND ON CONVERSATION @ConversationHandle MESSAGE TYPE [type] (@ReplyMessageBody);
END
<handle error>
COMMIT TRANSACTION;
END
END
ALTER过程[schema]。[usp\u过程队列激活]
以EXECUTE作为调用方
作为
开始
不计数;
开始
开始交易;
等待
(
接收顶部(1)
@会话句柄=会话句柄,
@MessageBody=CAST(消息体为XML),
@MessageTypeName=消息类型名称
来自[schema]。[ProcessingQueue]
),超时5000;
EXEC dbo.RunSSIS
声明@ReplyMessageBody XML=@MessageBody;
会话发送@ConversationHandle消息类型[TYPE](@ReplyMessageBody);
结束
提交事务;
结束
结束
下面是RunSSIS存储过程的样子
ALTER PROCEDURE [dbo].[RunSSIS]
<params>
AS
BEGIN
DECLARE @exec_id BIGINT
EXEC [SSISDB].[catalog].[create_execution]
@package_name=N'<SSIS_package>',
@folder_name=N'<folder>',
@project_name=N'<projectName>',
@use32bitruntime=FALSE,
@reference_id=NULL,
@execution_id=@exec_id OUTPUT
EXEC [SSISDB].[catalog].[set_execution_parameter_value]
@exec_id,
@object_type=30,
@parameter_name=N'<param_Name>',
@parameter_value=<param>
SELECT @exec_id
EXEC [SSISDB].[catalog].[start_execution] @exec_id
END
ALTER过程[dbo].[RunSSIS]
作为
开始
声明@exec_id BIGINT
EXEC[SSISDB].[catalog].[create_execution]
@包名称=N“”,
@文件夹名称=N“”,
@项目名称=N“”,
@use32bitruntime=FALSE,
@reference_id=NULL,
@execution\u id=@exec\u id输出
EXEC[SSIDB].[catalog].[set\u execution\u parameter\u value]
@行政长官,
@对象类型=30,
@参数_name=N“”,
@参数值=
选择@exec\u id
EXEC[SSISDB].[catalog].[start\u execution]@EXEC\u id
结束
现在,这将在事件查看器中引发以下异常,因为在SSIDB环境中无法识别Sql service broker激活安全上下文
激活的进程
正在上运行的“[schema].[usp_ProcessingQueueActivation]”
队列“”将输出
以下内容:'无法还原当前安全上下文。请
切换到调用“执行为”的原始数据库,然后重试
再说一遍。”
为了解决这个问题,我尝试了以下方法
- 所以我关注这个链接
并创建了一个具有自签名证书的用户(认为
是没有权限的用户)。但它返回了同样的错误,
深入挖掘,我发现,[internal].[prepare\u execution]在
SSIDB在第36行中有“REVERT”语句,该语句将错误作为
它一点也不喜欢模仿
- 我尝试将RunSSIS存储过程移动到SSIDB,并尝试从激活存储过程调用它,但由于SSIDB不允许任何具有SQL Server身份验证的用户,它需要具有Windows身份验证,并且由证书创建的用户显然不具有Windows凭据,因此被击落
- 我走的路对吗?我当然不认为同时使用SQL server的两个组件会有那么困难李>
- 如果不是正确的方法,那么从ServiceBroker调用服务的最佳方法是什么?我已经看到了SQLServerServiceBroker的“外部激活”,但还没有探究它。但我会坚持使用服务器环境内部的可扩展组件,不喜欢在prod环境中安装不同的组件(这对于个人支持来说总是一种开销,因为还有一点可能会失败)
我正在使用Windows auth,并且我的凭据具有系统管理员权限。我认为您可以去掉“以调用方身份执行”,所有内容(进程以及最终被调用的包)都将在Service Broker的安全上下文下运行。只要该上下文具有执行您想执行的操作的权限,您就可以了
我没有以这种方式使用过Service Broker,但我对SQL代理启动的作业也做了同样的事情。只要代理的安全上下文具有procs/packages中所需的权限,一切都可以正常运行。我们在服务中使用网络帐户,因此所有服务也可以在服务器之间工作。这有一种紧密耦合的代码味道,我的第一反应是将队列、存放proc的DB和SSIS执行分离到PowerShell脚本中。让脚本从service broker获取消息,然后在不同的连接上调用SSISDB,而无需在存储过程中包装
[catalog].[create\u execution]
和[catalog].[set\u execution\u parameter\u value]
。您仍然可以直接从代理运行此脚本
如果其中一个组件移动到不同的服务器,如果某个组件在dev/QA中的名称不同,或者技术发生变化(例如Azure ServiceBus而不是Broker),这种方法在安全上下文方面为您提供了最大的灵活性。您还可以通过日志记录/监视获得创造性。这看起来更适合于查看代码签名是否有效?现在回答这个问题有点晚了,实际上我们已经放弃了从Sql service broker调用SSIS->webservice的整个过程,而是使用Sql CLR路由。为了保护呼叫安全,我们禁用匿名呼叫,并强制Windows登录,因为它是intranet站点,而且我们希望所有呼叫该站点的人都应该登录,这是可行的。但我仍然认为这是微软错失的一次机会,它实际上是从数据库创建了一个真正的基于推送事件的系统。为了记录,如果没有EXECUTE AS子句,跨数据库模块签名将无法从service broker激活过程中工作,而EXECUTE AS调用者将无法工作,它必须是某个特定的用户
ALTER PROCEDURE [dbo].[RunSSIS]
<params>
AS
BEGIN
DECLARE @exec_id BIGINT
EXEC [SSISDB].[catalog].[create_execution]
@package_name=N'<SSIS_package>',
@folder_name=N'<folder>',
@project_name=N'<projectName>',
@use32bitruntime=FALSE,
@reference_id=NULL,
@execution_id=@exec_id OUTPUT
EXEC [SSISDB].[catalog].[set_execution_parameter_value]
@exec_id,
@object_type=30,
@parameter_name=N'<param_Name>',
@parameter_value=<param>
SELECT @exec_id
EXEC [SSISDB].[catalog].[start_execution] @exec_id
END