トレース機能を利用して、Select文の監査をします。
Audit Schema Object Access Eventをトレースし、ファイル出力された内容をOSのイベントログへ定期的に出力します。
msdb内にSPを2つ作成します。
SP_USRAuditTrace : Audit Schema Object Access EventをトレースするSP
SP_USRAuditTraceCheck : トレースしたファイルをチェックして、イベントログに出力するSP
SQLジョブを2つ作成します。
監査 : トレースを開始、チェックするSQLジョブ
監査ログ削除 : 出力された古いトレースファイルを削除するためのSQLジョブ
1.トレースログを出力するためのフォルダを準備します。
G:\work\tracelog
2.SP_USRAuditTraceを作成します。
sp_trace_setfilterにより監査に必要な条件を調整してください。
※トレース時のサーバ負荷、出力されるトレースファイルの量には注意してください。
use msdb go CREATE PROCEDURE [dbo].[SP_USRAuditTrace] AS DECLARE @ErrorMessage varchar(2000) ,@ErrorSeverity tinyint ,@ErrorState tinyint BEGIN TRY --トレースファイル名 declare @basefile varchar(50) set @basefile='USRAuditTrace' --既に起動済みの監査用トレースがあるか確認 declare @tid int declare @tfnmae varchar(1000) SELECT distinct @tid=traceid, @tfnmae=convert(varchar(1000),value) FROM :: fn_trace_getinfo(default) where convert(varchar(1000),value) like '%' + @basefile + '%' --ファイル名に追加する日付を作成 declare @d1 char(8) select @d1 = convert (char(8), GETDATE(), 112) declare @stopfg int SET @stopfg = 0 --トレース中 IF @tid is not null BEGIN --本日のトレース IF @tfnmae like '%'+@basefile+@d1+'%' BEGIN --終了 RETURN END ELSE --違う場合は新たにトレースを始める BEGIN --前回のトレースを止める用 SET @stopfg = 1 END END -- Create a Queue declare @rc int declare @TraceID int declare @maxfilesize bigint --サイズ MB set @maxfilesize = 10000 declare @fName sysname select @fName = 'G:\work\tracelog\' + @basefile + @d1 --100ファイルでローテーション exec @rc = sp_trace_create @TraceID output, 2, @fName, @maxfilesize, NULL, 100 if (@rc != 0) goto error declare @on bit set @on = 1 --114:Audit Schema Object Access Event exec sp_trace_setevent @TraceID, 114, 1, @on exec sp_trace_setevent @TraceID, 114, 9, @on exec sp_trace_setevent @TraceID, 114, 2, @on exec sp_trace_setevent @TraceID, 114, 3, @on exec sp_trace_setevent @TraceID, 114, 4, @on exec sp_trace_setevent @TraceID, 114, 5, @on exec sp_trace_setevent @TraceID, 114, 6, @on exec sp_trace_setevent @TraceID, 114, 7, @on exec sp_trace_setevent @TraceID, 114, 8, @on exec sp_trace_setevent @TraceID, 114, 10, @on exec sp_trace_setevent @TraceID, 114, 11, @on exec sp_trace_setevent @TraceID, 114, 12, @on exec sp_trace_setevent @TraceID, 114, 14, @on exec sp_trace_setevent @TraceID, 114, 19, @on exec sp_trace_setevent @TraceID, 114, 21, @on exec sp_trace_setevent @TraceID, 114, 23, @on exec sp_trace_setevent @TraceID, 114, 26, @on exec sp_trace_setevent @TraceID, 114, 28, @on exec sp_trace_setevent @TraceID, 114, 29, @on exec sp_trace_setevent @TraceID, 114, 34, @on exec sp_trace_setevent @TraceID, 114, 35, @on exec sp_trace_setevent @TraceID, 114, 37, @on exec sp_trace_setevent @TraceID, 114, 40, @on exec sp_trace_setevent @TraceID, 114, 41, @on exec sp_trace_setevent @TraceID, 114, 44, @on exec sp_trace_setevent @TraceID, 114, 49, @on exec sp_trace_setevent @TraceID, 114, 50, @on exec sp_trace_setevent @TraceID, 114, 51, @on exec sp_trace_setevent @TraceID, 114, 59, @on exec sp_trace_setevent @TraceID, 114, 60, @on exec sp_trace_setevent @TraceID, 114, 64, @on -- Set the Filters declare @intfilter int declare @bigintfilter bigint --DatabaseID(3) が ユーザデータベース(5) 以上(4)をトレース対象に set @intfilter = 5 exec sp_trace_setfilter @TraceID, 3, 0, 4, @intfilter -- exec sp_trace_setfilter @TraceID, 35, 0, 1, N'distribution' -- IntelliSenseは対象外に exec sp_trace_setfilter @TraceID, 10, 0, 7, N'Microsoft SQL Server Management Studio - Transact-SQL IntelliSense' -- ドメインユーザを監査対象にする場合 -- exec sp_trace_setfilter @TraceID, 7, 0, 6, N'ドメイン名' -- 7:NTDomainName 6:NTUserNameがNULLではない exec sp_trace_setfilter @TraceID, 7, 0, 1, NULL exec sp_trace_setfilter @TraceID, 6, 0, 1, NULL -- オブジェクトの所有者がdboのもの exec sp_trace_setfilter @TraceID, 37, 0, 6, N'dbo' -- クライアントの SQL Server ログイン名と 等しくない -- exec sp_trace_setfilter @TraceID, 11, 0, 1, N'SQLServerの実行ユーザ' -- セッションを開始したユーザーのログイン名と 等しくない -- exec sp_trace_setfilter @TraceID, 64, 0, 1, N'SQLServerの実行ユーザ' exec sp_trace_setfilter @TraceID, 64, 0, 1, NULL -- Set the trace status to start exec sp_trace_setstatus @TraceID, 1 --停止フラグが立っている時は、前回のトレースを削除する IF @stopfg = 1 BEGIN -- トレース一時停止 EXEC sp_trace_setstatus @tid, 0 -- トレース削除 EXEC sp_trace_setstatus @tid, 2 END select TraceID=@TraceID goto finish error: SELECT @ErrorMessage = 'ErrorCode=' + @rc RAISERROR ( @ErrorMessage , 16, 1) select ErrorCode=@rc finish: END TRY BEGIN CATCH SET @ErrorMessage = ERROR_MESSAGE() SET @ErrorSeverity = ERROR_SEVERITY() SET @ErrorState = ERROR_STATE() RAISERROR(@ErrorMessage, @ErrorSeverity, @ErrorState) END CATCH go
3.SP_USRAuditTraceCheckを作成します。
use msdb
go
CREATE PROCEDURE [dbo].[SP_USRAuditTraceCheck]
AS
DECLARE
@ErrorMessage varchar(2000)
,@ErrorSeverity tinyint
,@ErrorState tinyint
BEGIN TRY
--トレースファイル名
DECLARE @sttime varchar(100)
DECLARE @edtime varchar(100)
DECLARE @interval int
DECLARE @MSG varchar(4000)
DECLARE @HostName varchar(100)
DECLARE @LoginName varchar(100)
DECLARE @ServerName varchar(100)
DECLARE @DatabaseName varchar(100)
DECLARE @ObjectName varchar(100)
DECLARE @ACnt varchar(10)
DECLARE @SqlCMD1 varchar(3000)
DECLARE @SqlCMD2 varchar(3000)
declare @basefile varchar(50)
set @basefile='USRAuditTrace'
declare @fName sysname
select @fName = 'G:\work\tracelog\' + @basefile
declare @tid int
declare @tfnmae varchar(1000)
SELECT distinct @tid=traceid, @tfnmae=convert(varchar(1000),value) FROM ::fn_trace_getinfo(default)
where convert(varchar(1000),value) like '%' + @fName + '%'
SET @MSG =''
--トレースしていない場合
IF @tid is null
BEGIN
SET @MSG = 'DB監査メッセージ:監査が行われていません。'
RAISERROR ('%s', 0, 1 ,@MSG ) WITH LOG
--終了
RETURN
END
--チェック間隔
set @interval = -5
--調査対象 (分)
set @edtime = convert(varchar(16),GETDATE(),120)
set @sttime = convert(varchar(16),DATEADD(minute,@interval,@edtime),120)
--ファイル名に追加する日付を作成
declare @d1 char(8)
declare @d2 char(8)
SET @d1 = convert(char(8) ,convert (date,@edtime), 112)
SET @d2 = convert(char(8) ,convert (date,@sttime), 112)
--日付がまたがっているか
set @SqlCMD1 =''
IF @d1 <> @d2
BEGIN
--前日分
SET @SqlCMD1= 'select '
SET @SqlCMD1=@SqlCMD1 + ' ISNULL(HostName,'''') AS ''アクセス元'' '
SET @SqlCMD1=@SqlCMD1 + ', ISNULL(LoginName,'''') AS ''アクセスユーザー'' '
SET @SqlCMD1=@SqlCMD1 + ', ISNULL(ServerName,'''') AS ''アクセス先'' '
SET @SqlCMD1=@SqlCMD1 + ', ISNULL(DatabaseName,'''') AS ''アクセス先DB'' '
SET @SqlCMD1=@SqlCMD1 + ', ISNULL(ObjectName,'''') AS ''オブジェクト'' '
SET @SqlCMD1=@SqlCMD1 + ', convert(varchar(10),COUNT(*)) AS ''回数'' '
SET @SqlCMD1=@SqlCMD1 + ' from ::fn_trace_gettable('''+@fName + @d2 +'.trc'',default) '
SET @SqlCMD1=@SqlCMD1 + 'Where EventClass = 114 '
SET @SqlCMD1=@SqlCMD1 + 'and convert(datetime,StartTime) >= ''' + @sttime + ''' '
SET @SqlCMD1=@SqlCMD1 + 'and convert(datetime,StartTime) < ''' + @edtime + ''' '
SET @SqlCMD1=@SqlCMD1 + 'group by HostName,LoginName,ServerName,DatabaseName,ObjectName '
SET @SqlCMD1=@SqlCMD1 + ' UNION ALL '
END
--本日分
SET @SqlCMD2= 'select '
SET @SqlCMD2=@SqlCMD2 + ' ISNULL(HostName,'''') AS ''アクセス元'' '
SET @SqlCMD2=@SqlCMD2 + ', ISNULL(LoginName,'''') AS ''アクセスユーザー'' '
SET @SqlCMD2=@SqlCMD2 + ', ISNULL(ServerName,'''') AS ''アクセス先'' '
SET @SqlCMD2=@SqlCMD2 + ', ISNULL(DatabaseName,'''') AS ''アクセス先DB'' '
SET @SqlCMD2=@SqlCMD2 + ', ISNULL(ObjectName,'''') AS ''オブジェクト'' '
SET @SqlCMD2=@SqlCMD2 + ', convert(varchar(10),COUNT(*)) AS ''回数'' '
SET @SqlCMD2=@SqlCMD2 + ' from ::fn_trace_gettable('''+@fName + @d1 +'.trc'',default) '
SET @SqlCMD2=@SqlCMD2 + 'Where EventClass = 114 '
SET @SqlCMD2=@SqlCMD2 + 'and convert(datetime,StartTime) >= ''' + @sttime + ''' '
SET @SqlCMD2=@SqlCMD2 + 'and convert(datetime,StartTime) < ''' + @edtime + ''' '
SET @SqlCMD2=@SqlCMD2 + 'group by HostName,LoginName,ServerName,DatabaseName,ObjectName '
exec('DECLARE curtables CURSOR FAST_FORWARD FOR '+
@SqlCMD1 + @SqlCMD2 +
' order by ISNULL(HostName,''''),ISNULL(LoginName,''''),ISNULL(ServerName,''''),ISNULL(DatabaseName,''''),ISNULL(ObjectName,'''') ')
OPEN curtables
-- Loop through all the curtables in the database
FETCH NEXT
FROM curtables
INTO @HostName, @LoginName, @ServerName, @DatabaseName, @ObjectName, @ACnt
IF @@FETCH_STATUS = 0
BEGIN
SET @MSG = 'DB監査メッセージ:' + @sttime + '~' + @edtime + NCHAR(13) + NCHAR(10) + 'アクセス元,アクセスユーザー,アクセス先,アクセス先DB,オブジェクト,回数' + NCHAR(13) + NCHAR(10)
END
WHILE @@FETCH_STATUS = 0
BEGIN
SET @MSG = @MSG + @HostName + ',' + @LoginName + ',' + @ServerName + ',' + @DatabaseName + ',' + @ObjectName + ',' + @ACnt + NCHAR(13) + NCHAR(10)
FETCH NEXT
FROM curtables
INTO @HostName, @LoginName, @ServerName, @DatabaseName, @ObjectName, @ACnt
END
-- Close and deallocate the cursor
CLOSE curtables
DEALLOCATE curtables
IF @MSG <> ''
BEGIN
RAISERROR ('%s', 0, 1 ,@MSG ) WITH LOG
END
END TRY
BEGIN CATCH
SET @ErrorMessage = ERROR_MESSAGE()
SET @ErrorSeverity = ERROR_SEVERITY()
SET @ErrorState = ERROR_STATE()
RAISERROR(@ErrorMessage, @ErrorSeverity, @ErrorState)
END CATCH
go
4.「監査」SQLジョブ作成します。
※このジョブは5分おきに起動されます。
USE [msdb]
GO
/****** Object: Job [監査] Script Date: 2015/05/08 17:56:22 ******/
BEGIN TRANSACTION
DECLARE @ReturnCode INT
SELECT @ReturnCode = 0
/****** Object: JobCategory [[Uncategorized (Local)]] Script Date: 2015/05/08 17:56:22 ******/
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 <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
END
DECLARE @jobId BINARY(16)
EXEC @ReturnCode = msdb.dbo.sp_add_job @job_name=N'監査',
@enabled=1,
@notify_level_eventlog=2,
@notify_level_email=0,
@notify_level_netsend=0,
@notify_level_page=0,
@delete_level=0,
@description=N'使用できる説明はありません。',
@category_name=N'[Uncategorized (Local)]',
@owner_login_name=N'sa', @job_id = @jobId OUTPUT
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
/****** Object: Step [監査トレースの実施確認] Script Date: 2015/05/08 17:56:23 ******/
EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id=@jobId, @step_name=N'監査トレースの実施確認',
@step_id=1,
@cmdexec_success_code=0,
@on_success_action=3,
@on_success_step_id=0,
@on_fail_action=3,
@on_fail_step_id=0,
@retry_attempts=0,
@retry_interval=0,
@os_run_priority=0, @subsystem=N'TSQL',
@command=N'EXEC [dbo].[SP_USRAuditTrace]
',
@database_name=N'msdb',
@flags=0
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
/****** Object: Step [アクセスをチェック] Script Date: 2015/05/08 17:56:23 ******/
EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id=@jobId, @step_name=N'アクセスをチェック',
@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'TSQL',
@command=N'exec [SP_USRAuditTraceCheck]',
@database_name=N'msdb',
@flags=0
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
EXEC @ReturnCode = msdb.dbo.sp_update_job @job_id = @jobId, @start_step_id = 1
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
EXEC @ReturnCode = msdb.dbo.sp_add_jobschedule @job_id=@jobId, @name=N'スケジュール',
@enabled=1,
@freq_type=4,
@freq_interval=1,
@freq_subday_type=4,
@freq_subday_interval=5,
@freq_relative_interval=0,
@freq_recurrence_factor=0,
@active_start_date=20150128,
@active_end_date=99991231,
@active_start_time=0,
@active_end_time=235959
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
EXEC @ReturnCode = msdb.dbo.sp_add_jobserver @job_id = @jobId, @server_name = N'(local)'
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
COMMIT TRANSACTION
GOTO EndSave
QuitWithRollback:
IF (@@TRANCOUNT > 0) ROLLBACK TRANSACTION
EndSave:
GO
5.「監査ログ削除」SQLジョブ作成します。
※毎日0:01に起動します。
G:\work\tracelog配下の90日以上経過した、*.trcファイルを削除します。
forfiles /s /d -90 /m *.trc /p G:\work\tracelog /c “cmd /c del @path”
USE [msdb]
GO
/****** Object: Job [監査ログ削除] Script Date: 2015/05/08 17:56:55 ******/
BEGIN TRANSACTION
DECLARE @ReturnCode INT
SELECT @ReturnCode = 0
/****** Object: JobCategory [[Uncategorized (Local)]] Script Date: 2015/05/08 17:56:55 ******/
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 <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
END
DECLARE @jobId BINARY(16)
EXEC @ReturnCode = msdb.dbo.sp_add_job @job_name=N'監査ログ削除',
@enabled=1,
@notify_level_eventlog=2,
@notify_level_email=0,
@notify_level_netsend=0,
@notify_level_page=0,
@delete_level=0,
@description=N'使用できる説明はありません。',
@category_name=N'[Uncategorized (Local)]',
@owner_login_name=N'sa', @job_id = @jobId OUTPUT
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
/****** Object: Step [削除] Script Date: 2015/05/08 17:56:55 ******/
EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id=@jobId, @step_name=N'削除',
@step_id=1,
@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'forfiles /s /d -90 /m *.trc /p G:\work\tracelog /c "cmd /c del @path"
',
@flags=0
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
EXEC @ReturnCode = msdb.dbo.sp_update_job @job_id = @jobId, @start_step_id = 1
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
EXEC @ReturnCode = msdb.dbo.sp_add_jobschedule @job_id=@jobId, @name=N'スケジュール',
@enabled=1,
@freq_type=4,
@freq_interval=1,
@freq_subday_type=1,
@freq_subday_interval=0,
@freq_relative_interval=0,
@freq_recurrence_factor=0,
@active_start_date=20150129,
@active_end_date=99991231,
@active_start_time=100,
@active_end_time=235959
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
EXEC @ReturnCode = msdb.dbo.sp_add_jobserver @job_id = @jobId, @server_name = N'(local)'
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
COMMIT TRANSACTION
GOTO EndSave
QuitWithRollback:
IF (@@TRANCOUNT > 0) ROLLBACK TRANSACTION
EndSave:
GO
その他
トレース中の情報を確認
SELECT * FROM :: fn_trace_getinfo(default)
削除する場合
SPとジョブを削除します。
USE msdb GO DROP PROCEDURE [dbo].[SP_USRAuditTrace] GO DROP PROCEDURE [dbo].[SP_USRAuditTraceCheck] go sp_delete_job @job_name = '監査' go sp_delete_job @job_name = '監査ログ削除' go

