Memanggil sp_start_job dari prosedur tersimpan

8

Pengembang kami harus dapat memulai pekerjaan SQL Server Agent dari kode .Net mereka. Saya tahu saya dapat memanggil msdb..sp_start_job untuk melakukan hal itu, tetapi saya tidak ingin memberikan akses langsung ke akun pengguna umum untuk menjalankan pekerjaan.

Yang ingin saya lakukan adalah membuat prosedur tersimpan dalam database aplikasi menggunakan klausa WITH EXECUTE AS untuk menyamar sebagai akun proxy. Prosedur yang kita miliki adalah:

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

Ketika kami menjalankan ini, kami mendapat pesan berikut:

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

Ada ide? Apakah ini bahkan cara terbaik untuk melakukan ini di SQL2005?

Ed Leighton-Dick
sumber
1
Terpecahkan. Ada tiga bagian dari solusinya: rantai kepemilikan harus diaktifkan di server; pengguna yang digunakan dalam pernyataan EXECUTE AS harus sa atau pengguna dengan izin serupa untuk menjalankan pekerjaan xp_sqlagent_ *; dan pekerjaan itu harus dimiliki oleh pengguna yang sama seperti yang tercantum dalam pernyataan EXECUTE AS.
Ed Leighton-Dick
Eksperimen sedikit lebih menunjukkan satu variasi untuk solusi ini. Jika Anda ingin menggunakan pengguna proxy non-SA untuk menjalankan pekerjaan, Anda dapat memberikan izin kepada pengguna proxy EXECUTE pada prosedur xp_sqlagent_ * di database master. (Dua persyaratan lainnya - kepemilikan lintas basis data dan kepemilikan pekerjaan - masih berlaku.)
Ed Leighton-Dick

Jawaban:

5

Sudahkah Anda memasukkan login agentProxy ke dalam database msdb dan memberikannya hak untuk menjalankan sp_start_job? Jika tidak, Anda harus mengaktifkan perijinan izin basis data untuk basis data msdb dan basis data pengguna Anda.

Anda mungkin lebih baik memasukkan login ke dalam database msdb dan memberikannya hak yang benar.

mrdenny
sumber
Ya - Saya mulai dengan menambahkannya ke peran SQLAgentOperator dan kemudian mencoba izin EXECUTE langsung pada sp_start_job itu sendiri. Tidak ada yang membantu. Tampaknya melemparkan kesalahan ini terlepas dari izin proksi - bahkan akun tingkat sysadmin gagal.
Ed Leighton-Dick
Gunakan SQL Profiler dan lihat akun apa yang sebenarnya membuat panggilan. Sekarang saya lebih memikirkannya, Execute As menggunakan pengguna basis data, yang mungkin tidak menerjemahkan dengan benar ke basis data lain. Coba aktifkan perangkaian basis data dan lihat apakah itu berhasil.
mrdenny
Rantai kepemilikan adalah bagian besar dari solusi, jadi saya memberikan poin di sini. Ternyata juga ada dua bagian lain untuk ini; Saya akan perhatikan yang di atas.
Ed Leighton-Dick
8

Saya senang Anda menyelesaikan ini, tetapi kepemilikan rantai bukan solusi yang disarankan. Karena Anda tampaknya benar-benar khawatir tentang keamanan dan rincian hak yang terlibat, saya menambahkan balasan ini, meskipun terlambat, sebagai referensi untuk apa yang terjadi dan bagaimana menyelesaikan masalah ini.

EXECUTE AS lingkup peniruan

Klausa EXECUTE AS datang dalam dua rasa: EXECUTE AS LOGIN dan EXECUTE AS USER. EXECUTE AS LOGIN diautentikasi oleh server dan merupakan konteks peniruan yang dipercaya oleh seluruh instance SQL (lingkup server):

Saat menyamar sebagai prinsipal dengan menggunakan pernyataan EXECUTE AS LOGIN, atau dalam modul lingkup server dengan menggunakan klausa EXECUTE AS, ruang lingkup peniruannya adalah di seluruh server. Ini berarti bahwa setelah konteks beralih, sumber daya apa pun dalam server tempat login yang ditiru memiliki izin dapat diakses.

EXECUTE AS USER diautentikasi oleh database dan merupakan konteks peniruan yang hanya dipercaya oleh database tersebut (lingkup-database):

Namun, ketika menyamar sebagai prinsipal dengan menggunakan pernyataan EXECUTE AS USER, atau dalam modul lingkup-database dengan menggunakan klausa EXECUTE AS, ruang lingkup peniruan dibatasi untuk database secara default. Ini berarti bahwa referensi ke objek di luar lingkup basis data akan menghasilkan kesalahan.

Prosedur tersimpan yang memiliki klausa EXECUTE AS akan membuat konteks peniruan cakupan yang dilingkupi oleh basis data, dan dengan demikian tidak akan dapat merujuk objek di luar basis data, jika Anda tidak dapat merujuk msdb.dbo.sp_start_jobkarena ada di msdb. Ada banyak contoh lain yang tersedia, seperti mencoba mengakses ruang lingkup DMV server, mencoba menggunakan server tertaut atau mencoba untuk mengirimkan pesan Broker Layanan ke dalam basis data lain.

Memungkinkan peniruan cakupan database untuk mengakses sumber daya yang biasanya tidak diizinkan autentikator dari konteks peniruan harus dipercaya. Untuk peniruan cakupan dengan basis data, authenticator adalah basis data dbo. Ini dapat dicapai dengan dua cara yang mungkin:

  • Dengan mengaktifkan properti TRUSTWORTHY pada database yang mengotentikasi konteks peniruan (mis. Database tempat klausa EXECUTE AS dikeluarkan).
  • Dengan menggunakan tanda tangan kode.

Rincian ini dijelaskan dalam MSDN: Memperluas Peniruan Database dengan Menggunakan EXECUTE AS .

Ketika Anda menyelesaikan masalah melalui rantai kepemilikan silang basis data, Anda telah mengaktifkan rantai silang-db di seluruh tingkat server, yang dianggap sebagai risiko keamanan. Cara paling terkontrol, berbutir halus untuk mencapai hasil yang diinginkan adalah dengan menggunakan penandatanganan kode:

  • Dalam aplikasi database buat sertifikat yang ditandatangani sendiri
  • tanda tangani dbo.StartAgentJobdengan sertifikat ini
  • jatuhkan kunci pribadi sertifikat
  • ekspor sertifikat ke disk
  • impor sertifikat ke msdb
  • buat pengguna turunan dari sertifikat yang diimpor di msdb
  • memberikan izin AUTHENTICATE kepada pengguna yang berasal di msdb

Langkah-langkah ini memastikan bahwa konteks dbo.StartAgentJobprosedur EXECUTE AS sekarang dipercaya msdb, karena konteksnya ditandatangani oleh kepala sekolah yang memiliki izin ASLI di msdb. Ini memecahkan setengah dari teka-teki. Setengah lainnya adalah untuk benar-benar memberikan izin EXECUTE msdb.dbo.sp_start_jobke konteks peniruan yang sekarang tepercaya. Ada beberapa cara bagaimana ini bisa dilakukan:

  1. memetakan pengguna agentProxypengguna yang ditiru msdbdan memberinya izin untuk mengeksekusimsdb.dbo.sp_start_job
  2. memberikan izin eksekusi kepada pengguna msdbasli sertifikat yang diturunkan
  3. tambahkan tanda tangan baru ke prosedur, dapatkan pengguna untuk itu msdbdan berikan izin eksekusi kepada pengguna turunan ini

Opsi 1. sederhana, tetapi memiliki kelemahan besar: agentProxypengguna sekarang dapat melakukan atas msdb.dbo.sp_start_jobkehendaknya sendiri, ia benar-benar diberikan akses ke msdbdan memiliki izin eksekusi.

Opsi 3 benar secara positif, tetapi saya merasa tidak perlu berlebihan.

Jadi pilihan saya adalah Opsi 2: berikan izin EXECUTE msdb.dbo.sp_start_jobke pengguna yang berasal dari sertifikat yang dibuat di msdb.

Berikut ini adalah SQL yang sesuai:

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 saya memiliki beberapa artikel yang membahas topik ini, ditulis dalam konteks prosedur yang diaktifkan oleh Broker Layanan (karena memerlukan klausa EXECUTE AS):

BTW, jika Anda mencoba menguji skrip saya dan Anda tinggal di belahan bumi timur, atau di musim panas Inggris, pasti baca artikel terakhir yang saya tautkan sebelum pengujian.

Remus Rusanu
sumber
0

Karena Anda mencoba memulai SQL Server Agent dari kode .NET, ini mungkin pertanyaan yang lebih baik untuk StackOverflow?

http://www.stackoverflow.com

KPWINC
sumber
1
Saya pikir ini mungkin masalah keamanan basis data, tetapi saya akan mencoba StackOverflow jika kami tidak dapat menemukan jawaban di sini.
Ed Leighton-Dick
0

Memeriksa Instance SQL acak pada jaringan SQLAgentOperatorRole tidak memberi Anda hak istimewa sp_start_job secara langsung, ia mewarisi mereka dari SQLAgentUserRole.

Periksa ulang menggunakan:

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'

Jalankan ini di MSDB dan periksa apakah Anda tidak mewarisi akses penolakan eksplisit.

hth.

Andrew
sumber
Pengguna secara eksplisit adalah anggota SQLAgentOperatorRole dan SQLAgentUserRole.
Ed Leighton-Dick
0

Salah satu cara untuk mencapai ini tanpa memberikan izin tambahan: jangan biarkan proc yang disimpan memulai pekerjaan secara langsung, tetapi biarkan saja proc yang disimpan untuk membalik sedikit dalam sebuah tabel (dalam database aplikasi); kemudian, biarkan pekerjaan berjalan sekitar satu menit atau lebih, periksa apakah bitnya terbalik dan jika demikian, lakukan pekerjaan dan balikkan bit itu lagi. Jika pekerjaan melihat bit tidak terbalik, pekerjaan hanya akan keluar.

Bekerja seperti mantra, jika Anda tidak keberatan dengan penundaan (dan pekerjaan berjalan sangat sering).

Robert van den Berg
sumber