UPDATED - May 16, 2017 - Please review the updated code here.
In my previous post, Configuring the Azure SQL Database Firewall, I discussed how you can configure the firewall rules to manage access to the SQL Server. Today, I wanted to demonstrate how you can accomplish the same thing with your on-premise SQL Servers by creating a whitelist.
So let’s start off by defining “whitelist”. According to the American Heritage Dictionary, it is “a list of people or organizations that have been approved to receive special considerations”. In our example, that “special consideration” is access to the SQL Server only if your workstation IP address is on the whitelist.
So why would we care about this? Why not just manage access to SQL Server the normal way with logins and passwords. Here is one example. Let’s say you have a company policy that prohibits anyone from using a common login to connect to a SQL Server. But your application uses a single SQL login to make its connection to SQL Server, and EVERY developer in the company knows the password. Even though there is a written policy in place, what would prevent one of those developers form connecting to SQL Server to fix a bug, or worse, change data to circumvent the application logic.
A whitelist will define which logins are allowed to connect to SQL Server from a specific IP address. Using our scenario from above, we can walk through an example. First we need to create the whitelist table to enforce this policy: the application login (WebSiteLogin) should only be allowed to connect to SQL Server if it originates from the web server’s hostname (webserver1) and IP address: 192.168.100.55.
IF OBJECT_ID('dbo.WhiteList') IS NOT NULL
DROP TABLE dbo.WhiteList;
CREATE TABLE dbo.WhiteList
Id INT IDENTITY(1,1) PRIMARY KEY
Next, we need to add an entry to allow access.
Just creating the whitelist does nothing. That’s why we need to use a logon trigger to enforce the whiltelist rules.
CREATE TRIGGER WhiteListTrigger
ON ALL SERVER FOR LOGON
@LoginName varchar(255) = ORIGINAL_LOGIN()
,@HostName varchar(255) = HOST_NAME()
SELECT @HostIpAddress = client_net_address
WHERE session_id = @@SPID;
SELECT COUNT(*) FROM dbo.WhiteList
(LoginName = @LoginName) OR (LoginName = '*')
(HostName = @HostName) OR (HostName = '*')
(HostIpAddress = @HostIpAddress) OR (HostIpAddress = '*')
) = 0
The logon trigger simply compares the user’s login name, hostname, and IP address to what’s in the WhiteList table. If there is a match, then access is allowed. If not, then the connection is terminated via a rollback. To test this, we can attempt to login using WebSiteLogin from an IP address other than 192.168.100.55.
Immediately, we are greeted with a logon error message.
In addition to comparing the logins, the code also adds a wildcard option using the asterisk (*).
SELECT * FROM dbo.WhiteList;
Line 1 has an asterisk for LoginName and HostIpAddress. This means that any login from any IP address is allowed to connect as long as the HostName is dbserver. Line 2 has an asterisk for HostName and HostIpAddress. This means the sa login is allowed to connect from any hostname or IP address. Line 3 is the example we used above. An asktrisk in all three columns would allow any login from any hostname or IP address to connect.
In the event you lock yourself (or everyone) out of the SQL Server, there is a quick way to restore access. You’ll need to connect to SQL Server using the Dedicated Admin Connection, either through Management Studio or the SQLCMD command line using a login with SysAdmin permission. Once connected, you can disable the logon trigger.
From the example above, you can see how quickly you can implement your own firewall for your on-premise SQL Servers using a whitelist and a logon trigger.
Additional resources about Logon Triggers: