Hogyan rejtsük el az adatbázisokat

Pár hete megkeresett egy szak- és sorstársunk, az aktív-aktív clusterről zengett ódáim kapcsán, és megkérezte, hogy hogyan tudná smucig ügyfelét boldoggá tenni. A felállás a következő: van egy cluster, és nem aktív-aktív clustert szeretnének, hanem több SQL instance-t az adott resource groupba, hogy spóroljanak. A cél az, hogy különböző felhasználóknak az az élményük legyen, hogy senki más nem használja az adott SQL szervert. Az alábbiakban leírom, hogy miért NEM lehet ezt szépen megcsinálni.

Mi is az SQL cluster alapgondolata? Van egy resource group, benne pár diszk, egy IP cím meg egy hálózati név, és az egészre ráteszek egy SQL szervert. Mi lenne, ha hasonlóan a standalone szervereken használt named instance-hoz, még egy SQL szervert telepítenénk? A gondolat jó, de sajnos ez nem működik by design. A BOL ezt írja róla konkrétan: ” Each resource group can contain at most one instance of SQL Server.” Mi ennek az oka? Hát, nekem az jutott eszembe, hogy ha clustert építek, akkor nagy rendelkezésreállást akarok. Ha két instance-t telepítek ugyanabba a resource groupba, akkor azok együtt kell, h billenjenek, tehát ha A instance megdöglik, és elbillen a cluster, akkor viszi B instance-t is, kis szünetet okozva. Ha valamelyik diszk hal meg, az meg pláne kinyír mindent. Szóval így erős függés alakulhat ki a két instance között, és pont ezt akarja elkerülni a technológia.

Tehát zsákutca. Akkor nézzünk más megoldást. Közismert, hogy az SQL 2005-ben a security alrendszert fantasztikusan kibővítették, hihetetlen dolgokat lehet megtenni benne. Úgyhogy nézzünk is gyorsan körül, és találjuk meg a következő jogot: VIEW ANY DATABASE. Ha ezt revoke-oljuk, akkor mi történik? Hősünk csak az általa használható adatbázisokat látja a sys.databases táblában, ezzel együtt a Management Studio adatbázis-választó dropdown listája is beszűkül a megfelelő adatbázisokra. Ez nagyon jól hangzik, de a szigorítás sajnos túl jól sikerül. Az Object Explorerben baloldalt ugyanis eltűnik az összes adatbázis, csak a master és a tempdb látszik. Így emberünknek nincs meg az az illúziója, hogy ő egy dedikált szerveren dolgozik, az viszont megvan, hogy széjjelpolicyzta valaki. Ez a kis tüske benne van 2005-ben és 2008-ban is (R2-ben is), a Microsoft azt mondja, hogy majd egy következő major release-ben foglalkoznak vele (2011 vagy 2014 vagy efféle). Tökéletesen működő megoldás tehát nincs, ám teljesen meglepő módon a legjobb eredményt SQL 2000 Query Analyzerrel lehet elérni. Annak az Object Explorere megmutatja az adatbázisokat is megfelelően, rejtély, hogy hova tűnt ez 2005 táján. Az alábbi képen jól látható, hogy a foo userrel belépve a dropdown list jó, az Object Explorerben viszont nem látszik a foo adatbázis.

Hab a tortán: nem bírtam magammal, és elindítottam egy Profilert, hogy megnézzem, mit kérdez a kliens, amitől eltűnnek az adatbázisok az OE-ből. Semmit. Az Object Explorer refreshkor futó T-SQL lekérdezésben ott van benne rendesen a kis privát adatbázisom, de valamiért a gonosz kliens szoftver ezt megeszi. A Microsoft Connecten van már egy item arról, hogyan kéne működnie. Én részemről inkább bugnak tekintem, mint feature requestnek, de ez az én konzervativizmusom. Mindenkinek, aki szeretne ezzel játszani, egy kiváló minta script, Aaron Bertrandtól, aki szintén morcos volt egy kicsit.

USE [master];
GO
CREATE DATABASE foo;
GO
CREATE DATABASE bar;
GO
CREATE LOGIN [foo] WITH
    PASSWORD = N'foo',
    DEFAULT_DATABASE = [foo],
    CHECK_EXPIRATION = OFF,
    CHECK_POLICY = OFF;
GO
CREATE LOGIN [bar] WITH
    PASSWORD = N'bar',
    DEFAULT_DATABASE = [bar],
    CHECK_EXPIRATION = OFF,
    CHECK_POLICY = OFF;
GO
USE [foo];
GO
CREATE USER [foo]
    FOR LOGIN [foo]
    WITH DEFAULT_SCHEMA = [dbo];
GO
USE [bar];
GO
CREATE USER [bar]
    FOR LOGIN [bar]
    WITH DEFAULT_SCHEMA = [dbo];
GO
USE [master];
GO
DENY VIEW ANY DATABASE TO [foo];
DENY VIEW ANY DATABASE TO [bar];
GO

Ha már más tollával ékeskedem, meg kell jegyeznem, hogy ha a fent említett foo vagy bar usereket dbo-vá (nem db_ownerré) tesszük, akkor elvárás szerint működik a dolog:

USE foo;
GO
DROP USER foo;
GO
USE bar;
GO
DROP USER bar;
GO
USE [master];
GO
ALTER AUTHORIZATION ON DATABASE::foo TO [foo];
ALTER AUTHORIZATION ON DATABASE::bar TO [bar];
GO

Apró probléma: egy adatbázisnak csak egy dbo-ja lehet. De legalább kicsit workaroundoltuk.

Leave a comment