A estas alturas de la película, todos los que llevamos tiempo en esto de la administración de SQL Server hemos recibido la misma pregunta en más de una ocasión: “¿Se puede bloquear el acceso a SQL Server según la máquina desde la que se conecta un usuario?” Spoiler: sí, se puede, pero no de la manera que muchos esperan. Y no, SQL Server no tiene un checkbox mágico para esto. Hay que ensuciarse las manos. Y aquí es donde entramos nosotros.
Lo que SQL Server no puede hacer (al menos por defecto)
No existe, al menos hasta el día de hoy, ninguna opción nativa en SQL Server que permita vincular un login a una IP específica. Ni en el Management Studio, ni en el registro, ni en las opciones avanzadas. No busques, que no está. Y no, tampoco hay un parámetro oculto de configuración que habilite esto.
Así que si lo que esperabas era marcar una casilla para decir “este login solo se conecta desde esta IP”… puedes dejar de leer aquí. Pero si estás dispuesto a ir un poco más allá, porque lo estás, hay una solución elegante (y eficaz): usar un trigger de tipo LOGON.
¿Un trigger de inicio de sesión? Sí, y bien usado
SQL Server permite crear triggers a nivel de servidor que se ejecutan justo cuando un usuario intenta iniciar sesión. Y es ahí donde podemos interceptar la conexión, comprobar desde qué IP se está intentando conectar, y decidir si le damos la bienvenida… o le cerramos la puerta en la cara.
Para obtener la IP del cliente, podemos usar la vista sys.dm_exec_connections, que nos da, entre otros muchos datos, la dirección desde la que se está estableciendo la sesión actual. Esa es la base de todo este invento.
Primer ejemplo: el caso clásico del login sa
Empezamos por el escenario más sencillo: restringir el acceso del usuario sa a una IP concreta (o, mejor aún, solo permitirle conexión desde el propio servidor).
Este es un ejemplo de trigger directo y sin florituras:
CREATE TRIGGER [RestrictSALogin]
ON ALL SERVER
FOR LOGON
AS
BEGIN
DECLARE @client_ip VARCHAR(48);
SELECT @client_ip = client_net_address
FROM sys.dm_exec_connections
WHERE session_id = @@SPID;
IF ORIGINAL_LOGIN() = 'sa' AND @client_ip NOT IN ('192.168.101.202','<local machine>')
BEGIN
ROLLBACK;
PRINT 'Acceso denegado para sa desde una máquina no autorizada.';
END
END;
GO
Y ya está. Este trigger bloquea cualquier intento de conexión con el usuario sa desde una IP que no sea la del propio servidor o la que hayas indicado. Simple, efectivo y… sí, peligroso si no documentas bien la IP que estás autorizando. Porque si te equivocas y te bloqueas a ti mismo, te va a tocar entrar por modo seguro, y no será divertido.
Segundo escenario: múltiples usuarios, múltiples IPs
Ahora, pongámonos serios. No vas a crear un trigger por cada usuario. Ni tú, ni nadie. Para algo tenemos bases de datos. Vamos a externalizar la lógica de IPs permitidas en una tabla, y a hacer que el trigger se alimente de ahí.
Primero, creamos una base de datos auxiliar de configuración, por ejemplo ConfigSeguridad, y dentro, dos tablas: una con los logins permitidos y sus IPs, y otra (opcional) para registrar intentos fallidos de acceso.
CREATE DATABASE ConfigSeguridad;
GO
USE ConfigSeguridad;
GO
CREATE TABLE LoginsPermitidos (
NombreUsuario NVARCHAR(100) NOT NULL,
IPPermitida NVARCHAR(48) NOT NULL -- 'TODAS' si no hay restricción
);
Ahora podemos rellenarla con la lógica que queramos. Por ejemplo:
INSERT INTO LoginsPermitidos (NombreUsuario, IPPermitida)
VALUES
('sa', '192.168.101.225'),
('sa', '<local machine>'),
('admin', 'TODAS'),
('usuario1', '192.168.104.134');
Sí, aquí admitimos la palabra clave ‘TODAS’ como forma elegante de decir “este login puede conectarse desde cualquier parte del mundo, hasta desde el tren si hace falta”.
Y aquí viene el trigger maestro:
CREATE TRIGGER RestriccionLogins
ON ALL SERVER
WITH EXECUTE AS N'sa'
FOR LOGON
AS
BEGIN
DECLARE @IPCliente NVARCHAR(48);
DECLARE @NombreUsuario NVARCHAR(100);
SELECT @IPCliente = client_net_address
FROM sys.dm_exec_connections
WHERE session_id = @@SPID;
SET @NombreUsuario = ORIGINAL_LOGIN();
IF NOT EXISTS (
SELECT 1
FROM ConfigSeguridad.dbo.LoginsPermitidos
WHERE NombreUsuario = @NombreUsuario
AND (IPPermitida = @IPCliente OR IPPermitida = 'TODAS')
)
BEGIN
ROLLBACK;
PRINT 'Acceso denegado: Usuario o IP no autorizados.';
END
END;
GO
Este trigger es mucho más flexible. Puedes dar acceso a múltiples usuarios desde múltiples IPs, sin tener que tocar el código. Solo modificas los datos en la tabla. Que es como debe ser.
Y si, seguro que alguno está levantando la ceja por eso de usar EXECUTE AS ‘sa’ pero, es lo que hay. Es necesario para acceder a vistas como sys.dm_exec_connections si el usuario que se conecta no es sysadmin. No hay vuelta de hoja.
¿Y los errores? ¿Y los logs?
Todo esto está muy bien, pero cuando algo falla queremos saber qué ha pasado. Y sobre todo desde dónde.
Podemos mejorar el sistema añadiendo una tabla de log de errores y registrando ahí los intentos de conexión denegados:
CREATE TABLE LogErroresLogin (
Fecha DATETIME DEFAULT GETDATE(),
Usuario NVARCHAR(100),
IPOrigen NVARCHAR(48),
Motivo NVARCHAR(255)
);
Y dentro del trigger:
IF NOT EXISTS (...) -- como antes
BEGIN
INSERT INTO ConfigSeguridad.dbo.LogErroresLogin (Usuario, IPOrigen, Motivo)
VALUES (@NombreUsuario, @IPCliente, 'IP no permitida para este usuario');
ROLLBACK;
END
De esta forma no solo protegemos, sino que auditamos. Que es justo lo que queremos cuando las cosas se tuercen.
Cuidado con las metidas de pata
Este tipo de trigger tiene mucha potencia, pero también un alto potencial para dejarte fuera como si hubieras olvidado las llaves dentro del coche. Si te bloqueas a ti mismo por error, hay dos formas de volver a entrar en el servidor y recuperar el control.
La primera es iniciar SQL Server en modo de inicio mínimo (-f) o modo de usuario único (-m), y eliminar el trigger desde ahí. Es incómodo, requiere reiniciar servicios, y si lo haces en un entorno en producción, más te vale tener una buena excusa preparada.
La segunda, más limpia y menos traumática, es conectarte a través de DAC (Dedicated Admin Connection). Esta conexión especial está activa en todos los SQL Server, pero ojo: el acceso remoto mediante DAC sí está deshabilitado por defecto. Y eso, en muchos casos, es como si no existiera, porque muchos de nosotros no administramos los servidores desde la consola local del host.
Puedes habilitar el acceso remoto a DAC con esta instrucción:
sp_configure 'remote admin connections', 1;
RECONFIGURE;
Y aquí viene la parte clave, no puedes usar DAC desde el GUI de SSMS. Olvídate de escribir ADMIN:servidor en el cuadro de conexión: eso no funciona. Para conectarte por DAC necesitas usar sqlcmd, ya sea desde la línea de comandos o desde el modo SQLCMD en SSMS (sí, ese modo raro que muchos ignoran hasta que es demasiado tarde).
Desde consola, la conexión se haría así:
sqlcmd -S ADMIN:NombreServidor\Instancia -E
Y desde ahí, puedes desactivar el trigger como si nada hubiera pasado.
Así que, si vas a jugar con triggers de inicio de sesión, valida bien tu tabla de permisos, habilita y prueba DAC remota, y ten sqlcmd a mano. Porque cuando el trigger se ponga tonto, el Management Studio no te va a sacar del apuro. Y cuando eso pase, querrás tener un plan B que no incluya reiniciar producción en hora punta.
Conclusión
Sí, se puede restringir el acceso a SQL Server por IP. No, no es una funcionalidad nativa. Pero con un poco de código y sentido común, se puede controlar quién entra y desde dónde. Es una capa de seguridad adicional que, bien usada, puede salvarte de más de un disgusto. Especialmente si aún sigues permitiendo conexiones con el usuario sa desde equipos de usuarios. Que eso sí que es una mala práctica de campeonato.
El código completo lo tienes en mi cuenta de GitHub, como siempre. Si lo vas a implementar, hazlo con cabeza. Aquí no venimos a jugar con triggers, venimos a proteger entornos que importan.
Si tenéis alguna duda o sugerencia, podéis dejarla en Twitter, por mail o dejarnos un mensaje en los comentarios. Y recuerda que también tenemos un grupo de Telegram y un canal de YouTube a los que te puede unir. ¡Hasta la próxima!


