Gọi sp_start_job từ một thủ tục được lưu trữ


8

Các nhà phát triển của chúng tôi cần có khả năng bắt đầu công việc SQL Server Agent từ mã .Net của họ. Tôi biết tôi có thể gọi msdb..sp_start_job để làm việc đó, nhưng tôi không muốn cấp cho tài khoản người dùng chung quyền truy cập trực tiếp để chạy công việc.

Điều tôi muốn làm là tạo một thủ tục được lưu trữ trong cơ sở dữ liệu của ứng dụng bằng cách sử dụng mệnh đề VỚI EXECUTE AS để mạo danh tài khoản proxy. Thủ tục như chúng tôi có là:

CREATE PROCEDURE dbo.StartAgentJob 
    WITH EXECUTE AS 'agentProxy'
AS
BEGIN
    EXEC msdb.dbo.sp_start_job N'RunThisJob';
END

Tuy nhiên, khi chúng tôi chạy cái này, chúng tôi nhận được thông báo sau:

The EXECUTE permission was denied on the object 'sp_start_job', database 'msdb', schema 'dbo'.

Có ý kiến ​​gì không? Đây có phải là cách tốt nhất để làm điều này trong SQL2005 không?


1
Giải quyết. Có ba phần cho giải pháp: chuỗi quyền sở hữu phải được bật trên máy chủ; người dùng được sử dụng trong câu lệnh EXECUTE AS phải là sa hoặc người dùng có quyền tương tự để chạy các công việc xp_sqlagent_ *; và công việc phải được sở hữu bởi cùng một người dùng như được liệt kê trong câu lệnh EXECUTE AS.
Ed Leighton-Dick

Một thử nghiệm nhỏ hơn cho thấy một biến thể của giải pháp này. Nếu bạn muốn sử dụng người dùng proxy không phải SA để chạy công việc, bạn có thể cấp cho người dùng proxy quyền EXECUTE trên các thủ tục xp_sqlagent_ * trong cơ sở dữ liệu chính. (Hai yêu cầu khác - quyền sở hữu cơ sở dữ liệu chéo và quyền sở hữu công việc - vẫn được áp dụng.)
Ed Leighton-Dick

Câu trả lời:


5

Bạn đã đặt thông tin đăng nhập agentProxy trong cơ sở dữ liệu msdb và cấp cho nó quyền chạy sp_start_job chưa? Nếu không, bạn sẽ cần phải kích hoạt quyền cơ sở dữ liệu cho cơ sở dữ liệu msdb và cơ sở dữ liệu người dùng của bạn.

Có lẽ tốt hơn hết là bạn nên đăng nhập vào cơ sở dữ liệu msdb và cấp cho nó quyền chính xác.


Có - Tôi đã bắt đầu bằng cách thêm nó vào vai trò SQLAgentOperator và sau đó thử các quyền EXECUTE trực tiếp trên chính sp_start_job. Không giúp được gì. Nó dường như ném lỗi này bất kể quyền của proxy - ngay cả tài khoản cấp sysadmin cũng không thành công.
Ed Leighton-Dick

Sử dụng SQL Profiler và xem tài khoản nào thực sự thực hiện cuộc gọi. Bây giờ tôi nghĩ về nó nhiều hơn, Execute As đang sử dụng một người dùng cơ sở dữ liệu, có lẽ không dịch ra cơ sở dữ liệu khác một cách chính xác. Hãy thử bật chuỗi cơ sở dữ liệu và xem nếu nó hoạt động.
mrdenny

Chuỗi quyền sở hữu là một phần lớn của giải pháp, vì vậy tôi đang trao giải cho các điểm ở đây. Nó cũng chỉ ra rằng có hai phần khác về điều này; Tôi sẽ lưu ý những điều ở trên.
Ed Leighton-Dick

8

Tôi rất vui vì bạn đã giải quyết vấn đề này, nhưng chuỗi sở hữu không phải là giải pháp được đề xuất. Vì bạn có vẻ quan tâm một cách hợp lệ về bảo mật và mức độ chi tiết phù hợp của các quyền liên quan, nên tôi thêm câu trả lời này, mặc dù muộn, như một tài liệu tham khảo về những gì đang xảy ra và cách giải quyết vấn đề này.

EXECUTE NHƯ phạm vi mạo danh

Các mệnh đề EXECUTE AS có hai loại: EXECUTE AS LOGIN và EXECUTE AS USER. EXECUTE AS LOGIN được xác thực bởi máy chủ và là bối cảnh mạo danh được tin cậy bởi toàn bộ phiên bản SQL (phạm vi máy chủ):

Khi mạo danh hiệu trưởng bằng cách sử dụng câu lệnh EXECUTE AS LOGIN hoặc trong mô-đun phạm vi máy chủ bằng cách sử dụng mệnh đề EXECUTE AS, phạm vi của mạo danh là toàn máy chủ. Điều này có nghĩa là sau khi chuyển đổi ngữ cảnh, bất kỳ tài nguyên nào trong máy chủ đăng nhập được mạo danh đều có quyền truy cập.

EXECUTE AS USER được xác thực bởi cơ sở dữ liệu và là bối cảnh mạo danh chỉ được cơ sở dữ liệu đó tin cậy (phạm vi cơ sở dữ liệu):

Tuy nhiên, khi mạo danh hiệu trưởng bằng cách sử dụng câu lệnh EXECUTE AS USER hoặc trong mô-đun phạm vi cơ sở dữ liệu bằng cách sử dụng mệnh đề EXECUTE AS, phạm vi mạo danh được giới hạn trong cơ sở dữ liệu theo mặc định. Điều này có nghĩa là các tham chiếu đến các đối tượng nằm ngoài phạm vi của cơ sở dữ liệu sẽ trả về lỗi.

Một thủ tục được lưu trữ có mệnh đề EXECUTE AS sẽ tạo ra một bối cảnh mạo danh phạm vi cơ sở dữ liệu và do đó sẽ không thể tham chiếu các đối tượng bên ngoài cơ sở dữ liệu, trong trường hợp bạn sẽ không thể tham chiếu msdb.dbo.sp_start_jobvì trong đó msdb. Có nhiều ví dụ khác có sẵn, như cố gắng truy cập DMV phạm vi máy chủ, cố gắng sử dụng máy chủ được liên kết hoặc cố gắng gửi thông điệp Nhà môi giới dịch vụ vào cơ sở dữ liệu khác.

Việc cho phép một cơ sở dữ liệu phạm vi mạo danh để truy cập vào một tài nguyên thường không được phép xác thực của bối cảnh mạo danh phải được tin cậy. Đối với một cơ sở dữ liệu phạm vi mạo danh, trình xác thực là cơ sở dữ liệu dbo. Điều này có thể đạt được bằng hai phương tiện có thể:

  • Bằng cách bật thuộc tính TRUSTWORTHY trên cơ sở dữ liệu đã xác thực bối cảnh mạo danh (ví dụ: cơ sở dữ liệu có mệnh đề EXECUTE AS được ban hành).
  • Bằng cách sử dụng chữ ký mã.

Các chi tiết này được mô tả trong MSDN: Mở rộng mạo danh cơ sở dữ liệu bằng cách sử dụng EXECUTE AS .

Khi bạn giải quyết vấn đề thông qua chuỗi sở hữu cơ sở dữ liệu chéo, bạn đã kích hoạt chuỗi liên kết chéo ở toàn bộ cấp độ máy chủ, được coi là rủi ro bảo mật. Cách kiểm soát tốt nhất, chi tiết hơn để đạt được kết quả mong muốn là sử dụng ký mã:

  • Trong cơ sở dữ liệu ứng dụng tạo chứng chỉ tự ký
  • ký tên dbo.StartAgentJobvới chứng chỉ này
  • đánh rơi khóa riêng của chứng chỉ
  • xuất chứng chỉ ra đĩa
  • nhập chứng chỉ vào msdb
  • tạo người dùng xuất phát từ chứng chỉ đã nhập trong msdb
  • cấp quyền AUTHENTICATE cho người dùng dẫn xuất trong msdb

Các bước này đảm bảo rằng bối cảnh EXECUTE AS của dbo.StartAgentJobthủ tục hiện được tin cậy msdb, bởi vì bối cảnh được ký bởi một hiệu trưởng có sự cho phép AUTHENTICATE msdb. Điều này giải quyết một nửa câu đố. Nửa còn lại là thực sự cấp quyền EXECUTE cho msdb.dbo.sp_start_jobbối cảnh mạo danh đáng tin cậy hiện nay. Có một số cách có thể được thực hiện:

  1. ánh xạ người dùng mạo nhận agentProxyngười dùng trong msdbvà cấp cho ông thực thi điều khoản trênmsdb.dbo.sp_start_job
  2. cấp quyền thực thi cho msdbngười dùng chứng chỉ dẫn xuất
  3. thêm chữ ký mới vào thủ tục, tạo ra một người dùng cho nó msdbvà cấp quyền thực thi cho người dùng dẫn xuất này

Tùy chọn 1. đơn giản, nhưng có một nhược điểm lớn: agentProxyngười dùng hiện có thể thực hiện msdb.dbo.sp_start_jobtheo ý mình, anh ta thực sự được cấp quyền truy cập msdbvà có quyền thực thi.

Lựa chọn 3 là đúng đắn, nhưng tôi cảm thấy không cần thiết quá mức.

Vì vậy, ưu tiên của tôi là Tùy chọn 2: cấp quyền EXECUTE cho msdb.dbo.sp_start_jobngười dùng xuất phát chứng chỉ được tạo trong msdb.

Đây là SQL tương ứng:

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

Blog của tôi có một số bài viết về chủ đề này, được viết trong bối cảnh các quy trình được kích hoạt của Nhà môi giới dịch vụ (vì chúng yêu cầu một điều khoản EXECUTE AS):

BTW, nếu bạn đang cố kiểm tra kịch bản của tôi và bạn sống ở bán cầu đông hoặc vào mùa hè ở Vương quốc Anh, chắc chắn đọc bài viết cuối cùng mà tôi đã liên kết trước khi thử nghiệm.


0

Vì bạn đang cố gắng khởi động SQL Server Agent từ mã .NET, đây có thể là một câu hỏi tốt hơn cho StackOverflow?

http://www.stackoverflow.com


1
Tôi nghĩ rằng đây có thể là một vấn đề bảo mật cơ sở dữ liệu, nhưng tôi sẽ thử StackOverflow nếu chúng tôi không thể tìm thấy câu trả lời ở đây.
Ed Leighton-Dick

0

Kiểm tra một Trường hợp SQL ngẫu nhiên trên mạng SQLAgentOperatorRole không cung cấp cho bạn các quyền riêng tư sp_start_job, nó thừa hưởng chúng từ SQLAgentUserRole.

Kiểm tra lại bằng cách sử dụng:

select dp.NAME AS principal_name,
                 dp.type_desc AS principal_type_desc,
                 o.NAME AS object_name,
                 p.permission_name,
                 p.state_desc AS permission_state_desc 
    from    sys.database_permissions p
    left    OUTER JOIN sys.all_objects o on p.major_id = o.OBJECT_ID
    inner   JOIN sys.database_principals dp on p.grantee_principal_id = dp.principal_id
    where o.name = 'sp_start_job'

Chạy cái này trong MSDB và kiểm tra kỹ xem bạn không được thừa hưởng bất kỳ quyền truy cập từ chối rõ ràng nào.

hth


Người dùng rõ ràng là một thành viên của SQLAgentOperatorRole và SQLAgentUserRole.
Ed Leighton-Dick

0

Một cách để đạt được điều này mà không cần cấp quyền bổ sung: không để cho Proc được lưu trữ bắt đầu công việc trực tiếp mà chỉ cho phép các Proc được lưu trữ lật một chút trong bảng (trong cơ sở dữ liệu ứng dụng); sau đó, để công việc chạy mỗi phút hoặc lâu hơn, kiểm tra xem bit có bị lật hay không và nếu có, hãy thực hiện công việc và lật lại bit một lần nữa. Nếu công việc thấy bit không bị lật, công việc sẽ thoát.

Hoạt động như một cơ duyên, nếu bạn không ngại sự chậm trễ (và công việc chạy rất thường xuyên).

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.