一、背景
在某天晚上凌晨1點,我收到領導的通知:需要把我們所有的數據庫的密碼都需要進行一次修改,原因是我們放到Web服務器的配置文件config中明文了我們的數據庫帳號和密碼,而且這份配置文件可能泄露了,更糟糕的是我們的數據庫是可以通過外網進行訪問的。雖然有端口進行映射,但是我們的數據依然處在危險的狀態,所以這個時候DBA需要爭分奪秒修改數據庫的帳號密碼。
我們的數據庫服務器大概有30台,而且每台機器上跑了很多個數據庫。有創建數據庫帳號經驗的同學你會發現:使用SSMS進行創建帳號密碼是件多么痛苦的事情,需要點擊很多checkbox,特別是在創建一個可以訪問整個數據庫實例里的所有數據庫的時候(雖然我們提倡每個數據庫的帳號和密碼都不一樣,更嚴格的要求可能需要設置同一個數據庫下需要有不同權限的帳號進行管理)
如果我們對數據庫的帳號進行有效管理的話,我們可以很輕松的完成這個任務,只需要一條SQL就能管理了。在這里我提倡一種安全、易維護的方案給大家:SQL Server數據庫帳號密碼安全設計
在看這篇文章之前,建議你先看看:SQL Server 2005控制用戶權限訪問表
二、設計概要
我們首先要明白我們出現的問題是什么:
1. 我們厭煩了一個個去點擊checkbox;
2. 點擊那么多次checkbox,我們不能確保所有的點擊都是正確的;
所以我們第一步要想的就是有沒什么辦法可以解決上面這些問題?上面的這些操作SSMS是能讓用戶把操作保存為腳本的,我們可以自己編寫SQL腳本來完成類似的工作。為了模擬SSMS上的操作,我們需要獲取到數據庫實例中所包含的所有數據庫,再對每個數據庫創建帳號和密碼。我們可以通過游標的形式循環數據庫,並創建帳號和密碼。最后我們需要禁用掉sa這個帳號。
修改下面【通用SQL模板】的@user和@password的值,拷貝到下面的代碼到SSMS中執行,這樣就可以生成出適合本數據庫實例的SQL腳本【生成的腳本代碼】了,我們再拷貝生成的SQL代碼到SSMS中執行就可以了。
執行下面的兩個腳本不過秒級,所以20台服務器對你來說,簡單啦。
三、通用SQL模板
--創建數據庫帳號 DECLARE @dbname varchar(100) DECLARE @user varchar(100) DECLARE @password varchar(100) DECLARE @sql varchar(max) SET @user = 'UfranimdA_gz' SET @password = 'o23#25R@8a8A!@23#@%' SET @sql = ' USE [master] GO CREATE LOGIN ['+ @user + '] WITH PASSWORD=N'''+ @password +''', DEFAULT_DATABASE=[master], CHECK_EXPIRATION=OFF, CHECK_POLICY=ON GO EXEC master..sp_addsrvrolemember @loginame = N'''+@user+''', @rolename = N''sysadmin'' GO' PRINT(@sql) DECLARE @itemCur CURSOR SET @itemCur = CURSOR FOR SELECT name from sys.databases where state =0 OPEN @itemCur FETCH NEXT FROM @itemCur INTO @dbname WHILE @@FETCH_STATUS=0 BEGIN SET @sql = ' USE ['+ @dbname + '] GO CREATE USER ['+@user+'] FOR LOGIN ['+@user+'] GO USE ['+ @dbname + '] GO ALTER USER ['+@user+'] WITH DEFAULT_SCHEMA=[dbo] GO USE ['+ @dbname + '] GO EXEC sp_addrolemember N''db_owner'', N'''+@user+''' GO' PRINT(@sql) FETCH NEXT FROM @itemCur INTO @dbname END CLOSE @itemCur DEALLOCATE @itemCur --禁用sa帳號 SET @sql = ' USE [master] GO ALTER LOGIN [sa] DISABLE GO' PRINT(@sql)
四、生成的腳本代碼
--創建數據庫帳號密碼 USE [master] GO CREATE LOGIN [UfranimdA_gz] WITH PASSWORD=N'o23#25R@8a8A!@23#@%', DEFAULT_DATABASE=[master], CHECK_EXPIRATION=OFF, CHECK_POLICY=ON GO EXEC master..sp_addsrvrolemember @loginame = N'UfranimdA_gz', @rolename = N'sysadmin' GO USE [master] GO CREATE USER [UfranimdA_gz] FOR LOGIN [UfranimdA_gz] GO USE [master] GO ALTER USER [UfranimdA_gz] WITH DEFAULT_SCHEMA=[dbo] GO USE [master] GO EXEC sp_addrolemember N'db_owner', N'UfranimdA_gz' GO USE [tempdb] GO CREATE USER [UfranimdA_gz] FOR LOGIN [UfranimdA_gz] GO USE [tempdb] GO ALTER USER [UfranimdA_gz] WITH DEFAULT_SCHEMA=[dbo] GO USE [tempdb] GO EXEC sp_addrolemember N'db_owner', N'UfranimdA_gz' GO USE [model] GO CREATE USER [UfranimdA_gz] FOR LOGIN [UfranimdA_gz] GO USE [model] GO ALTER USER [UfranimdA_gz] WITH DEFAULT_SCHEMA=[dbo] GO USE [model] GO EXEC sp_addrolemember N'db_owner', N'UfranimdA_gz' GO USE [msdb] GO CREATE USER [UfranimdA_gz] FOR LOGIN [UfranimdA_gz] GO USE [msdb] GO ALTER USER [UfranimdA_gz] WITH DEFAULT_SCHEMA=[dbo] GO USE [msdb] GO EXEC sp_addrolemember N'db_owner', N'UfranimdA_gz' GO USE [DBA_DB] GO CREATE USER [UfranimdA_gz] FOR LOGIN [UfranimdA_gz] GO USE [DBA_DB] GO ALTER USER [UfranimdA_gz] WITH DEFAULT_SCHEMA=[dbo] GO USE [DBA_DB] GO EXEC sp_addrolemember N'db_owner', N'UfranimdA_gz' GO USE [TestDB] GO CREATE USER [UfranimdA_gz] FOR LOGIN [UfranimdA_gz] GO USE [TestDB] GO ALTER USER [UfranimdA_gz] WITH DEFAULT_SCHEMA=[dbo] GO USE [TestDB] GO EXEC sp_addrolemember N'db_owner', N'UfranimdA_gz' GO USE [master] GO ALTER LOGIN [sa] DISABLE GO
五、特別說明
1. 這里生成的SQL腳本中包含了系統數據庫:master、model、msdb、tempdb,為了方便我就沒對這些數據庫進行限制的,希望以后可以修正下這個腳本。
2. 這里再次推薦大家使用同一的數據庫帳號密碼的管理,無論是安全還是方便維護都是大有好處的。SQL Server數據庫帳號密碼安全設計,大家可以提些其它的想法。