DuoKey SQL EKM の暗号化状態を監視し、アラートを構成する
効果的な監視により、暗号化されたデータベースが健全でコンプライアンスに準拠した状態を維持できます。このガイドでは、リアルタイムの状態監視、自動ヘルスチェック、SQL Server Agent アラート、監査ログについて説明します。
暗号化されたすべてのデータベースを簡単に監視するためのビューを作成します:
CREATE OR ALTER VIEW dbo.vw_TDE_Status
AS
SELECT
DB_NAME(dek.database_id) AS DatabaseName,
d.state_desc AS DatabaseState,
CASE dek.encryption_state
WHEN 0 THEN 'No DEK Present'
WHEN 1 THEN 'Unencrypted'
WHEN 2 THEN 'Encryption In Progress'
WHEN 3 THEN 'Encrypted'
WHEN 4 THEN 'Key Change In Progress'
WHEN 5 THEN 'Decryption In Progress'
WHEN 6 THEN 'Protection Change In Progress'
END AS EncryptionStatus,
dek.percent_complete AS ProgressPercent,
dek.key_algorithm AS Algorithm,
dek.key_length AS KeyLength,
ak.name AS ProtectingKeyName,
cp.name AS EKMProvider,
dek.create_date AS DEKCreated,
dek.regenerate_date AS LastKeyRotation,
DATEDIFF(DAY, ISNULL(dek.regenerate_date, dek.create_date), GETDATE())
AS DaysSinceRotation
FROM sys.dm_database_encryption_keys dek
INNER JOIN sys.databases d ON dek.database_id = d.database_id
LEFT JOIN sys.asymmetric_keys ak ON dek.encryptor_thumbprint = ak.thumbprint
LEFT JOIN sys.cryptographic_providers cp ON ak.provider_id = cp.provider_id;
GOSELECT * FROM dbo.vw_TDE_Status暗号化状態を理解することは、監視において非常に重要です:
| 状態 | 値 | 説明 | 必要なアクション |
|---|---|---|---|
| 0 | DEK なし | データベース暗号化キーが存在しません | CREATE DATABASE ENCRYPTION KEY で DEK を作成 |
| 1 | 未暗号化 | DEK は存在しますが暗号化が有効になっていません | ALTER DATABASE SET ENCRYPTION ON で有効化 |
| 2 | 暗号化中 | 暗号化が進行中 | 完了を待機し、percent_complete を監視します |
| 3 | 暗号化済み | データベースは完全に暗号化されています | なし - 通常の運用 |
| 4 | キー変更 | キーローテーションを実行中 | 完了を待機します |
| 5 | 復号中 | 復号を実行中 | 完了を待機します |
| 6 | 保護の変更 | 保護機能の変更を実行中 | 完了を待機します |
-- All encrypted databases with status
SELECT
DB_NAME(database_id) AS [Database],
encryption_state,
percent_complete
FROM sys.dm_database_encryption_keys;
GO
-- Check EKM provider is healthy
SELECT name, is_enabled, version
FROM sys.cryptographic_providers
WHERE name = 'DuoKeyProvider';
GO
-- Databases needing attention
SELECT
DB_NAME(database_id) AS [Database],
'Key rotation overdue' AS Issue
FROM sys.dm_database_encryption_keys
WHERE DATEDIFF(DAY, ISNULL(regenerate_date, create_date), GETDATE()) > 365;
GOこの包括的なストアドプロシージャは、よくある問題をチェックし、必要に応じてメールアラートを送信できます:
CREATE OR ALTER PROCEDURE dbo.usp_TDE_HealthCheck
@AlertThresholdDays INT = 365,
@SendEmail BIT = 0,
@EmailRecipients NVARCHAR(500) = NULL
AS
BEGIN
SET NOCOUNT ON;
DECLARE @Issues TABLE (
Severity VARCHAR(20),
Category VARCHAR(50),
DatabaseName NVARCHAR(128),
Issue NVARCHAR(500),
Recommendation NVARCHAR(500)
);
-- Check for databases that should be encrypted but aren't
INSERT INTO @Issues
SELECT
'WARNING',
'Encryption Gap',
name,
'Database is not encrypted',
'Consider enabling TDE for this database'
FROM sys.databases
WHERE database_id > 4 -- Exclude system databases
AND is_encrypted = 0
AND name NOT IN ('tempdb', 'ReportServer', 'ReportServerTempDB');
-- Check for key rotation overdue
INSERT INTO @Issues
SELECT
'WARNING',
'Key Rotation',
DB_NAME(database_id),
'Key rotation overdue (' +
CAST(DATEDIFF(DAY, ISNULL(regenerate_date, create_date), GETDATE()) AS VARCHAR) +
' days since last rotation)',
'Rotate DEK per security policy'
FROM sys.dm_database_encryption_keys
WHERE DATEDIFF(DAY, ISNULL(regenerate_date, create_date), GETDATE()) > @AlertThresholdDays;
-- Check for stuck encryption operations
INSERT INTO @Issues
SELECT
'CRITICAL',
'Encryption Stuck',
DB_NAME(database_id),
'Encryption operation stuck at ' + CAST(percent_complete AS VARCHAR) + '%',
'Investigate I/O performance and DuoKey connectivity'
FROM sys.dm_database_encryption_keys
WHERE encryption_state IN (2, 4, 5, 6)
AND percent_complete < 100
AND DATEDIFF(HOUR, modify_date, GETDATE()) > 4;
-- Check EKM provider status
IF NOT EXISTS (
SELECT 1 FROM sys.cryptographic_providers
WHERE name = 'DuoKeyProvider' AND is_enabled = 1
)
BEGIN
INSERT INTO @Issues VALUES (
'CRITICAL',
'EKM Provider',
'N/A',
'DuoKey EKM Provider is not enabled or missing',
'Verify provider installation and enable if disabled'
);
END
-- Return results
SELECT * FROM @Issues
ORDER BY
CASE Severity WHEN 'CRITICAL' THEN 1 WHEN 'WARNING' THEN 2 ELSE 3 END,
Category, DatabaseName;
-- Optionally send email (requires Database Mail configured)
IF @SendEmail = 1 AND EXISTS (SELECT 1 FROM @Issues)
BEGIN
DECLARE @body NVARCHAR(MAX);
SELECT @body = STRING_AGG(
Severity + ': ' + Category + ' - ' + DatabaseName + ': ' + Issue,
CHAR(13) + CHAR(10)
) FROM @Issues;
EXEC msdb.dbo.sp_send_dbmail
@recipients = @EmailRecipients,
@subject = 'SQL EKM Health Check Alert',
@body = @body;
END
END
GO-- Basic health check (returns issues only)
EXEC dbo.usp_TDE_HealthCheck;
GO
-- With custom threshold (90 days for key rotation)
EXEC dbo.usp_TDE_HealthCheck @AlertThresholdDays = 90;
GO
-- With email alerts (requires Database Mail)
EXEC dbo.usp_TDE_HealthCheck
@AlertThresholdDays = 365,
@SendEmail = 1,
@EmailRecipients = '[email protected],[email protected]';
GOスケジュールに従ってヘルスチェックを実行する自動化された SQL Server Agent ジョブを作成します:
-- Create health check job
USE msdb;
GO
EXEC dbo.sp_add_job
@job_name = N'TDE_HealthCheck_Hourly',
@enabled = 1,
@description = N'Hourly TDE encryption health check';
GO
EXEC dbo.sp_add_jobstep
@job_name = N'TDE_HealthCheck_Hourly',
@step_name = N'RunHealthCheck',
@subsystem = N'TSQL',
@command = N'EXEC dbo.usp_TDE_HealthCheck
@AlertThresholdDays = 365,
@SendEmail = 1,
@EmailRecipients = ''[email protected]''',
@database_name = N'master';
GO
EXEC dbo.sp_add_schedule
@schedule_name = N'Hourly',
@freq_type = 4,
@freq_interval = 1,
@freq_subday_type = 8,
@freq_subday_interval = 1;
GO
EXEC dbo.sp_attach_schedule
@job_name = N'TDE_HealthCheck_Hourly',
@schedule_name = N'Hourly';
GO
EXEC dbo.sp_add_jobserver
@job_name = N'TDE_HealthCheck_Hourly';
GO
PRINT 'Health check job created successfully.';
GO| スケジュール | freq_type | freq_subday_type | freq_subday_interval |
|---|---|---|---|
| 1 時間ごと | 4 (毎日) | 8 (時間) | 1 |
| 15 分ごと | 4 (毎日) | 4 (分) | 15 |
| 6 時間ごと | 4 (毎日) | 8 (時間) | 6 |
| 毎日午前 6 時に 1 回 | 4 (毎日) | 1 (1 回) | N/A |
I/O パフォーマンスを監視して、TDE が過剰なオーバーヘッドを引き起こしていないことを確認します:
-- TDE Performance Baseline Query
SELECT
DB_NAME(fs.database_id) AS DatabaseName,
mf.name AS FileName,
mf.type_desc AS FileType,
fs.num_of_reads AS Reads,
fs.num_of_writes AS Writes,
fs.io_stall_read_ms AS ReadStallMs,
fs.io_stall_write_ms AS WriteStallMs,
CAST(fs.size_on_disk_bytes / 1024.0 / 1024.0 AS DECIMAL(10,2)) AS SizeMB,
d.is_encrypted AS Encrypted,
CASE
WHEN fs.num_of_reads > 0
THEN CAST(fs.io_stall_read_ms / fs.num_of_reads AS DECIMAL(10,2))
ELSE 0
END AS AvgReadLatencyMs,
CASE
WHEN fs.num_of_writes > 0
THEN CAST(fs.io_stall_write_ms / fs.num_of_writes AS DECIMAL(10,2))
ELSE 0
END AS AvgWriteLatencyMs
FROM sys.dm_io_virtual_file_stats(NULL, NULL) fs
INNER JOIN sys.master_files mf
ON fs.database_id = mf.database_id AND fs.file_id = mf.file_id
INNER JOIN sys.databases d
ON fs.database_id = d.database_id
WHERE d.is_encrypted = 1
ORDER BY fs.io_stall_read_ms + fs.io_stall_write_ms DESC;
GO| 指標 | 正常範囲 | 超過時の対応 |
|---|---|---|
| AvgReadLatencyMs | < 20ms | ストレージ I/O を確認し、より高速なストレージを検討します |
| AvgWriteLatencyMs | < 20ms | ストレージ I/O を確認し、ログの最適化を検討します |
| 暗号化中の CPU | < 80% | 業務時間外に暗号化をスケジュールします |
| TDE スキャンの進捗 | 増加中 | ロックや I/O ボトルネックを確認します |
コンプライアンスのためにキー操作を追跡するには、SQL Server Audit を有効にします:
-- Create server audit
CREATE SERVER AUDIT TDE_Audit
TO FILE (FILEPATH = 'C:\SQLAudit\', MAXSIZE = 100 MB)
WITH (QUEUE_DELAY = 1000, ON_FAILURE = CONTINUE);
GO
ALTER SERVER AUDIT TDE_Audit WITH (STATE = ON);
GO
-- Create audit specification for crypto operations
CREATE SERVER AUDIT SPECIFICATION TDE_AuditSpec
FOR SERVER AUDIT TDE_Audit
ADD (DATABASE_CHANGE_GROUP),
ADD (SCHEMA_OBJECT_ACCESS_GROUP),
ADD (BACKUP_RESTORE_GROUP)
WITH (STATE = ON);
GO
PRINT 'Audit configuration created successfully.';
GO| イベントグループ | キャプチャする内容 |
|---|---|
| DATABASE_CHANGE_GROUP | CREATE/ALTER/DROP DATABASE 操作 |
| SCHEMA_OBJECT_ACCESS_GROUP | 暗号化キーと証明書へのアクセス |
| BACKUP_RESTORE_GROUP | バックアップと復元の操作 |