Mostrando entradas con la etiqueta AD. Mostrar todas las entradas
Mostrando entradas con la etiqueta AD. Mostrar todas las entradas
Una funcionalidad que se está utilizando mucho en las empresas es el Single Sign On (SSO), esto es, permitir que los usuarios se logueen una vez y accedan a todos los sistemas que necesiten, sin tener que ingresar nuevamente sus credenciales. Más allá de las graves implicaciones de seguridad que esto acarrea, es algo que se está utilizando mucho y que los administradores deben conocer.
El SSO no es otra cosa que kerberizar servicios, es decir, autenticar el usuario, obtener un ticket, y luego solicitar servicios con el ticket de sessión. En el caso de los servicios Web, MS integra fácilmente IIS con la autenticación de Active Directory. Apache, por su parte, también brinda esta posibilidad.
En este artículo mostraré los pasos necesarios para kerberizar Apache, es decir, permitir que un usuario acceda a un sitio web sólo si antes se autentica utilizando kerberos. La configuración mostrada es sobre un servidor GNU/Linux, y describe los pasos para kerberizar Apache tanto en una red con AD, como en una de MIT Keberos.
Se asume que el lector tiene ciertos conocimientos básicos de kerberos. Sino pueden leer los artículos que escribí anteriormente sobre el tema:
- Instalación de MIT Kerberos
- Configurar PAM para utilizar kerberos
- Autenticar con kerberos y almacenar información de usuarios con LDAP en GNU/Linux
- OpenLDAP kerberizado
Yendo al grano, los pasos de configuración son los siguientes:
1. Crear un usuario en el dominio que servirá como principal para el servicio HTTP (solicitud de tickets de servicio). El uso es como el de una cuenta de máquina.
En AD:
- Abrir Active Directory Users and Computers (ADUC)
- Ir al dominio donde se creará el usuario.
- Click derecho en Users
- Elegir New -> User
- Completar los datos y finalizar.
En MIT Kerberos:
# kadmin.local
Authenticating as principal root/admin@DVPEM.ORG with password.
kadmin.local: addprinc -randkey HTTP/apache.dvpem.org@DVPEM.ORG
WARNING: no policy specified for HTTP/apache.dvpem.org@DVPEM.ORG; defaulting to no policy
Principal "HTTP/apache.dvpem.org@DVPEM.ORG" created.
donde -randkey permite generar un password random.
2. Mapear el servicio HTTP con el usuario recién creado y exportar el keytab para ser utilizado en el servidor:
En AD:
ktpass -princ HTTP/apache.dvpem.org@DVPEM.ORG -mapuser DVPEM\pruebaapache -ptype KRB5_NT_PRINCIPAL -pass prueba -out C:\apache.keytab
donde:
-princ indica el nombre que tendrá el principal (servicio HTTP)
-mapuser indica el usuario con el que se mapea el servicio
-ptype especifica el tipo del principal
-pass asigna un password para el principal. Si utilizan un asterisco (*) el sistema pregunta el password.
-out especifica el nombre del archivo keytab a generar
Dependiendo del tipo de encripción soportado por el servidor y el cliente, puede ser necesario especificar el uso de encripción débil. Esto se realiza con:
-mapop set +desonly
-crypto all o bien -crypto DES-CBC-MD5
En MIT Kerberos:
kadmin.local: ktadd -k /root/apache.keytab HTTP/apache.dvpem.org
Entry for principal HTTP/apache.dvpem.org with kvno 5, encryption type AES-256 CTS mode with 96-bit SHA-1 HMAC added to keytab WRFILE:/root/apache.keytab.
Entry for principal HTTP/apache.dvpem.org with kvno 5, encryption type ArcFour with HMAC/md5 added to keytab WRFILE:/root/apache.keytab.
Entry for principal HTTP/apache.dvpem.org with kvno 5, encryption type Triple DES cbc mode with HMAC/sha1 added to keytab WRFILE:/root/apache.keytab.
Entry for principal HTTP/apache.dvpem.org with kvno 5, encryption type DES cbc mode with CRC-32 added to keytab WRFILE:/root/apache.keytab.
3. Copiar el keytab al servidor donde se encuentra Apache instalado. Cambiar el dueño del archivo y restringir los permisos. Si por ejemplo se copia el archivo a /etc/apache2/apache.keytab, ejecutar lo siguiente:
chown www-data:www-data /etc/apache2/apache.keytab
cmod 400 /etc/apache2/apache.keytab
4. Instalar en el servidor web las utilidades de kerberos y el módulo de Apache, y habilitar el módulo:
# apt-get install krb5-{config,user} libapache2-mod-auth-kerb
# a2enmod mod_auth_kerb
5. Configurar los valores de realm, KDCs, y dominios para kerberos. Esto es, editar las siguientes líneas del archivo /etc/krb5.conf
- En la sección libdefaults setear el nombre del realm:
default_realm = DVPEM.ORG
- En la sección realms, indicar cuáles son los servidores KDC para nuestro realm:
DVPEM.ORG = {
kdc = kdc01.dvpem.org:88
admin_server = kdc01.dvpem.org
}
- En la sección domain_realm, agregar los mapeos de dominio con realms:
.dvpem.org = DVPEM.ORG
dvpem.org = DVPEM.ORG
6. Testear si kerberos funciona correctamente. Para ello, solicitar un ticket de usuario, para un usuario válido del dominio:
$ kinit demasiadovivo@DVPEM.ORG
$ klist
7. Agregar la siguiente configuración a apache para el directorio que se desea autenticar con kerberos. En este ejemplo, la intención es autenticar el directorio /var/www/mipagina
<Directory /var/www/mipagina>
AuthType Kerberos
AuthName "Kerberos Login"
KrbMethodK5Passwd Off
KrbMethodNegotiate On
KrbAuthRealms DVPEM.ORG
KrbServiceName HTTP
Krb5KeyTab /etc/apache2/apache.keytab
require valid-user
</Directory>
donde:
AuthType Kerberos: especifica el tipo de autenticación
KrbMethodNegotiate On: habilita el uso de SPNEGO (GSSAPI-SASL)
KrbMethodK5Passwd Off: deshabilita el uso de password para la autenticación. Esto puede causar problemas con browsers que no soportan SPNEGO, o máquinas que no se encuentran unidas al dominio. En estos casos puede setearse este valor en On, pero esto permite el uso de autenticación BASIC (muy insegura).
KrbAuthRealms DVPEM.ORG: especifica el realm (o dominio)
KrbServiceName HTTP: nombre del servicio
Krb5KeyTab /etc/apache2/apache.keytab: donde se encuentra el keytab
require valid-user: fuerza a que el usuario sea validado antes de acceder.
8. Chequear que el ticket provisto por el servidor contiene un tipo de encripción que es consistente con los valores configurado en el keytab:
Obtener un ticket de servicio y listar los tipos de encripción:
kvno HTTP/apache.dvpem.org@DVPEM.ORG
klist -e
Mostrar los tipos de encripción configurados en el keytab:
klist -e -k -t /etc/apache2/apache.keytab
Si los valores no coinciden, el servicio no podrá ser utilizado.
NOTA: Hay que tener en cuenta que Windows 7 y 2008 dejaron de aceptar por defecto la encripción con DES, algo que puede causar errores en la autenticación.
9. Reiniciar Apache y probar la configuración accediendo a la página Web protegida con Kerberos.
Algo muy importante es que debe utilizarse el nombre DNS especificado en el keytab como nombre del servicio, dado que si se utiliza la IP o un alias, la autenticación no funcionará.
10. Errores, posibles causas y soluciones. A continuación se listan los errores con los que me topé al configurar el servicio y una explicación sobre cómo lo solucioné. Además incluí soluciones alternativas.
krb5_get_init_creds_password() failed: Cannot resolve network address for KDC in requested realm
- Verificar que tanto el registro A como el registro PTR del servidor se encuentren registrados. Si por ejemplo el nombre del servidor apache es apache.dvpem.org, debe ingresarse el registro PTR correspondiende a la IP de dicho servidor.
- El parámetro KrbAuthRealms de Apache debe estar seteado correctamente. Recordar que en este parámetro se especifica el realm (dominio) en mayúsculas:
KrbAuthRealms DVPEM.ORG
- Los kdc del dominio se encuentran seteados correctamente en el archivo /etc/krb5.conf. Un ejemplo de esta configuración es:
DVPEM.ORG = {
kdc = kdc01.dvpem.org:88
admin_server = kdc01.dvpem.org
}
failed to verify krb5 credentials: Server not found in Kerberos database
- El principal utilizado esta mal configurado en el keytab creado o en el atributo KrbServiceName de la configuración de Apache.
- Al acceder a la página debe utilizarse el nombre del servidor registrado en el keytab. Es decir, si el principal está designado para apache.dvpem.org, en el navegador debe utilziarse la dirección apache.dvpem.org.
failed to verify krb5 credentials: KDC has no support for encryption type
- El tipo de encripción aceptada por el servidor no es compatible con la encripción aceptada por el cliente, o bien los tipos de encripción configurados en el keytab no son compatibles con el servidor. Verificar obteniendo un ticket de servicio y la encripción soportada en el keytab:
kvno HTTP/apache.dvpem.org@DVPEM.ORG
klist -e
klist -e -k -t /etc/apache2/apache.keytab
Hay que tener en cuenta que Windows 7 y 2008 dejaron de aceptar por defecto la encripción con DES, algo que puede causar el error mencionado si se utilizan estos sistemas.
gss_acquire_cred() failed: Unspecified GSS failure. Minor code may provide more information (, )
- Revisar si no se encuentra seteado el valor "Use Kerberos DES encryption for this account" en la cuenta del usuario utilizada para el pricipal.
Referencias
- Kerberos Module for Apache - Configuration
- Configure Apache to use Kerberos authentication
- Kerberos authentication with Apache in a multi-domain Active Directory
- Single Sign On with Kerberos using Debian and Windows Server 2008 R2
- Kerberos-Based SSO with Apache
- Using mod_auth_kerb and Windows 2000/2003/2008R2 as KDC
- Apache on Linux and Single-Sign-On with Active Directory
- Active Directory and Apache Kerberos authentication
- JBoss Doc - Chapter 5. Configuring Microsoft Active Directory
- Ktpass
Etiquetas:
Active Directory,
AD,
apache,
articulos,
autenticacion,
debian,
GNU/Linux,
kerberos,
MIT Kerberos,
seguridad,
Single Sign On,
SSO,
web
Es muy importante para todo administrador de seguridad conocer en todo momento quienes tienen cuentas de usuario con privilegios elevados y "vigilarlos". A partir de esto se desprende que es todavía más importante saber cuando se otorgan privilegios a usuarios.
En todo dominio existen grupos de usuario utilizados por administradores o helpdesk que cuentan con mayores privilegios que los usuarios comunes, por obvias razones. El problema es cuando se asignan estos privilegios y no todos (o ninguno) los administradores están informados. El caso más riesgoso es cuando un atacante logra escalar privilegios gracias a algún exploit o vulnerabilidad conocida (se acuerdan de pass-the-hash?).
Active Directory posee grupos bien definidos con privilegios elevados, siendo "Domain Admins" el Dios supremo. Cada organización puede definir sus propios grupos, pero "Domain Admins" estará siempre presente como la autoridad máxima, así que debe estar auditado. Otros grupos de importancia son "Enterprise Admins", "Schema Admins" y "Backup Operators".
Este artículo brinda los pasos necesarios para auditar grupos en Active Directory y enviar mensajes de alerta por mail cuando un grupo crítico esté siendo modificado. De esta forma los responsables de Seguridad de la Información estarán notificados al instante cuando ocurra una brecha de seguridad donde un usuario escale privilegios en el dominio. Lo que se auditará serán inserciones y eliminaciones de usuarios en los grupos que corresponda.
Habilitar auditoría de grupos en AD
La auditoría de usuarios/grupos/workstations en AD se realiza de la misma manera que la auditoría de directorios. Para hacerlo hay que utilizar la herramienta "Active Directory Users and Computers" (ADUC). En esta debe dirigirse a View y tildar "Advanced Features" para poder ver las propiedades avanzadas de los objetos.
Con la opción habilitada, resta dirigirse a la unidad organizativa (OU) donde se encuentran los grupos a auditar. Tal vez deseen habilitar la auditoría para todos los usuarios, o para usuarios/grupos particulares. Para esta explicación habilitaremos la auditoría a todos los objetos de la OU Users. Entonces, dirigirse a la OU Users y abrir las propiedades, allí dirigirse a la pestaña Security y en esta dar al botón Advanced. En esta ventana dirigirse a la pestaña Auditing, dar al botón "Add...", escribir Everyone y dar Ok. En la lista de propiedades a auditar, tildar todo menos "Full control", "List contents", "Read all properties" y "Read Permissions" (las lecturas generan demasiados logs y no son de demasiada utilidad)
Lo que se hace con esta configuración es que cada vez que cualquier usuario (por eso se elige Everyone) modifique un objeto de la OU Users se genere una entrada en el log de Windows.
Probablemente se encuentren con que esta auditoría ya se encuentra habilitada y heredada de la configuración del dominio, pero si no es así, con los pasos anteriores podrán configurarla.
Hook al evento y envío de mail
Cuando el evento que deseamos auditar se dispare deberemos realizar alguna acción. Como comenté al principio, nuestra acción será enviar un mail a los encargados de la seguridad, y en el mismo colocaremos el contenido de la entrada de log que generó el evento.
Si bien es muy simple generar una tarea que envíe un mail avisando del evento, la información que puede contener el mismo es muy escueta y no sirve de mucho más que estar informado. Lo mejor es contar con un script que lea la entrada del log y envíe el mail con el contenido de la misma.
Script en PowerShell
En la mayoría de los blogs explican cómo utilizar la herramienta wevtutil para enviar la información de los logs en el mail cuando se ejecuta el evento. Wevtutil permite parsear los logs y obtener información, para lo cual es muy útil, pero para este caso, no lo es tanto. El problema es que estas soluciones se basan en crear un script que lee la última entrada del log que cumple con las condiciones del evento buscado, y de esta forma puede ocurrir que si dos o más eventos con las mismas características se generan en corto intervalo de tiempo, perdamos información.
La mejor solución que encontré es la explicada en el artículo Trigger a PowerShell Script from a Windows Event, a partir de la cual generé el siguiente script (luego de pelear un buen rato con PS), denominado eventreporter.ps1:
# Script by demasiadovivo
param($eventRecordID,$eventChannel)
$event = Get-WinEvent -Logname $eventChannel -FilterXPath "<QueryList><Query Id='0' Path='$eventChannel'><Select Path='$eventChannel'>*[System[(EventRecordID=$eventRecordID)]]</Select></Query></QueryList>"
$smtp_server = "mailserver.ejemplo.com"
$msg = New-Object Net.Mail.MailMessage
$msg.From = "security_alert@ejemplo.com"
$msg.To.Add("demasiadovivo@ejemplo.com")
$msg.subject = "ALERTA! se hicieron cambios en grupo crítico"
$data =$event.Message
$data = [String]::join([environment]::NewLine, $data)
$msg.body = $data
$smtp = new-object Net.Mail.SmtpClient($smtp_server)
$smtp.Send($msg)
Vayamos por partes para comprender su funcionamiento. El script primero obtiene los parámetros eventRecordID y eventChannel, donde eventRecordID es el valor que identifica la línea del log donde se encuentra el evento que disparó la acción, y eventChannel es el log donde se encuentra (System, Security, Application, etc). No confundir eventRecordID con eventID. El primero es el identificador de la entrada del evento, algo así como el número de línea dentro del log, mientras que eventID es el identificador que utiliza Windows para distinguir el tipo de evento (por ejemplo Logon). Estos valores los envía la tarea programada que se dispara con el evento, como veremos después.
El siguiente paso es obtener la entrada del log correspondiente al evento. Para ello se utiliza el comando Get-WinEvent y los valores de eventRecordID y eventChannel. El evento se obtiene con la consulta "<QueryList><Query Id='0' Path='$eventChannel'><Select Path='$eventChannel'>*[System[(EventRecordID=$eventRecordID)]]</Select></Query></QueryList>" que se encuentra en formato XML y utiliza el lenguaje XPath (http://en.wikipedia.org/wiki/XPath). Se utiliza XPath en las consultas porque internamente los logs se guardan en formato XML. Para entender un poco mejor cómo se arman consultas en este lenguaje, leer MSDN XPath Syntax.
Finalmente el script arma un mail con el contenido obtenido del log ($event.Message) y lo envía a las direcciones designadas. Una línea que puede llamar la atención es "[String]::join([environment]::NewLine, $data)". Me llevó más de 3 horas encontrar cómo hacer que el mensaje del log original conserve los enters, lo cual se logra a través de esa línea... en bash todo esto sería mucho más fácil...
Recuerden que para poder ejecutar scripts de PowerShell, primero deben cambiar la política de ejecución de la máquina. Esto se realiza ejecutando lo siguiente:
Set-ExecutionPolicy RemoteSigned
Asignar una tarea al evento
Bien, ya activamos la auditoría de los grupos y tenemos el script a ejecutar cuando el evento ocurra. El siguiente paso es asignar la ejecución del script con el evento. Esto se hace a través de la herramienta "Computer Management". Hay que tener en cuenta en este punto que la tarea deberá agregarse en todos los controladores de dominio (DC), dado que las modificaciones de grupos podrían realizarse en cualquiera de ellos.
Como todo en el mundo MS, nada es tan directo y uno termina teniendo que utilizar algunas artimañas para lograr lo que desea. Para poder entregar al script los argumentos eventRecordID y eventChannel hay que hacer algunas modificaciones manuales a una tarea, como veremos a continuación.
Primero hay que crear la tarea que se ejecutará al producirse el evento. Para ello, dirigirse a "Task Scheduler -> Task Scheduler Library" dentro de "Computer Management". Allí dando click derecho se elige "Create Task..." y se obtiene la ventana de configuración de la tarea. A la misma habrá que asignar un nombre y opcionalmente una descripción. Como queremos que se ejecute en modo batch, hay que cambiar el usuario con el que se ejecutará la tarea, así que clickear el botón "Change User or Group..." y escribir "SYSTEM" (o bien crear un usuario con los privilegios suficientes para leer logs).
En la pestaña "Triggers" se agrega la condición que debe darse para que se ejecute el script. En ella debe crearse un nuevo Trigger con "New..." y elegir la opción "On an event" como disparador de la tarea. Luego elegir "Custom" en las settings y dar a "Edit Event Filter...". En esta ventana ir a la pestaña "XML", seleccionar "Edit query manually" y utilizar el siguiente código:
<QueryList>
<Query Id="0" Path="Security">
<Select Path="Security">*[(System/EventID=4732) or (System/EventID=4733)] and *[EventData/Data [@Name='TargetUserName']='Backup Operators'] or *[(System/EventID=4728) or (System/EventID=4729)] and *[(EventData/Data[@Name='TargetUserName']='Domain Admins') or (EventData/Data[@Name='TargetUserName']='Schema Admins') or (EventData/Data[@Name='TargetUserName']='Enterprise Admins')]</Select>
</Query>
</QueryList>
Como se puede observar, la consulta es similar a la utilizada en el script, en formato XML y utilizando el lenguaje XPath para seleccionar los siguientes eventos:
- 4732/4733 se agregó/eliminó un usuario a un grupo local. Se utilizan en conjunto con el grupo "Backup Operators" que es local.
- 4728, 4729 se agregó/eliminó un usuario a un grupo global. Se utilizan en conjunto con los grupos "Domain Admins", "Schema Admins" y "Enterprise Admins" que son globales.
NOTA 1: si en un futuro desean auditar algún grupo universal, los identificadores de eventos son 4756 para cuando se agrega, y 4757 para cuando se elimina un usuario del grupo.
NOTA 2: para entender mejor la consulta, pueden observar la estructura XML de los eventos en MSDN Event Schema Elements.
Continuando en la pestaña "Actions", elegir "New" para agregar la ejecución del script. Dentro de la ventana emergente elegir la acción "Start a program", en el nombre del programa/script escribir "PowerShell.exe", y en la sección de argumentos escribir ".\eventreporter.ps1 -eventRecordID $(eventRecordID) -eventChannel $(eventChannel)", reemplazando el path del script por el que corresponda. Con esto ya termina la definición de la tarea y pueden dar OK para terminar.
Como se ve, se utilizan los parámetros eventRecordID y eventChannel en la llamada del script, los cuales se utilizan luego para obtener el identificador de la entrada. Acá es donde entra en juego la "magia" del administrador. Para variar, nada es coherente con las herramientas de MS y no es posible indicar, de forma directa, cómo asignar los valores a los parámetros... gracias MS!!! Por ello es necesario aplicar el siguiente artilugio.
Primero deben dar click derecho sobre la tarea recién creada, elegir la opción "Export" y guardar el XML en alguna ubicación. Supongamos que llamamos a este XML como el nombre de la tarea, "Eventos_criticos.xml". Una vez hecho esto, eliminen la tarea. Sí eliminen, ya la volveremos a crear a partir del XML.
Ahora abrir el XML recién generado con algún editor de texto y buscar la sección "<Triggers>". Dentro de la misma encontrarán la sección "<EventTrigger>". En ella colocar el siguiente código:
<ValueQueries>
<Value name="eventChannel">Event/System/Channel</Value>
<Value name="eventRecordID">Event/System/EventRecordID</Value>
<Value name="eventSeverity">Event/System/Level</Value>
</ValueQueries>
es decir, la sección completa debe quedar:
<Triggers>
<EventTrigger>
<Enabled>true</Enabled>
<Subscription><QueryList><Query Id="0" Path="Security"><Select Path="Security">*[(System/EventID=4732) or (System/EventID=4733)] and *[EventData/Data [@Name='TargetUserName']='Backup Operators'] or *[(System/EventID=4728) or (System/EventID=4729)] and *[(EventData/Data[@Name='TargetUserName']='Domain Admins') or (EventData/Data[@Name='TargetUserName']='Schema Admins') or (EventData/Data[@Name='TargetUserName']='Enterprise Admins')]</Select></Query></QueryList></Subscription>
<ValueQueries>
<Value name="eventChannel">Event/System/Channel</Value>
<Value name="eventRecordID">Event/System/EventRecordID</Value>
<Value name="eventSeverity">Event/System/Level</Value>
</ValueQueries>
</EventTrigger>
</Triggers>
Salvar los cambios en el XML.
Finalmente volvemos a crear la tarea a partir del XML modificado. Para ello ir a Task Scheduler, dar click derecho y elegir la opción "Import Task", la cual les permitirá buscar el archivo recién creado. Otra forma de hacer esto último es ejecutando desde consola el siguiente comando:
C:\>schtasks /create /TN "Event Viewer Tasks\Eventos_Criticos" /XML Eventos_criticos.xml
Lo que se hizo aquí es indicarle a la tarea cuáles son los valores que debe utilizar para los parámetros eventChannel (Event/System/Channel), eventRecordID (Event/System/EventRecordID) y eventSeverity (Event/System/Level), que luego entregará al script creado en la sección anterior. No hay forma de hacer esto modificando la tarea desde el GUI, esta es la única manera... lindo verdad?...
En los otros controladores de dominio solamente deberán importar el XML recién creado y copiar el script a una ubicación donde el DC pueda ejecutar.
Acerca de...
Como comentario final solo me resta renegar una vez más contra MS. Algo tan simple como auditar un log, que en algún *nix sería cosa de dos minutos, se convierte en un dolor de cabeza. Siguiendo los pasos que describo en este artículo podrán hacerlo en dos minutos, pero encontrar la información necesaria para poder armar esto me llevó casi dos tardes. Windows es fácil de usar para el usuario final, pero cuando se quiere hacer algo semi-avanzado de administración te hace la vida imposible.
Dirán, me quejo pero lo uso. Y si, no me queda otra, desgraciadamente la gran mayoría de las organizaciones con una infraestructura IT mediana utilizan Active Directory, y para ser administrador de seguridad, necesitas conocer esta tecnología y hacer cosas como la que describí en este artículo. Lo único que espero es que en algún momento se tome conciencia y se deje de utilizar esta bosta para pasar a algo mejor.
Referencias
- Trigger a PowerShell Script from a Windows Event
- AD DS Auditing Step-by-Step Guide
- Getting event log contents by email on an event log trigger
- Email with event log attachment on an event log trigger
- MSDN XPath Syntax
- Event Schema Elements
- Attaching Tasks to Event Viewer Logs and Events
- PowerShell Cookbook - Chapter 23. Event Logs
- PowerShell Cookbook - Appendix C. XPath Quick Reference
En todo dominio existen grupos de usuario utilizados por administradores o helpdesk que cuentan con mayores privilegios que los usuarios comunes, por obvias razones. El problema es cuando se asignan estos privilegios y no todos (o ninguno) los administradores están informados. El caso más riesgoso es cuando un atacante logra escalar privilegios gracias a algún exploit o vulnerabilidad conocida (se acuerdan de pass-the-hash?).
Active Directory posee grupos bien definidos con privilegios elevados, siendo "Domain Admins" el Dios supremo. Cada organización puede definir sus propios grupos, pero "Domain Admins" estará siempre presente como la autoridad máxima, así que debe estar auditado. Otros grupos de importancia son "Enterprise Admins", "Schema Admins" y "Backup Operators".
Este artículo brinda los pasos necesarios para auditar grupos en Active Directory y enviar mensajes de alerta por mail cuando un grupo crítico esté siendo modificado. De esta forma los responsables de Seguridad de la Información estarán notificados al instante cuando ocurra una brecha de seguridad donde un usuario escale privilegios en el dominio. Lo que se auditará serán inserciones y eliminaciones de usuarios en los grupos que corresponda.
Habilitar auditoría de grupos en AD
La auditoría de usuarios/grupos/workstations en AD se realiza de la misma manera que la auditoría de directorios. Para hacerlo hay que utilizar la herramienta "Active Directory Users and Computers" (ADUC). En esta debe dirigirse a View y tildar "Advanced Features" para poder ver las propiedades avanzadas de los objetos.
Con la opción habilitada, resta dirigirse a la unidad organizativa (OU) donde se encuentran los grupos a auditar. Tal vez deseen habilitar la auditoría para todos los usuarios, o para usuarios/grupos particulares. Para esta explicación habilitaremos la auditoría a todos los objetos de la OU Users. Entonces, dirigirse a la OU Users y abrir las propiedades, allí dirigirse a la pestaña Security y en esta dar al botón Advanced. En esta ventana dirigirse a la pestaña Auditing, dar al botón "Add...", escribir Everyone y dar Ok. En la lista de propiedades a auditar, tildar todo menos "Full control", "List contents", "Read all properties" y "Read Permissions" (las lecturas generan demasiados logs y no son de demasiada utilidad)
Lo que se hace con esta configuración es que cada vez que cualquier usuario (por eso se elige Everyone) modifique un objeto de la OU Users se genere una entrada en el log de Windows.
Probablemente se encuentren con que esta auditoría ya se encuentra habilitada y heredada de la configuración del dominio, pero si no es así, con los pasos anteriores podrán configurarla.
Hook al evento y envío de mail
Cuando el evento que deseamos auditar se dispare deberemos realizar alguna acción. Como comenté al principio, nuestra acción será enviar un mail a los encargados de la seguridad, y en el mismo colocaremos el contenido de la entrada de log que generó el evento.
Si bien es muy simple generar una tarea que envíe un mail avisando del evento, la información que puede contener el mismo es muy escueta y no sirve de mucho más que estar informado. Lo mejor es contar con un script que lea la entrada del log y envíe el mail con el contenido de la misma.
Script en PowerShell
En la mayoría de los blogs explican cómo utilizar la herramienta wevtutil para enviar la información de los logs en el mail cuando se ejecuta el evento. Wevtutil permite parsear los logs y obtener información, para lo cual es muy útil, pero para este caso, no lo es tanto. El problema es que estas soluciones se basan en crear un script que lee la última entrada del log que cumple con las condiciones del evento buscado, y de esta forma puede ocurrir que si dos o más eventos con las mismas características se generan en corto intervalo de tiempo, perdamos información.
La mejor solución que encontré es la explicada en el artículo Trigger a PowerShell Script from a Windows Event, a partir de la cual generé el siguiente script (luego de pelear un buen rato con PS), denominado eventreporter.ps1:
# Script by demasiadovivo
param($eventRecordID,$eventChannel)
$event = Get-WinEvent -Logname $eventChannel -FilterXPath "<QueryList><Query Id='0' Path='$eventChannel'><Select Path='$eventChannel'>*[System[(EventRecordID=$eventRecordID)]]</Select></Query></QueryList>"
$smtp_server = "mailserver.ejemplo.com"
$msg = New-Object Net.Mail.MailMessage
$msg.From = "security_alert@ejemplo.com"
$msg.To.Add("demasiadovivo@ejemplo.com")
$msg.subject = "ALERTA! se hicieron cambios en grupo crítico"
$data =$event.Message
$data = [String]::join([environment]::NewLine, $data)
$msg.body = $data
$smtp = new-object Net.Mail.SmtpClient($smtp_server)
$smtp.Send($msg)
Vayamos por partes para comprender su funcionamiento. El script primero obtiene los parámetros eventRecordID y eventChannel, donde eventRecordID es el valor que identifica la línea del log donde se encuentra el evento que disparó la acción, y eventChannel es el log donde se encuentra (System, Security, Application, etc). No confundir eventRecordID con eventID. El primero es el identificador de la entrada del evento, algo así como el número de línea dentro del log, mientras que eventID es el identificador que utiliza Windows para distinguir el tipo de evento (por ejemplo Logon). Estos valores los envía la tarea programada que se dispara con el evento, como veremos después.
El siguiente paso es obtener la entrada del log correspondiente al evento. Para ello se utiliza el comando Get-WinEvent y los valores de eventRecordID y eventChannel. El evento se obtiene con la consulta "<QueryList><Query Id='0' Path='$eventChannel'><Select Path='$eventChannel'>*[System[(EventRecordID=$eventRecordID)]]</Select></Query></QueryList>" que se encuentra en formato XML y utiliza el lenguaje XPath (http://en.wikipedia.org/wiki/XPath). Se utiliza XPath en las consultas porque internamente los logs se guardan en formato XML. Para entender un poco mejor cómo se arman consultas en este lenguaje, leer MSDN XPath Syntax.
Finalmente el script arma un mail con el contenido obtenido del log ($event.Message) y lo envía a las direcciones designadas. Una línea que puede llamar la atención es "[String]::join([environment]::NewLine, $data)". Me llevó más de 3 horas encontrar cómo hacer que el mensaje del log original conserve los enters, lo cual se logra a través de esa línea... en bash todo esto sería mucho más fácil...
Recuerden que para poder ejecutar scripts de PowerShell, primero deben cambiar la política de ejecución de la máquina. Esto se realiza ejecutando lo siguiente:
Set-ExecutionPolicy RemoteSigned
Asignar una tarea al evento
Bien, ya activamos la auditoría de los grupos y tenemos el script a ejecutar cuando el evento ocurra. El siguiente paso es asignar la ejecución del script con el evento. Esto se hace a través de la herramienta "Computer Management". Hay que tener en cuenta en este punto que la tarea deberá agregarse en todos los controladores de dominio (DC), dado que las modificaciones de grupos podrían realizarse en cualquiera de ellos.
Como todo en el mundo MS, nada es tan directo y uno termina teniendo que utilizar algunas artimañas para lograr lo que desea. Para poder entregar al script los argumentos eventRecordID y eventChannel hay que hacer algunas modificaciones manuales a una tarea, como veremos a continuación.
Primero hay que crear la tarea que se ejecutará al producirse el evento. Para ello, dirigirse a "Task Scheduler -> Task Scheduler Library" dentro de "Computer Management". Allí dando click derecho se elige "Create Task..." y se obtiene la ventana de configuración de la tarea. A la misma habrá que asignar un nombre y opcionalmente una descripción. Como queremos que se ejecute en modo batch, hay que cambiar el usuario con el que se ejecutará la tarea, así que clickear el botón "Change User or Group..." y escribir "SYSTEM" (o bien crear un usuario con los privilegios suficientes para leer logs).
En la pestaña "Triggers" se agrega la condición que debe darse para que se ejecute el script. En ella debe crearse un nuevo Trigger con "New..." y elegir la opción "On an event" como disparador de la tarea. Luego elegir "Custom" en las settings y dar a "Edit Event Filter...". En esta ventana ir a la pestaña "XML", seleccionar "Edit query manually" y utilizar el siguiente código:
<QueryList>
<Query Id="0" Path="Security">
<Select Path="Security">*[(System/EventID=4732) or (System/EventID=4733)] and *[EventData/Data [@Name='TargetUserName']='Backup Operators'] or *[(System/EventID=4728) or (System/EventID=4729)] and *[(EventData/Data[@Name='TargetUserName']='Domain Admins') or (EventData/Data[@Name='TargetUserName']='Schema Admins') or (EventData/Data[@Name='TargetUserName']='Enterprise Admins')]</Select>
</Query>
</QueryList>
Como se puede observar, la consulta es similar a la utilizada en el script, en formato XML y utilizando el lenguaje XPath para seleccionar los siguientes eventos:
- 4732/4733 se agregó/eliminó un usuario a un grupo local. Se utilizan en conjunto con el grupo "Backup Operators" que es local.
- 4728, 4729 se agregó/eliminó un usuario a un grupo global. Se utilizan en conjunto con los grupos "Domain Admins", "Schema Admins" y "Enterprise Admins" que son globales.
NOTA 1: si en un futuro desean auditar algún grupo universal, los identificadores de eventos son 4756 para cuando se agrega, y 4757 para cuando se elimina un usuario del grupo.
NOTA 2: para entender mejor la consulta, pueden observar la estructura XML de los eventos en MSDN Event Schema Elements.
Continuando en la pestaña "Actions", elegir "New" para agregar la ejecución del script. Dentro de la ventana emergente elegir la acción "Start a program", en el nombre del programa/script escribir "PowerShell.exe", y en la sección de argumentos escribir ".\eventreporter.ps1 -eventRecordID $(eventRecordID) -eventChannel $(eventChannel)", reemplazando el path del script por el que corresponda. Con esto ya termina la definición de la tarea y pueden dar OK para terminar.
Como se ve, se utilizan los parámetros eventRecordID y eventChannel en la llamada del script, los cuales se utilizan luego para obtener el identificador de la entrada. Acá es donde entra en juego la "magia" del administrador. Para variar, nada es coherente con las herramientas de MS y no es posible indicar, de forma directa, cómo asignar los valores a los parámetros... gracias MS!!! Por ello es necesario aplicar el siguiente artilugio.
Primero deben dar click derecho sobre la tarea recién creada, elegir la opción "Export" y guardar el XML en alguna ubicación. Supongamos que llamamos a este XML como el nombre de la tarea, "Eventos_criticos.xml". Una vez hecho esto, eliminen la tarea. Sí eliminen, ya la volveremos a crear a partir del XML.
Ahora abrir el XML recién generado con algún editor de texto y buscar la sección "<Triggers>". Dentro de la misma encontrarán la sección "<EventTrigger>". En ella colocar el siguiente código:
<ValueQueries>
<Value name="eventChannel">Event/System/Channel</Value>
<Value name="eventRecordID">Event/System/EventRecordID</Value>
<Value name="eventSeverity">Event/System/Level</Value>
</ValueQueries>
es decir, la sección completa debe quedar:
<Triggers>
<EventTrigger>
<Enabled>true</Enabled>
<Subscription><QueryList><Query Id="0" Path="Security"><Select Path="Security">*[(System/EventID=4732) or (System/EventID=4733)] and *[EventData/Data [@Name='TargetUserName']='Backup Operators'] or *[(System/EventID=4728) or (System/EventID=4729)] and *[(EventData/Data[@Name='TargetUserName']='Domain Admins') or (EventData/Data[@Name='TargetUserName']='Schema Admins') or (EventData/Data[@Name='TargetUserName']='Enterprise Admins')]</Select></Query></QueryList></Subscription>
<ValueQueries>
<Value name="eventChannel">Event/System/Channel</Value>
<Value name="eventRecordID">Event/System/EventRecordID</Value>
<Value name="eventSeverity">Event/System/Level</Value>
</ValueQueries>
</EventTrigger>
</Triggers>
Salvar los cambios en el XML.
Finalmente volvemos a crear la tarea a partir del XML modificado. Para ello ir a Task Scheduler, dar click derecho y elegir la opción "Import Task", la cual les permitirá buscar el archivo recién creado. Otra forma de hacer esto último es ejecutando desde consola el siguiente comando:
C:\>schtasks /create /TN "Event Viewer Tasks\Eventos_Criticos" /XML Eventos_criticos.xml
Lo que se hizo aquí es indicarle a la tarea cuáles son los valores que debe utilizar para los parámetros eventChannel (Event/System/Channel), eventRecordID (Event/System/EventRecordID) y eventSeverity (Event/System/Level), que luego entregará al script creado en la sección anterior. No hay forma de hacer esto modificando la tarea desde el GUI, esta es la única manera... lindo verdad?...
En los otros controladores de dominio solamente deberán importar el XML recién creado y copiar el script a una ubicación donde el DC pueda ejecutar.
Acerca de...
Como comentario final solo me resta renegar una vez más contra MS. Algo tan simple como auditar un log, que en algún *nix sería cosa de dos minutos, se convierte en un dolor de cabeza. Siguiendo los pasos que describo en este artículo podrán hacerlo en dos minutos, pero encontrar la información necesaria para poder armar esto me llevó casi dos tardes. Windows es fácil de usar para el usuario final, pero cuando se quiere hacer algo semi-avanzado de administración te hace la vida imposible.
Dirán, me quejo pero lo uso. Y si, no me queda otra, desgraciadamente la gran mayoría de las organizaciones con una infraestructura IT mediana utilizan Active Directory, y para ser administrador de seguridad, necesitas conocer esta tecnología y hacer cosas como la que describí en este artículo. Lo único que espero es que en algún momento se tome conciencia y se deje de utilizar esta bosta para pasar a algo mejor.
Referencias
- Trigger a PowerShell Script from a Windows Event
- AD DS Auditing Step-by-Step Guide
- Getting event log contents by email on an event log trigger
- Email with event log attachment on an event log trigger
- MSDN XPath Syntax
- Event Schema Elements
- Attaching Tasks to Event Viewer Logs and Events
- PowerShell Cookbook - Chapter 23. Event Logs
- PowerShell Cookbook - Appendix C. XPath Quick Reference
Etiquetas:
Active Directory,
AD,
ADUC,
articulos,
auditoria,
PowerShell,
scripts,
seguridad,
Windows 2008
Si son seguidores del blog, saben que utilizo un GNU/Linux unido a un dominio AD desde hace tiempo. Algo que siempre estuve por configurar es el automontaje de los shares para no tener que escribir las direcciones una y otra vez. Hoy llegó el momento =D
A continuación describiré un poco cómo acceder y montar shares SMB en GNU/Linux y luego les mostraré cómo hacer para que un share se monte automáticamente al inicio de sesión, utilizando el ticket kerberos que nos entrega el controlador de dominio en el login.
Montar shares
Para los que trabajan con GNU/Linux es muy común acceder sistemas de archivos Windows a través del protocolo SMB (CIFS es el nombre actual del protocolo). Samba posee una excelente compatibilidad con el protocolo y provee diversas herramientas para el acceso.
Una vez que Samba está instalado, acceder un servidor de archivos es tan simple como escribir la siguiente URL en su navegador de archivos favorito (Dolphin, Nautilus, Krusader, etc):
En una red hogareña, sin AD, la autenticación con el servidor se realiza utilizando el viejo NTLM, con lo cual, al tipear la URL anterior, el navegador les pedirá que ingresen las credenciales de un usuario válido (desde la visión del servidor).
Otra forma de acceder a los archivos es montar el sistema remoto en un directorio local. El paquete smbfs provee soporte para el sistema de archivos smb/cifs, el cual se puede utilizar en el comando mount de la siguiente manera:
Por supuesto que también es posible agregar una entrada en /etc/fstab para hacer el montaje más rápido y/o automático. La entrada en fstab correspondiente al ejemplo anterior es la siguiente:
Digo poco atractivas porque en ambos casos es necesario colocar las credenciales en texto plano. Con la segunda opción se evita que otro usuario abra el fstab y vea el password, pero igualmente no es del todo satisfactoria.
Automontar shares en redes corporativas
En una red corporativa con servidores Windows, es muy probable que se utilice Active Directory. La autenticación en estos entornos se lleva a cabo utilizando kerberos, aunque por defecto (al menos hasta Windows 2003) los servidores de archivos soportan NTLM por compatibilidad. Incluso en redes corporativas con servicios integrados con kerberos provistos por servidores GNU/Linux se está utilizando bastante Samba como protocolo para la compartición de archivos, lo que hace doblemente atractiva la siguiente explicación.
Ahora, gracias a Samba y PAM, es posible mejorar el esquema de clientes Linux dentro de la corporación. Algo muy común es que los usuarios de workstations con Windows tengan mapeos automáticos al realizar un login, como por ejemplo el disco F:\ apuntando al servidor server1.ejemplo.com. Un cliente GNU/Linux puede tener esta misma comodidad, con mapeos automáticos de shares de red al árbol de directorios de su máquina.
La siguiente configuración tiene en cuenta que la workstation GNU/Linux autentica usuarios contra Domain Controllers (o servidores kerberos de GNU/Linux) con PAM y kerberos, como se explicó en el artículo Configurar PAM para utilizar kerberos.
Utilizando el entorno descripto en el artículo, los usuarios contarán con un ticket kerberos luego de que se autentiquen. Como Samba es compatible con kerberos, no es necesario seguir ingresando las credenciales al montar o acceder un share, Samba hará la autenticación de forma transparente utilizando el ticket correspondiente.
No existe una alternativa segura para hacer que un usuario monte un share que no figure en el fstab, sólo un administrador puede hacerlo. Claro que no sirve colocar una entrada en fstab que intente montar automáticamente un share, dado que se hará a nombre de root y root no posee un ticket kerberos... es decir, access denied!
La solución entonces consta de dos pasos. Agregar la línea en el fstab, y luego configurar kde, gnome, o el desktop que utilicen, para que realice el mount cuando el usuario se loguea.
Teniendo en cuenta el ejemplo con el que venimos trabajando, deberá agregarse la siguiente línea en fstab para utilizar kerberos:
El siguiente paso es agregar un script que desmonte los shares una vez que el usuario ejecuta logout, porque si la misma workstation es compartida por diferentes usuarios, dejar el acceso a los shares de otro usuario no es buena idea. Esta tarea debe realizarse con un script similar al anterior:
To Do
Como bien dije, no es posible que los usuarios monten los shares que no se encuentren definidos en fstab. Es decir, en fstab deben figurar todos los shares disponibles para los usuarios de una dada workstation, porque sino no podrán montarlos. Esto es un inconveniente bastante molesto, dado que si el usuario puede acceder a los shares, no tiene mucho sentido restringir para que no pueda montarlo en el árbol de directorios local.
Existe, claro, una forma indirecta y que en general es considerada insegura. La misma se basa en otorgar setuid root al ejecutable mount.cifs. Con esto, cuando un usuario ejecute el comando mount.cifs, éste se ejecuta con permisos de root, y por consiguiente puede montar los shares, aunque en este caso, probablemente no funcione el ticket kerberos (no lo probé). Queda en ustedes si se deciden por esta alternativa.
Referencia
- Samba HowTo: Mount a CIFS Network Share [Mapped Drive] in openSUSE
A continuación describiré un poco cómo acceder y montar shares SMB en GNU/Linux y luego les mostraré cómo hacer para que un share se monte automáticamente al inicio de sesión, utilizando el ticket kerberos que nos entrega el controlador de dominio en el login.
Montar shares
Para los que trabajan con GNU/Linux es muy común acceder sistemas de archivos Windows a través del protocolo SMB (CIFS es el nombre actual del protocolo). Samba posee una excelente compatibilidad con el protocolo y provee diversas herramientas para el acceso.
Una vez que Samba está instalado, acceder un servidor de archivos es tan simple como escribir la siguiente URL en su navegador de archivos favorito (Dolphin, Nautilus, Krusader, etc):
smb://server1.ejemplo.com/donde server1.ejemplo.com es el nombre del servidor.
En una red hogareña, sin AD, la autenticación con el servidor se realiza utilizando el viejo NTLM, con lo cual, al tipear la URL anterior, el navegador les pedirá que ingresen las credenciales de un usuario válido (desde la visión del servidor).
Otra forma de acceder a los archivos es montar el sistema remoto en un directorio local. El paquete smbfs provee soporte para el sistema de archivos smb/cifs, el cual se puede utilizar en el comando mount de la siguiente manera:
mount -t cifs //server1.ejemplo.com /media/samba -o user=pepeAl ejecutar el comando anterior, aparecerá un prompt solicitando el password del usuario en cuestión.
Por supuesto que también es posible agregar una entrada en /etc/fstab para hacer el montaje más rápido y/o automático. La entrada en fstab correspondiente al ejemplo anterior es la siguiente:
//server1.ejemplo.com /media/samba cifs user,auto,username=pepe 0 0donde las opciones son:
user -> para que lo pueda montar un usuario común (sin ser root)Claro que al intentar montar el sistema solicitará el password correspondiente. Hay dos formas de evitar que esto pase, aunque ninguna es muy atractiva:
auto -> debe montarse automáticamente al iniciar el sistema
username=pepe -> especifica el nombre del usuario a utilizar
- utilizar la opción password=y luego utilizar la opción credentials=/home/pepe/cred.smb en fstab.
- crear un archivo (por ejemplo /home/pepe/cred.smb) que contenga las líneas:
username=pepe
password=elpassword
Digo poco atractivas porque en ambos casos es necesario colocar las credenciales en texto plano. Con la segunda opción se evita que otro usuario abra el fstab y vea el password, pero igualmente no es del todo satisfactoria.
Automontar shares en redes corporativas
En una red corporativa con servidores Windows, es muy probable que se utilice Active Directory. La autenticación en estos entornos se lleva a cabo utilizando kerberos, aunque por defecto (al menos hasta Windows 2003) los servidores de archivos soportan NTLM por compatibilidad. Incluso en redes corporativas con servicios integrados con kerberos provistos por servidores GNU/Linux se está utilizando bastante Samba como protocolo para la compartición de archivos, lo que hace doblemente atractiva la siguiente explicación.
Ahora, gracias a Samba y PAM, es posible mejorar el esquema de clientes Linux dentro de la corporación. Algo muy común es que los usuarios de workstations con Windows tengan mapeos automáticos al realizar un login, como por ejemplo el disco F:\ apuntando al servidor server1.ejemplo.com. Un cliente GNU/Linux puede tener esta misma comodidad, con mapeos automáticos de shares de red al árbol de directorios de su máquina.
La siguiente configuración tiene en cuenta que la workstation GNU/Linux autentica usuarios contra Domain Controllers (o servidores kerberos de GNU/Linux) con PAM y kerberos, como se explicó en el artículo Configurar PAM para utilizar kerberos.
Utilizando el entorno descripto en el artículo, los usuarios contarán con un ticket kerberos luego de que se autentiquen. Como Samba es compatible con kerberos, no es necesario seguir ingresando las credenciales al montar o acceder un share, Samba hará la autenticación de forma transparente utilizando el ticket correspondiente.
No existe una alternativa segura para hacer que un usuario monte un share que no figure en el fstab, sólo un administrador puede hacerlo. Claro que no sirve colocar una entrada en fstab que intente montar automáticamente un share, dado que se hará a nombre de root y root no posee un ticket kerberos... es decir, access denied!
La solución entonces consta de dos pasos. Agregar la línea en el fstab, y luego configurar kde, gnome, o el desktop que utilicen, para que realice el mount cuando el usuario se loguea.
Teniendo en cuenta el ejemplo con el que venimos trabajando, deberá agregarse la siguiente línea en fstab para utilizar kerberos:
//server1.ejemplo.com /media/samba cifs user,noauto,sec=krb5 0 0las opciones relevantes aquí son:
noauto -> no montar automáticamentePara el automontaje se crea un script en bash (o su shell favorito) con el siguiente contenido:
sec=krb5 -> indica a samba que utilice kerberos en la autenticación
#!/bin/bashy se coloca en el directorio correspondiente (dándole ejecución con chmod +x) para que desktop lo ejecute al iniciar la sesión del usuario. Por ejemplo:
mount //server1.ejemplo.com
- en kde deberá colocarse en $HOME/.kde/Autostart/De esta forma, una vez que el usuario se validó contra kerberos, el sistema automáticamente montará sus shares en el lugar correspondiente, una verdadera comodidad, y un paso más para extender el uso de GNU/Linux en las corporaciones =)
- en gnome debe abrirse el "Gnome Control Center" ir a "aplicaciones al inicio" y agregar la ruta al script.
El siguiente paso es agregar un script que desmonte los shares una vez que el usuario ejecuta logout, porque si la misma workstation es compartida por diferentes usuarios, dejar el acceso a los shares de otro usuario no es buena idea. Esta tarea debe realizarse con un script similar al anterior:
#!/bin/bashy colocarlo en el directorio correspondiente al desktop que utilicen. Por ejemplo:
umount //server1.ejemplo.com
- en kde existe el directorio $HOME/.kde/shutdow destinado a tal fin
- en gnome ??? (avísenme si lo encuentran)
To Do
Como bien dije, no es posible que los usuarios monten los shares que no se encuentren definidos en fstab. Es decir, en fstab deben figurar todos los shares disponibles para los usuarios de una dada workstation, porque sino no podrán montarlos. Esto es un inconveniente bastante molesto, dado que si el usuario puede acceder a los shares, no tiene mucho sentido restringir para que no pueda montarlo en el árbol de directorios local.
Existe, claro, una forma indirecta y que en general es considerada insegura. La misma se basa en otorgar setuid root al ejecutable mount.cifs. Con esto, cuando un usuario ejecute el comando mount.cifs, éste se ejecuta con permisos de root, y por consiguiente puede montar los shares, aunque en este caso, probablemente no funcione el ticket kerberos (no lo probé). Queda en ustedes si se deciden por esta alternativa.
Referencia
- Samba HowTo: Mount a CIFS Network Share [Mapped Drive] in openSUSE
Etiquetas:
Active Directory,
AD,
administracion,
articulos,
CIFS,
GNU/Linux,
kerberos,
Samba,
SMB
Uno de los servicios más utilizados actualmente para la autenticación en diferentes organizaciones es kerberos. Cualquiera que utilice o haya utilizado Active Directory seguramente conozca, aunque sea vagamente, kerberos, dado que este entorno lo utiliza como base. También se utiliza bastante en soluciones empresariales de Red Hat.
Dado que es un servicio de mucha importancia y uno de los que cualquier persona que trabaje en administración de sistemas o seguridad debe conocer, me parece bien dedicar un artículo para describir como funciona. En un próximo artículo veremos cómo instalarlo y configurarlo en GNU/Linux.
Este artículo forma parte del proyecto Autenticación y administración centralizada de usuarios en GNU/Linux.
Qué es?
Kerberos es un protocolo de autenticación desarrollado por el MIT e implementado en varios sistemas operativos. La principal función es permitir que dos nodos puedan autenticarse entre sí sobre una red insegura. Se utiliza principalmente en modelos cliente-servidor donde cliente y servidor pueden autenticarse mutuamente.
Kerberos funciona utilizando criptografía simétrica y requiere de una tercera parte confiable (siempre hay que confiar en alguien...).
Dato interesante: el nombre kerberos proviene del perro con tres cabezas y cola de serpiente, guardian de la entrada del templo de Hades en la mitología griega. El nombre era acertado porque la idea era proveer 3 mecanismos de seguridad: autenticación, contabilidad y auditoria. Desgraciadamente, sólo se implementó el componente de autenticación.
En el modelo kerberos contamos con dos servidores lógicos (que en la práctica suelen estar implementados en un sólo servidor físico denominado Key Distribution Center o KDC):
Qué servicios se puede acceder con un ticket de kerberos? cualquiera que implemente este tipo de autenticación. Por ejemplo, la autenticación de usuarios en un sistema operativo, acceso a servicios ldap, web, smtp, etc. Para poder utilizar un servicio kerberizado, el cliente debe primero contactar al AS y el TGS para obtener un ticket, que luego utiliza para acceder el servicio.
Los tickets tienen una validez de tiempo limitada, para lo cual se utilizan timestamps. Debido a esto, tanto clientes como servidores deben tener sus relojes sincronizados, porque sino el sistema no funciona. Normalmente esta sincronización se realiza utilizando el protocolo NTP.
Descripción del protocolo
El handshake de autorización para acceder a un servicio es la siguiente:
Resumiendo, obtenemos el siguiente flujo:
Sí, parece (o es) tremendo lío el sistema de autenticación, pero es efectivo y seguro, y prestando atención llega a entenderse bien (aunque con el tiempo uno se vuelve a olvidar =P).
Gracias a que la autenticación con usuario y contraseña genera el TGT, para acceder a distintos servicios sólo necesitamos este ticket, por lo cual no es necesario cargar las credenciales por cada servicio accedido. Esto permite que sistemas como el single sign-on funcionen. Además el TGT puede ser renovable dentro de un dado período de tiempo, lo que da flexibilidad a servicios que necesitan mucho tiempo para completarse.
Se desprende de la explicación anterior que el KDC contiene todas las credenciales de todos sus usuarios. Obviamente estas credenciales no se almacenan de forma plana en la base de datos. La base de datos se encripta utilizando una master key que el administrador debe elegir al momento de configurar el KDC. Pero esta master key también debe estar almacenada en algún lugar si se desea que el servicio se cargue automáticamente! En el kerberos de MIT la master key se almacena en el archivo stash. En AD existe un usuario denominado kbrtgt cuya contraseña es la utilizada como master key del KDC, este usuario no puede loguearse y está deshabilitado.
Limitaciones y desventajas
Terminología
En el mundo kerberos existen ciertas definiciones que es necesario conocer para poder configurarlo correctamente. Veamos entonces los términos utilizados:
Referencias
- Kerberos protocol wik
- The Kerberos protocol and its implementation
- Kerberos FAQ, v2.0
Dado que es un servicio de mucha importancia y uno de los que cualquier persona que trabaje en administración de sistemas o seguridad debe conocer, me parece bien dedicar un artículo para describir como funciona. En un próximo artículo veremos cómo instalarlo y configurarlo en GNU/Linux.
Este artículo forma parte del proyecto Autenticación y administración centralizada de usuarios en GNU/Linux.
Qué es?
Kerberos es un protocolo de autenticación desarrollado por el MIT e implementado en varios sistemas operativos. La principal función es permitir que dos nodos puedan autenticarse entre sí sobre una red insegura. Se utiliza principalmente en modelos cliente-servidor donde cliente y servidor pueden autenticarse mutuamente.
Kerberos funciona utilizando criptografía simétrica y requiere de una tercera parte confiable (siempre hay que confiar en alguien...).
Dato interesante: el nombre kerberos proviene del perro con tres cabezas y cola de serpiente, guardian de la entrada del templo de Hades en la mitología griega. El nombre era acertado porque la idea era proveer 3 mecanismos de seguridad: autenticación, contabilidad y auditoria. Desgraciadamente, sólo se implementó el componente de autenticación.
En el modelo kerberos contamos con dos servidores lógicos (que en la práctica suelen estar implementados en un sólo servidor físico denominado Key Distribution Center o KDC):
- Authentication Server (AS): servidor encargado de autenticar al cliente y proveer un ticket para contactar al TGS. Este servidor almacena la clave de los clientes y las utiliza para autenticarlos.
- Ticket Granting Server (TGS): servidor encargado de proveer tickets a los clientes para que puedan acceder al servicio deseado.
Qué servicios se puede acceder con un ticket de kerberos? cualquiera que implemente este tipo de autenticación. Por ejemplo, la autenticación de usuarios en un sistema operativo, acceso a servicios ldap, web, smtp, etc. Para poder utilizar un servicio kerberizado, el cliente debe primero contactar al AS y el TGS para obtener un ticket, que luego utiliza para acceder el servicio.
Los tickets tienen una validez de tiempo limitada, para lo cual se utilizan timestamps. Debido a esto, tanto clientes como servidores deben tener sus relojes sincronizados, porque sino el sistema no funciona. Normalmente esta sincronización se realiza utilizando el protocolo NTP.
Descripción del protocolo
El handshake de autorización para acceder a un servicio es la siguiente:
- Cliente C contacta al AS requieriendo acceso a un servicio del Service Server (SS).
- AS utiliza la clave que tiene almacenada del usuario (user master key) para encriptar la clave de sesión necesaria para encriptar los mensajes con el TGS (TGSsk). Además, AS envía al cliente otra tupla (denominada Ticket Granting Ticket - TGT) pero encriptada con la clave del TGS, la cual contiene el ID del cliente, la dirección de red del mismo, el tiempo de validez del ticket y la clave de sesión (TGSsk).
- Cuando el cliente recibe los mensajes, desencripta el primero para obtener la clave de sesión TGSsk. Al desencriptar este mensaje, prueba quién es, dado que otro cliente no tendrá la clave necesaria para desencriptar el mensaje. El TGT no lo desencripta porque está encriptado con la clave del TGS.
- El cliente ahora envía el TGT al TGS y un mensaje autenticador, compuesto por el ID del cliente y el timestamp, encriptado con la clave de sesión TGSsk.
- Una vez que el TGS recibe los mensajes del cliente, desencripta el TGT para obtener la clave de sesión TGSsk, y con esta clave desencripta el otro mensaje (el autenticador) y responde al cliente enviando un nuevo ticket, muy similar al TGT, pero para ser utilizado con el Service Server, que provee el servicio deseado (por ejemplo ldap). Este mensaje contiene el ID del cliente, la dirección de red, el período de validez y una nueva clave de sesión para utilizar con el servidor (SSsk). Además, envía otro mensaje que contiene el SSsk, encriptado con la clave de sesión del TGS (TGSsk).
- Finalmente el cliente tiene todo lo necesario para acceder el servicio que desea, por lo que contacta al SS enviando el ticket que recibió del TGS y un nuevo autenticador encriptado con la SSsk.
- SS desencripta el ticket recibido para obtener la clave de sesión SSsk, con la cual desencripta el autenticador del cliente. SS responde con el último mensaje del handshake inicial que contiene el timestamp encontrado en el autenticador del cliente más 1, encriptado con la clave de sesión SSsk.
- Con el último mensaje el cliente puede comprobar la autenticidad del servidor.
Resumiendo, obtenemos el siguiente flujo:
C ---- pedido de servicio -----> AS
AS ---- TGSsk encriptada con clave del cliente ----> C
AS ---- TGT ----> C
C ---- TGT ----> TGS
C ---- autenticador encriptado con TGSsk ----> TGS
TGS ---- ticket para acceder servicio ----> C
TGS ---- SSsk encriptado con clave del cliente ----> C
C ----> ticket para acceder servicio ----> SS
C ----> autenticador encriptado con SSsk ----> SS
SS ----> timestamp +1 encriptado con la clave de sesión SSsk ----> C
Sí, parece (o es) tremendo lío el sistema de autenticación, pero es efectivo y seguro, y prestando atención llega a entenderse bien (aunque con el tiempo uno se vuelve a olvidar =P).
Gracias a que la autenticación con usuario y contraseña genera el TGT, para acceder a distintos servicios sólo necesitamos este ticket, por lo cual no es necesario cargar las credenciales por cada servicio accedido. Esto permite que sistemas como el single sign-on funcionen. Además el TGT puede ser renovable dentro de un dado período de tiempo, lo que da flexibilidad a servicios que necesitan mucho tiempo para completarse.
Se desprende de la explicación anterior que el KDC contiene todas las credenciales de todos sus usuarios. Obviamente estas credenciales no se almacenan de forma plana en la base de datos. La base de datos se encripta utilizando una master key que el administrador debe elegir al momento de configurar el KDC. Pero esta master key también debe estar almacenada en algún lugar si se desea que el servicio se cargue automáticamente! En el kerberos de MIT la master key se almacena en el archivo stash. En AD existe un usuario denominado kbrtgt cuya contraseña es la utilizada como master key del KDC, este usuario no puede loguearse y está deshabilitado.
Limitaciones y desventajas
- La obvia desventaja de un sistema de autenticación centralizado es el único punto de falla. Si se cae el AS o el TGS, nadie puede acceder a ningún servicio. Esto se soluciona utilizando más de un servidor y replicando los datos.
- Todos los participantes deben tener coordinados sus relojes, porque sino, los tickets no funcionan.
- Dado que todas las claves se almacenan en un servidor, si un atacante logra hackearlo, podrá acceder como cualquier usuario!
- Otro problema es el replay attack, un ataque que no simple, pero tampoco imposible como se demuestra en el paper Replay Attack on Kerberos V and SMB.
Terminología
En el mundo kerberos existen ciertas definiciones que es necesario conocer para poder configurarlo correctamente. Veamos entonces los términos utilizados:
- Realm (reino, interesante nombre): indica el dominio de autenticación. El realm establece los límites en los cuales un servidor de autenticación tiene autoridad para autenticar usuarios, hosts o servicios. Es posible, sin embargo, realizar autenticaciones cross-realm entre, por ejemplo, un usuario de un realm y un servicio de otro. Esto se lleva a cabo a través de una relación de confianza entre los realms que debe ser establecida previamente. Básicamente un usuario/servicio pertenece a un realm sólo si comparte un secreto (password/key) con el servidor de autenticación. Es recomendable que el nombre del realm sea igual al del dominio (DNS) en el que nos encontramos, escrito con letras mayúsculas (los nombres son case-sensitive). Si nuestro dominio es demasiadovivo.org, lo aconsejable es nombrar al realm DEMASIADOVIVO.ORG.
- Principal: es el nombre utilizado para referirse a las entradas en la base de datos del servidor de autenticación. Cada usuario/host/servicio del realm tiene asociado un principal (string) que lo identifica. Ejemplos de principals son el nombre de usuario, el nombre de un host, etc. Cada principal puede tener varios componentes, pero generalmente se usan 3:
- primary: la primera parte del principal. En el caso de un usuario, este es su nombre de usuario. En el caso de un servicio, es el nombre del servicio.
- instance: la segunda parte de principal. Da información que califica al primary y puede ser null. En el caso de un usuario, el instance suele usarse para describir el uso para el cual están destinadas las credenciales. En el caso de un host, el instance es el hostname.
- realm: el nombre del realm en mayúsculas.
- Ticket: en la explicación anterior se describió el concepto de tickets en kerberos. Un ticket permite demostrar la autenticidad de un cliente. Los tickets caducan luego de un cierto tiempo, y es necesario obtener uno nuevo cuando esto sucede, o bien renovarlo si esto es posible.
- Keytab: es un archivo que contiene pares principal -> clave. Este archivo se puede utilizar para obtener tickets sin que el sistema pida password en el proceso de autenticación. El uso más común es en scripts que necesitan utilizar kerberos sin interacción humana. Los archivos keytab son muy importantes y deben mantenerse seguros.
Referencias
- Kerberos protocol wik
- The Kerberos protocol and its implementation
- Kerberos FAQ, v2.0
Etiquetas:
Active Directory,
AD,
administracion,
articulos,
autenticacion,
kerberos,
seguridad
Desde que estoy en mi actual trabajo, me vi forzado a utilizar Active Directory (AD), a aprender de qué trata, cómo funciona, y cómo administrarlo.
Realmente este servicio me parece una buena idea por parte de MS, y a nivel empresa es muy útil. La experiencia en el trabajo me enseñó que cuando la cantidad de usuarios supera un cierto número, administrarlos por workstation y/o por servicio es muy complejo, inaceptable. Además, la facilidad de independizar al usuario de la workstation en la que se encuentra, es muy importante para muchas empresas.
El problema, claro está, es que AD es de MS, con todo lo que ello representa:
- código cerrado- licencias caras y limitantes- poco flexible- software malo (si, la idea de AD es buena, pero el soft de MS es malo)- hay que utilizar Windows- fuerza a utilizar más software MS, gracias a su política "incompatible con el mundo no MS"- no se puede aprender de él- mientras todo anda, es fácil, pero cuando algo falla, arreglarlo es extremadamente difícil- etc, etc
No es ningún secreto que MS no me cae bien, y creo que las razones anteriores son suficientes para ello.
Por eso me di a la tarea de buscar una alternativa libre que brinde capacidades similares. El objetivo es tener un sistema centralizado de usuarios, donde los usuarios tienen una identidad única para utilizar el sistema operativo (y las aplicaciones que utilicen autenticación integrada) desde cualquier máquina.
MS no inventó nada nuevo con Active Directory, sino que supo combinar protocolos que ya se utilizaban desde hace años y que mayoritariamente nacieron como protocolos libres, por lo cual existen alternativas para cada componente. El problema es unir estos componentes para que trabajen en conjunto.
Los componentes básicos para lograr la funcionalidad deseada son:
- Autenticación con Kerberos.- NTP para mantener sincronizados los relojes (requerimiento importante para kerberos).- Servicio de directorio LDAP para almacenar datos de usuarios, grupos, hosts, etc.- DNS para asignar nombres de dominio.- DHCP para distribuir direcciones IPs (opcional pero muy útil).- Replicación de los datos entre múltiples servidores (multi-master replication).- Administración de seguridad a través de políticas de grupo (GPOs).
Es claro que AD no se queda ahí y gracias al la integración con el resto del soft MS, es posible tener integrado servicio de email (Exchange), y servicio de archivos (SMB), entre otros.
Sacando las GPOs, todo el resto se puede lograr utilizando software libre, por ejemplo:
- MIT Kerberos- NTP- OpenLDAP- Bind (DNS)- Samba- Postfix
La tarea entonces es configurar los servicios para que trabajen en conjunto.
Existe mucha información en internet sobre cómo lograr que las herramientas interactúen, pero poco sobre proyectos que integren todo.
El más notable al respecto es la distribución Calculate Linux. Si bien todavía no probé esta distribución, la descripción de la misma es muy alentadora, ya que hasta permite integrar hosts Windows para que interactúen con los servidores Linux.
En base a lo expuesto, desde hace un par de meses estoy trabajando en armar una infraestructura como la de Active Directory, pero utilizando software libre y documentando todo al respecto, desde la definición de kerberos y LDAP, hasta la instalación y configuración de los diferentes servicios en servidores y clientes para lograr la funcionalidad deseada.
Como la información es mucha, decidí repartirla en varios artículos que iré publicando a lo largo del próximo mes (o tal vez dos meses). Uno de estos artículos ya lo publiqué hace un par de semanas, y trata sobre PAM.
La lista de artículos es la siguiente:
- Un servicio básico, el DNS: breve descripción y cómo utilizar bind
A medida que los vaya publicando, volveré a este artículo para actualizar los links y tener así todo integrado.
De los citados, sólo me falta escribir el de DNS, y puede que alguno lo termine partiendo en 2 por ser muy largos, pero básicamente no cambiará mucho a lo planteado.
También espero tener tiempo de armar un sistema de archivos y montar un servidor de mail con postfix, pero como viene la mano en el trabajo, puede que eso quede para más adelante.
Mi recomendación es que si les interesa la idea, vayan armando sus propios proyectos y compartan dudas, mejoras o lo que se les ocurra. Pueden utilizar comentarios en el blog o en la página de IT Freek Zone en facebook.
Les recomiendo utilizar máquinas virtuales para poder probar servidores y clientes con una sola máquina de forma rápida. Además clonando discos virtuales es fácil deshacer y volver a empezar.
Etiquetas:
Active Directory,
AD,
administracion,
articulos,
autenticacion,
bind,
DNS,
GNU/Linux,
kerberos,
LDAP,
Postfix,
Samba,
servers,
SMB
Suscribirse a:
Entradas (Atom)


