Mostrando entradas con la etiqueta Active Directory. Mostrar todas las entradas
Mostrando entradas con la etiqueta Active Directory. 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
En los artículos anteriores se explicaron las bases del funcionamiento y utilización de kerberos, LDAP y PAM. Además se explicó cómo autenticar usuarios de GNU/Linux utilizando kerberos. Con esta información en mente, ahora somos capaces de armar un servicio de autenticación centralizada para hosts GNU/Linux, que utilice estos ampliamente aceptados y utilizados servicios.
Para lograr que toda la información de usuarios y grupos se almacene y administre en servidores LDAP, debemos encontrar la forma de que las workstations GNU/Linux se comuniquen con LDAP para obtener los datos que comúnmente se encuentran en los archivos /etc/passwd, /etc/shadow y /etc/group.
En /etc/passwd tenemos los datos concernientes a los usuarios del sistema. Cada entrada representa un usuario y los campos almacenados son los siguientes:
El problema con PAM, es que no permite acceder el resto de la información del usuario almacenada en un LDAP, es decir, información comúnmente almacenada en passwd, shadow y group. Para ello debemos valernos de otra herramienta, llamada NSS (Name Service Switch).
NSS permite utilizar distintas fuentes para obtener diferentes tipos de datos comunes, como los datos de usuario citados anteriormente. Es decir, agrega transparencia al resto de los programas a la hora de acceder dinstinta información. NSS es la capa que permite a un administrador configurar los sistemas para que obtengan de fuentes remotas datos que normalmente se buscarían en archivos locales en /etc (como passwd, group, hosts, etc).
Gracias a NSS, ahora podremos almacenar los datos que nos interesen, como los de usuarios y grupos, en LDAP, simplemente configurando el archivo /etc/nsswitch.conf
Creación de usuarios en kerberos
Para autenticar usuarios con kerberos, primero debemos agregar los principals correspondientes en la base de datos. Agregar un principal para un usuario es tan fácil como ejecutar addprinc utilizando kadmin:
Creación de usuarios en LDAP
Si bien podríamos utilizar la autenticación LDAP para autenticar los usuarios, lo mejor es utilizar el confiable kerberos, y dejar LDAP para almacenar los datos de usuarios, grupos y demás.
Como vimos anteriormente, debemos almacenar ciertos atributos del usuario que normalmente estarían en /etc/passwd. Dado que la autenticación la realizamos con kerberos, no es necesario almacenar el password del usuario, aunque esto podría hacerse si se quisiera autenticar con LDAP.
Existe un RFCs (RFC 2307), que describe un mecanismo para mapear entidades UNIX al estándar X.500, para que los atributos se puedan resolver utilizando LDAP. Si bien este documento es experimental, se utiliza ampliamente en el mundo UNIX.
La librería NSS-LDAP utiliza este mapeo para resolver los atributos del usuario, por lo tanto es el formato que debemos adoptar para crear las entradas en el LDAP. OpenLDAP trae esquemas predefinidos para este mapeo, los cuales pueden encontrar en /etc/ldap/schema/nis.schema. Los objectClass que utilizaremos comúnmente son posixAccount, shadowAccount y posixGroup.
Veamos cómo se mapea cada campo del /etc/passwd en atributos LDAP:
,ou=People,dc=demasiadovivo,dc=org.
Por su parte, el equivalente de atributos para cada grupo es el siguiente:
,ou=Group,dc=demasiadovivo,dc=org.
Ahora que contamos con los datos suficientes para crear un usuario, creemos el archivo user1.ldif donde pondremos la definición de nuestro primer usuario y grupo.
En la definición encontramos varios objectClass. Para el caso de grupos, utilizamos la ya mencionada posixGroup, mientras que para usuarios usamos person, posixAccount, y shadowAccount. La clase person nos permite agregar información atributos como número de teléfono y descripción. Por su parte, shadowAccount permite agregar atributos concernientes al tratamiento de passwords, como el password en si, fecha de último cambio, y resto de información que se encuentra en /etc/shadow. Si bien no almacenaremos passwords en LDAP, sí resulta útil guardar el resto de la información referente al mismo.
Para agregar el usuario, ejecutamos ldapadd de la siguiente manera:
ldapadd -c -x -D cn=admin,dc=demasiadovivo,dc=org -W -f user1.ldif
Podemos verificar los datos recien ingresados con:
y
Configurar PAM para utilizar kerberos
Configurar NSS para utilizar LDAP
Como ya adelante en las secciones anteriores NSS (Name Service Switch) es una funcionalidad provista por la librería GNU C para independizar a las aplicaciones de la ubicación de los servicios.
Antíguamente los datos se buscaban en archivos locales como /etc/passwd, /etc/group, /etc/hosts, etc, pero con el crecimiento de tecnologías de base de datos centralizadas como DNS, NIS, LDAP, etc, se hizo evidente la necesidad de contar con un servicio que abstraiga al programa de la ubicación de los datos. Por ello se creó NSS, basándose en un método utilizado por Sun en Solaris 2.
NSS permite al administrador configurar dónde se encontrarán los datos de diferentes bases de datos a través del archivo nsswitch.conf. Incluso se puede establecer un orden sobre qué base de datos consultar primero. El programa sólo utiliza una llamada al sistema y se olvida de donde se encuentran los datos. Gracias a esto, cambiar de base de datos es muy simple. Este caso es muy similar al de PAM.
Entre las bases de datos que podemos configurar tenemos:
cp /etc/pam.d/{common-auth,common-account,common-password,common-session} /root/backup
Luego entenderán porque es necesario este backup.
Ahora si, instalamos la librería libnss-ldapd que provee servicios LDAP para NSS, y el demonio nslcd que es el encargado de realizar las búsquedas LDAP para los procesos que quieran información de usuarios, grupos, etc:
NOTA: Algo a tener en cuenta aquí es utilizar libnss-ldapd y no libnss-ldap. Con la segunda no pude realizar autenticación de usuarios utilizando GSSAPI, a pesar de mucho intentarlo. libnss-ldapd es más nueva y mejora varias cuestiones de libnss-ldap.
En la instalación, debconf requerirá algunos datos de configuración.
Para el paquete libnss-ldapd:
Se puede observar que el sistema intentará resolver los datos de usuario localmente, y si no puede, consultará al servidor ldap.
Como el demonio nscd cachea los valores, es necesario reiniciarlo:
Para testear la configuración, se puede utilizar el comando getent. Este comando permite obtener entradas de la base de datos administrativa, esto incluye passwd, group, hosts, services, protocols y networks.
La mejor forma de ver que todo está funcionando es obtener los datos de un usuario que esté declarado en el servidor LDAP, pero que no esté localmente. Si por ejemplo el usuario demasiadovivo no se encuentra declarado en el /etc/passwd local y si en el LDAP, pueden probar el siguiente comando:
Pueden corroborar que el usuario no existe localmente mirando /etc/passwd.
Si ejecutan "getent passwd" sin un nombre de usuario, pueden ver la base de datos completa de usuarios, que incluye a los locales y a los de LDAP.
Prueba de login
Bien, ya tenemos todo lo necesario para ver si nuestro sistema centralizado de usuarios está funcionando correctamente. Veamos los pasos que seguimos hasta aquí:
yeah! como se puede observar, el sistema automáticamente creó el directorio home y asignó los IDs correspondientes al usuario, como se declaró en la correspondiente entrada LDAP.
CUIDADO!
Algo que hay que tener muy en cuenta es que kerberos utiliza verificación de host resolviendo el nombre de la máquina desde donde nos conectamos. Por ello es necesario tener definido el nombre de la máquina y el mapeo IP-nombre (registro PTR) en el servidor DNS. Caso contrario, pueden encontrarse con el siguiente error en /var/log/auth.log:
Referencias
- Authentication against LDAP servers
- PADL Software Pty Ltd - nss_ldap
- OpenLDAP installation on Debian
- MIT Kerberos installation on Debian
- OpenLDAP provider with MIT Kerberos V on Debian squeeze
- OpenLDAPServer
- SingleSignOn
- The POSIX API
- Linux NSS (libnss) and nss_ldap problems and possible solutions
- LDAPClientAuthentication
- LDAP Implementation HOWTO - 2. LDAP authentication using pam_ldap and nss_ldap
- opensolaris - About the Name Service Switch
- NSS Wiki
- Linux Authentication Using OpenLDAP, Part One
- ZYNTRAX - Chapter 5. OpenLDAP Samples - 5.2 Securing the Directory
- SEAM Error Messages and Troubleshooting
- Kerberos and LDAP
- Replacing NIS with Kerberos and LDAP HOWTO
- LDAP System Administration - A.2 Name Service Switch (NSS)
Para lograr que toda la información de usuarios y grupos se almacene y administre en servidores LDAP, debemos encontrar la forma de que las workstations GNU/Linux se comuniquen con LDAP para obtener los datos que comúnmente se encuentran en los archivos /etc/passwd, /etc/shadow y /etc/group.
En /etc/passwd tenemos los datos concernientes a los usuarios del sistema. Cada entrada representa un usuario y los campos almacenados son los siguientes:
- credenciales (sólo el nombre de usuario se almacena en /etc/passwd, cuestiones de contraseña se encuentran en /etc/shadow)
- ID, identificador de usuario
- grupos a los cuales pertenece
- nombre real
- directorio home (ej: /home/demasiadovivo)
- shell a utilizar (opcional)
- nombre de login
- hash del password o el password encriptado.
- fecha del último cambio de password.
- edad mínima de un password, es decir, el número de días que el usuario debe esperar entre cambios de passwords.
- edad máxima de un password. Duración del password, es decir, cuanto tiempo podemos usar un password como máximo.
- período de advertencia. Cuántos días antes de que el password expire, el sistema debe avisar al usuario que esto sucederá.
- período de inactividad de un password. La cantidad de días que un password debe ser aceptado para generar uno nuevo, luego de que el password expiró. Una vez que este período expira, el usuario no podrá loguearse más y deberá contactar al administrador.
- fecha de expiración del usuario, en formato timestamp Unix.
- nombre de grupo
- contraseña de grupo encriptada (opcional)
- GID, o identificador de grupo
- lista de los usuarios que pertenecen al grupo
El problema con PAM, es que no permite acceder el resto de la información del usuario almacenada en un LDAP, es decir, información comúnmente almacenada en passwd, shadow y group. Para ello debemos valernos de otra herramienta, llamada NSS (Name Service Switch).
NSS permite utilizar distintas fuentes para obtener diferentes tipos de datos comunes, como los datos de usuario citados anteriormente. Es decir, agrega transparencia al resto de los programas a la hora de acceder dinstinta información. NSS es la capa que permite a un administrador configurar los sistemas para que obtengan de fuentes remotas datos que normalmente se buscarían en archivos locales en /etc (como passwd, group, hosts, etc).
Gracias a NSS, ahora podremos almacenar los datos que nos interesen, como los de usuarios y grupos, en LDAP, simplemente configurando el archivo /etc/nsswitch.conf
Creación de usuarios en kerberos
Para autenticar usuarios con kerberos, primero debemos agregar los principals correspondientes en la base de datos. Agregar un principal para un usuario es tan fácil como ejecutar addprinc utilizando kadmin:
# kadmin.localPodemos checkear que el usuario se creó correctamente ejecutando kinit y klist:
Authenticating as principal root/admin@DEMASIADOVIVO.ORG with password.
kadmin.local: addprinc demasiadovivo
WARNING: no policy specified for demasiadovivo@DEMASIADOVIVO.ORG; defaulting to no policy
Enter password for principal "demasiadovivo@DEMASIADOVIVO.ORG":
Re-enter password for principal "demasiadovivo@DEMASIADOVIVO.ORG":
Principal "demasiadovivo@DEMASIADOVIVO.ORG" created.
# kinit demasiadovivoLo que hicimos fue obtener un ticket para el usuario demasiadovivo (con kinit), y luego listar los tickets cacheados en la máquina (klist). Como pudieron ver, /tmp/krb5cc_0 es nuestro ticket. Con klist se pueden ver varias propiedades de los tickets, como algoritmos de encripción (-e), direcciones en las credenciales (-a), etc. kinit también acepta varios parámetros, como tiempo de vida (-l), hora de inicio (-s), renovar un ticket (-R), etc.
Password for demasiadovivo@DEMASIADOVIVO.ORG:
# klist
Ticket cache: FILE:/tmp/krb5cc_0
Default principal: demasiadovivo@DEMASIADOVIVO.ORG
Valid starting Expires Service principal
06/22/11 14:07:18 06/23/11 00:07:18 krbtgt/DEMASIADOVIVO.ORG@DEMASIADOVIVO.ORG
renew until 06/23/11 14:07:14
Creación de usuarios en LDAP
Si bien podríamos utilizar la autenticación LDAP para autenticar los usuarios, lo mejor es utilizar el confiable kerberos, y dejar LDAP para almacenar los datos de usuarios, grupos y demás.
Como vimos anteriormente, debemos almacenar ciertos atributos del usuario que normalmente estarían en /etc/passwd. Dado que la autenticación la realizamos con kerberos, no es necesario almacenar el password del usuario, aunque esto podría hacerse si se quisiera autenticar con LDAP.
Existe un RFCs (RFC 2307), que describe un mecanismo para mapear entidades UNIX al estándar X.500, para que los atributos se puedan resolver utilizando LDAP. Si bien este documento es experimental, se utiliza ampliamente en el mundo UNIX.
La librería NSS-LDAP utiliza este mapeo para resolver los atributos del usuario, por lo tanto es el formato que debemos adoptar para crear las entradas en el LDAP. OpenLDAP trae esquemas predefinidos para este mapeo, los cuales pueden encontrar en /etc/ldap/schema/nis.schema. Los objectClass que utilizaremos comúnmente son posixAccount, shadowAccount y posixGroup.
Veamos cómo se mapea cada campo del /etc/passwd en atributos LDAP:
- login name = uid
- user ID = uidNumber
- group ID = gidNumber
- nombre de usuario = cn para el nombre y sn para el apellido.
- directorio home = homeDirectory
- shell = loginShell (opcional)
Por su parte, el equivalente de atributos para cada grupo es el siguiente:
- nombre del grupo = cn
- contraseña = userPassword (opcional)
- group ID = gidNumber
- lista de usuarios = memberUid
Ahora que contamos con los datos suficientes para crear un usuario, creemos el archivo user1.ldif donde pondremos la definición de nuestro primer usuario y grupo.
dn: cn=Administrador_Seguridad,ou=Group,dc=demasiadovivo,dc=org cn: Administrador_Seguridad gidNumber: 2000 objectClass: top objectClass: posixGroup
dn: uid:demasiadovivo,ou=People,dc=demasiadovivo,dc=org uid: demasiadovivo uidNumber: 2000 gidNumber: 2000 cn: Victor objectClass: top objectClass: person objectClass: posixAccount objectClass: shadowAccount loginShell: /bin/bash homeDirectory: /home/demasiadovivo
Para agregar el usuario, ejecutamos ldapadd de la siguiente manera:
ldapadd -c -x -D cn=admin,dc=demasiadovivo,dc=org -W -f user1.ldif
Podemos verificar los datos recien ingresados con:
ldapsearch "(uid=demasiadovivo)" -x
ldapsearch "(cn=Administrador_Seguridad)" -x
Este paso ya se explicó en el artículo del mismo nombre que pueden encontrar aquí.
Configurar NSS para utilizar LDAP
Como ya adelante en las secciones anteriores NSS (Name Service Switch) es una funcionalidad provista por la librería GNU C para independizar a las aplicaciones de la ubicación de los servicios.
Antíguamente los datos se buscaban en archivos locales como /etc/passwd, /etc/group, /etc/hosts, etc, pero con el crecimiento de tecnologías de base de datos centralizadas como DNS, NIS, LDAP, etc, se hizo evidente la necesidad de contar con un servicio que abstraiga al programa de la ubicación de los datos. Por ello se creó NSS, basándose en un método utilizado por Sun en Solaris 2.
NSS permite al administrador configurar dónde se encontrarán los datos de diferentes bases de datos a través del archivo nsswitch.conf. Incluso se puede establecer un orden sobre qué base de datos consultar primero. El programa sólo utiliza una llamada al sistema y se olvida de donde se encuentran los datos. Gracias a esto, cambiar de base de datos es muy simple. Este caso es muy similar al de PAM.
Entre las bases de datos que podemos configurar tenemos:
- password: información de usuarios. Default /etc/passwd
- group: información de grupos de usuarios. Default: /etc/group
- shadow: contraseñas de usuario. Default: /etc/shadow
- hosts: nombres de computadoras. Default: /etc/hosts
- network: nombres de redes. Default: /etc/networks
- files: archivos, por ejemplo /etc/passwd
- compat: se puede usar para traer información de usuarios y grupos en archivos con nueva sitaxis como /etc/passwd, /etc/shadow, /etc/group
- dns: obtener la información de hosts de servidores DNS
- ldap: traer los datos del directorio LDAP
cp /etc/pam.d/{common-auth,common-account,common-password,common-session} /root/backup
Luego entenderán porque es necesario este backup.
Ahora si, instalamos la librería libnss-ldapd que provee servicios LDAP para NSS, y el demonio nslcd que es el encargado de realizar las búsquedas LDAP para los procesos que quieran información de usuarios, grupos, etc:
# apt-get install libnss-ldapd nslcd
En la instalación, debconf requerirá algunos datos de configuración.
Para el paquete libnss-ldapd:
- Servicios a configurar para que utilicen LDAP. Los valores por defecto sirven para la mayoría de los casos: passwd, shadow, y group.
- URI del servidor LDAP: ldap://ldap.demasiadovivo.org/
- DN base para las búsquedas ldap: dc=demasiadovivo,dc=org
passwd: files ldap group: files ldap shadow: files ldap
hosts: files dns networks: files
protocols: db files services: db files ethers: db files rpc: db files
netgroup: nis
Como el demonio nscd cachea los valores, es necesario reiniciarlo:
# /etc/init.d/nscd restart
La mejor forma de ver que todo está funcionando es obtener los datos de un usuario que esté declarado en el servidor LDAP, pero que no esté localmente. Si por ejemplo el usuario demasiadovivo no se encuentra declarado en el /etc/passwd local y si en el LDAP, pueden probar el siguiente comando:
$ getent passwd demasiadovivo demasiadovivo:x:2000:2000:Victor:/home/demasiadovivo:/bin/bash
Si ejecutan "getent passwd" sin un nombre de usuario, pueden ver la base de datos completa de usuarios, que incluye a los locales y a los de LDAP.
Prueba de login
Bien, ya tenemos todo lo necesario para ver si nuestro sistema centralizado de usuarios está funcionando correctamente. Veamos los pasos que seguimos hasta aquí:
- instalamos kerberos
- instalamos LDAP
- dimos de alta al usuario demasiadovivo en kerberos y configuramos un password
- dimos de alta al usuario demasiadovivo en LDAP, donde pusimos toda la información necesaria del /etc/passwd
- configuramos PAM en la máquina cliente para que autentique utilizando kerberos. Incluso agregamos una regla en common-session para que se cree un directorio home para los usuarios que no existan localmente.
- configuramos NSS en la máquina cliente para busque los datos del usuario en LDAP
machine login: demasiadovivo Password: Linux machine 2.6.32-5-amd64 #1 SMP Mon Mar 7 21:35:22 UTC 2011 x86_64
The programs included with the Debian GNU/Linux system are free software; the exact distribution terms for each program are described in the individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent permitted by applicable law. Creating directory '/home/demasiadovivo' machine@demasiadovivo:~$ id uid=2000(demasiadovivo) gid=2000(Administrador_Seguridad) grupos=2000(Administrador_Seguridad)
CUIDADO!
Algo que hay que tener muy en cuenta es que kerberos utiliza verificación de host resolviendo el nombre de la máquina desde donde nos conectamos. Por ello es necesario tener definido el nombre de la máquina y el mapeo IP-nombre (registro PTR) en el servidor DNS. Caso contrario, pueden encontrarse con el siguiente error en /var/log/auth.log:
pam_krb5(login:auth): (user demasiadovivo) credential verification failed: Hostname cannot be canonicalized
Referencias
- Authentication against LDAP servers
- PADL Software Pty Ltd - nss_ldap
- OpenLDAP installation on Debian
- MIT Kerberos installation on Debian
- OpenLDAP provider with MIT Kerberos V on Debian squeeze
- OpenLDAPServer
- SingleSignOn
- The POSIX API
- Linux NSS (libnss) and nss_ldap problems and possible solutions
- LDAPClientAuthentication
- LDAP Implementation HOWTO - 2. LDAP authentication using pam_ldap and nss_ldap
- opensolaris - About the Name Service Switch
- NSS Wiki
- Linux Authentication Using OpenLDAP, Part One
- ZYNTRAX - Chapter 5. OpenLDAP Samples - 5.2 Securing the Directory
- SEAM Error Messages and Troubleshooting
- Kerberos and LDAP
- Replacing NIS with Kerberos and LDAP HOWTO
- LDAP System Administration - A.2 Name Service Switch (NSS)
Etiquetas:
Active Directory,
administracion,
articulos,
autenticacion,
GNU/Linux,
kerberos,
LDAP,
PAM,
password,
seguridad
En artículos anteriores se explicó cómo funciona kerberos y la forma de utilizarlo en GNU/Linux. Las workstations con Linux instalado pueden autenticar sus usuarios contra servidores de este tipo, ya sea que los mismos utilicen Linux, Windows (Active Directory), o cualquier otro SO que implemente el estándar. La configuración descripta a continuación es la misma sin importar sobre qué plataforma se implemente el servicio kerberos. Es decir, se puede utilizar, por ejemplo, para autenticar clientes Linux contra el servicio Active Directory de Windows.Para la autenticación con kerberos, hay que instalar el módulo de PAM correspondiente, en todos los clientes. En debian, el paquete se denomina libpam-krb5:
# apt-get install krb5-{config,user} libpam-krb5Durante la instalación, debconf requerirá algunos datos para continuar:
- el nombre del realm: DEMASIADOVIVO.ORGEstos son los mismos datos que configuramos al instalar el servidor kerberos. Toda esta configuración se puede cambiar en el archivo /etc/krb5.conf.
- servidores kerberos para el realm, separados con espacios.
- servidor administrativo para el realm, para administrar cambio de contraseña.
En este archivo, como se explicó en la instalación del servidor, pueden eliminar todos los realms que aparecen en la instalación default (athena, mit, etc), y deberán agregar el dominio de su realm en la sección domain_realm:
[domain_realm]Luego de que se instala el módulo de kerberos, debian automáticamente establece en PAM que la autenticación de usuarios debe utilizar este protocolo. Si no están utilizando debian, tal vez requieran una configuración adicional para empezar a utilizarlo.
.demasiadovivo.org = DEMASIADOVIVO.ORG
demasiadovivo.org = DEMASIADOVIVO.ORG
Veamos entonces cómo deberían quedar cada uno de los archivos de PAM, y el significado de cada configuración:
/etc/pam.d/common-account
account [success=1 new_authtok_reqd=done default=ignore] pam_unix.soSe puede observar que este archivo es muy similar a cuando se utiliza sólo autenticación Unix. Para agregar la autenticación de kerberos, se agrega una línea final que invoca el módulo pam_krb5 con el argumento minimum_uid=1000.
account requisite pam_deny.so
account required pam_permit.so
account required pam_krb5.so minimum_uid=1000
En este caso, el sistema invoca tanto el módulo pam_unix como pam_krb5 como required, lo cual implica que si alguno de estos falla, la operación falla. El argumento "minimum_uid=1000" hace que la autenticación kerberos se aplique a los usuarios cuyo user ID sea mayor a 1000. Esto permite tener cuentas locales como la de root (uid=0), la cual no autentica contra kerberos.
/etc/pam.d/common-auth
auth [success=2 default=ignore] pam_krb5.so minimum_uid=1000En este archivo podemos ver como funciona la autenticación propiamente dicha. Primero se intenta autenticar con kerberos a los usuarios cuyo uid es mayor o igual a 1000. Si esto tiene éxito, se salta a la línea pam_permit (success=2) y el usuario puede entrar. Si la autenticación kerberos falla, se intenta con la autenticación unix tradicional, permitiendo password en blanco (nullok_secure), y utilizando el mismo password que se utilizó en la autenticación kerberos (try_first_pass). Esto último se hace para que el sistema no requiera el password dos veces cuando la autenticación kerberos falla. Si ninguna de las autenticaciones es exitosa, se niega el acceso (pam_deny).
auth [success=1 default=ignore] pam_unix.so nullok_secure try_first_pass
auth requisite pam_deny.so
auth required pam_permit.so
/etc/pam.d/common-pasword
password requisite pam_krb5.so minimum_uid=1000Para el cambio de password se utiliza como requisito pam_krb5 con uid mayor igual a 1000. Si esto falla, el password no se actualiza. Si el password kerberos se actualiza correctamente, se intenta actualizar el password local, utilizando el mismo pass ingresado para kerberos (use_authtok). El resto de los argumentos de pam_unix son los mismos que cuando se utiliza autenticación tradicional, donde obscure checkea fortaleza del pass, y sha512 es el algoritmo para hashear el pass.
password [success=1 default=ignore] pam_unix.so obscure use_authtok try_first_pass sha512
password requisite pam_deny.so
password required pam_permit.so
Algo a tener en cuenta aquí es que si la actualización del password local falla, la operación falla aunque el password kerberos no haya tenido problemas.
/etc/pam.d/common-session
session [default=1] pam_permit.soFinalmente en el archivo de session encontramos una regla adicional y opcional que es la de kerberos. Algo interesante que podemos hacer en este archivo es agregar una regla para la creación del directorio home del usuario.
session requisite pam_deny.so
session required pam_permit.so
session optional pam_krb5.so minimum_uid=1000
session required pam_unix.so
Si creamos un usuario en kerberos y no en la máquina cliente, cuando éste intente ingresar, el sistema arrojará error si el home no existe, porque este directorio no se crea al agregar el usuario.
Para esto, existe un módulo denominado pam_mkhomedir. Este módulo crea el directorio home del usuario cuando éste se loguea por primera vez. Si el directorio ya existe, no hace nada. Un argumento interesante para este módulo es skel, que permite especificar el esqueleto del directorio home.
Podemos modificar el archivo anterior para agregar esta funcionalidad, de la siguiente manera:
session [default=1] pam_permit.soCon esto, la próxima vez que se autentique un usuario en el cliente configurado, éste utilizará kerberos en lugar del tradicional sistema Unix. Claro que el usuario a utilizar debe estar previamente creado en el servidor kerberos.
session requisite pam_deny.so
session required pam_permit.so
session required pam_mkhomedir.so skel=/etc/skel/
session optional pam_krb5.so minimum_uid=1000
session required pam_unix.so
Una vez autenticados, se puede ver el ticket generado ejecutando klist:
$ klist
Ticket cache: FILE:/tmp/krb5cc_1000_s6uumi
Default principal: demasiadovivo@DEMASIADOVIVO.ORG
Valid starting Expires Service principal
09/24/11 08:08:07 09/24/11 18:07:57 krbtgt/DEMASIADOVIVO.ORG@DEMASIADOVIVO.ORG
renew until 09/24/11 18:08:07
Etiquetas:
Active Directory,
administracion,
articulos,
autenticacion,
GNU/Linux,
kerberos,
PAM,
password,
seguridad
Un protocolo que se ha popularizado muchísimo en los últimos años es LDAP. El mismo es utilizado en la mayoría de las empresas, ya sea con Active Directory o con alguna de las múltiples soluciones para GNU/Linux como OpenLDAP, o 389 Directory Server.
Existen librerías para la mayoría de los lenguajes de programación que soportan LDAP, por lo cual existen muchos programas que lo utilizan.
Este protocolo es la base de cualquier sistema de directorio actual (Active Directory entre ellos), y es muy importante que todo administrador y/o programador conozca acerca de el.
Este artículo los introducirá en el mundo LDAP, explicando de qué trata, cómo funciona, la terminología, cómo es la autenticación y el formato de las búsquedas. El mismo forma parte del proyecto Autenticación y administración centralizada de usuarios en GNU/Linux.
Qué es?
Lightweight Directory Access Protocol (LDAP) es una base de datos especial (no relacional) que provee servicios de directorio basado en el estándar X.500, diseñada para almacenar información basada en atributos y soportar filtros sofisticados en búsquedas. A diferencia de una base de datos relacional, LDAP está optimizado para realizar búsquedas y organiza de forma distinta los datos.
Piensen en un directorio como una guía telefónica. En la guía encontramos personas con sus atributos (nompre, apellido, dirección y teléfono) organizadas en base a la letra de su apellido.
Un directorio informático que estamos acostumbrados a utilizar es la lista de direcciones de email. En la lista de emails encontramos las direcciones de email de nustros contactos, así como el nombre, teléfono, dirección física, etc. Podemos filtrar esta lista para buscar compañeros de trabajo, de universidad, por nombre, etc.
El "Light" en el nombre de LDAP se debe a que es una implementación más liviana que el anterior estandar X.500 denominado Directory Access Protocol, el cual estaba diseñado para trabajar sobre el stack OSI.
El modelo de información en LDAP está basado en entradas. Una entrada es un conjunto de atributos que tiene un nombre único (Distinguished Name - DN). El DN es utilizado para distinguir la entrada unequívocamente y se arma a partir de su RDN (Relative Distinguished Name), construido a partir de algún/os atributo/s de la entrada, y el DN de la entrada padre. Cada atributo de la entrada tiene un tipo y uno o varios valores. Los tipos suelen representarse con un string nemotécnico como 'cn' (common name), 'c' (country), 'ou' (organization unit), etc.
La información del directorio se organiza en forma de árbol y a este se lo denomina directory information tree (DIT). La jerarquía del árbol se arma a partir de información geográfica tomando como base del árbol o bien el nombre DNS. Dentro de esta jerarquía se pueden definir varias unidades organizativas, personas, dispositivos, etc.
Un ejemplo de entrada LDAP es:
El protocolo utiliza el port TCP 389 por defecto, en caso de no utilizar ssl, y 636 en caso de hacerlo.
Esquemas, Clases de objeto, Atributos y entradas
Como vimos, el directorio está formado por entradas, las que a su vez están formadas por un conjunto de atributos. Estos atributos se agrupan en clases de objetos (objectClass), las que a su vez se empaquetan en esquemas (schemes). Todas las objectClass y los atributos se definen dentro de esquemas. En OpenLDAP pueden encontrar la definición de los atributos y clases de objetos en el directorio /etc/ldap/schema/.
Los atributos se definen por separado y se pueden utilizar en una o varias objectClass. Para poder utilizar un atributo en una entrada, ésta debe contener alguna objectClass que contenga el atributo, y a su vez, la objectClass debe estar incluida en algún esquema reconocido por el servidor LDAP.
Las objectClass se pueden organizar jerárquicamente, en cuyo caso heredan todas las propiedades de sus padres o SUPerior. Estas objectClass pueden ser STRUCTURAL, en cuyo caso se usan para crear entradas, AUXILIARY en cuyo caso se pueden agregar en cualquier entrada, o ABSTRACT. El ejemplo más común de objectClass ABSTRACT es top, que forma el mayor nivel de cualquier jerarquía objectClass. Cada una de estas definiciones pueden tener atributos obligatorios y otros opcionales.
Las entradas agrupan conjuntos de objectClass, donde cada una debe contener obligatoriamente (y sólo puede contener una) STRUCTURAL. Además, puede contener una ABSTRACT y un número arbitrario de AUXILIARY.
Autenticación
LDAP soporta varios métodos de autenticación para acceder al directorio, existiendo dos principales que deben ser soportados (según el estándar):
Búsquedas en el directorio
La sintaxis para realizar búsquedas no es muy intuitiva y muy distinta a la forma en que consultamos bases de datos relacionales a través de SQL, pero con el tiempo (como todo) uno se acostumbra.
Los parámetros son los siguientes:
Una excelente herramienta para realizar búsquedas en LDAP es ldapsearch, la cual viene en el paquete ldap-utils. Un ejemplo es el siguiente:
Lo que viene...
Próximamente publicaré un artículo sobre cómo instalar y configurar el servicio de directorio más utilizando en entornos *nix (principalmente GNU/Linux), denominado OpenLDAP.
Referencias
- OpenLDAP - 1. Introduction to OpenLDAP Directory Services
- LDAP Wiki
- Chapter 3. LDAP Schemas, objectClasses and Attributes
- 6. LDAP Lightweight Directory Access Protocol
- LDAP for Rocket Scientists
Existen librerías para la mayoría de los lenguajes de programación que soportan LDAP, por lo cual existen muchos programas que lo utilizan.
Este protocolo es la base de cualquier sistema de directorio actual (Active Directory entre ellos), y es muy importante que todo administrador y/o programador conozca acerca de el.
Este artículo los introducirá en el mundo LDAP, explicando de qué trata, cómo funciona, la terminología, cómo es la autenticación y el formato de las búsquedas. El mismo forma parte del proyecto Autenticación y administración centralizada de usuarios en GNU/Linux.
Qué es?
Lightweight Directory Access Protocol (LDAP) es una base de datos especial (no relacional) que provee servicios de directorio basado en el estándar X.500, diseñada para almacenar información basada en atributos y soportar filtros sofisticados en búsquedas. A diferencia de una base de datos relacional, LDAP está optimizado para realizar búsquedas y organiza de forma distinta los datos.
Piensen en un directorio como una guía telefónica. En la guía encontramos personas con sus atributos (nompre, apellido, dirección y teléfono) organizadas en base a la letra de su apellido.
Un directorio informático que estamos acostumbrados a utilizar es la lista de direcciones de email. En la lista de emails encontramos las direcciones de email de nustros contactos, así como el nombre, teléfono, dirección física, etc. Podemos filtrar esta lista para buscar compañeros de trabajo, de universidad, por nombre, etc.
El "Light" en el nombre de LDAP se debe a que es una implementación más liviana que el anterior estandar X.500 denominado Directory Access Protocol, el cual estaba diseñado para trabajar sobre el stack OSI.
El modelo de información en LDAP está basado en entradas. Una entrada es un conjunto de atributos que tiene un nombre único (Distinguished Name - DN). El DN es utilizado para distinguir la entrada unequívocamente y se arma a partir de su RDN (Relative Distinguished Name), construido a partir de algún/os atributo/s de la entrada, y el DN de la entrada padre. Cada atributo de la entrada tiene un tipo y uno o varios valores. Los tipos suelen representarse con un string nemotécnico como 'cn' (common name), 'c' (country), 'ou' (organization unit), etc.
La información del directorio se organiza en forma de árbol y a este se lo denomina directory information tree (DIT). La jerarquía del árbol se arma a partir de información geográfica tomando como base del árbol
Un ejemplo de entrada LDAP es:
dn: cn=demasiadovivo,dc=itfreekzone,dc=blogspot,dc=comEn el ejemplo, el DN es "cn=demasiadovivo,dc=itfreekzone,dc=blogspot,dc=com" que está formado por el atributo common name, y los atributos domain component (dc) de las entradas padre. El resto son los atributos de la entrada. Como pueden observar, una entrada puede contener referencias a otras entradas, como es el caso del atributo manager que referencia a la entrada "cn=Javiz,dc=je-photography,dc=blogspot,dc=com".
cn: demasiadovivo
givenName: demasiadovivo
mail: espameasiqueres@gmail.com
manager: cn=Javiz,dc=je-photography,dc=blogspot,dc=com
objectClass: person
El protocolo utiliza el port TCP 389 por defecto, en caso de no utilizar ssl, y 636 en caso de hacerlo.
Esquemas, Clases de objeto, Atributos y entradas
Como vimos, el directorio está formado por entradas, las que a su vez están formadas por un conjunto de atributos. Estos atributos se agrupan en clases de objetos (objectClass), las que a su vez se empaquetan en esquemas (schemes). Todas las objectClass y los atributos se definen dentro de esquemas. En OpenLDAP pueden encontrar la definición de los atributos y clases de objetos en el directorio /etc/ldap/schema/.
Los atributos se definen por separado y se pueden utilizar en una o varias objectClass. Para poder utilizar un atributo en una entrada, ésta debe contener alguna objectClass que contenga el atributo, y a su vez, la objectClass debe estar incluida en algún esquema reconocido por el servidor LDAP.
Las objectClass se pueden organizar jerárquicamente, en cuyo caso heredan todas las propiedades de sus padres o SUPerior. Estas objectClass pueden ser STRUCTURAL, en cuyo caso se usan para crear entradas, AUXILIARY en cuyo caso se pueden agregar en cualquier entrada, o ABSTRACT. El ejemplo más común de objectClass ABSTRACT es top, que forma el mayor nivel de cualquier jerarquía objectClass. Cada una de estas definiciones pueden tener atributos obligatorios y otros opcionales.
Las entradas agrupan conjuntos de objectClass, donde cada una debe contener obligatoriamente (y sólo puede contener una) STRUCTURAL. Además, puede contener una ABSTRACT y un número arbitrario de AUXILIARY.
Autenticación
LDAP soporta varios métodos de autenticación para acceder al directorio, existiendo dos principales que deben ser soportados (según el estándar):
- Método de Autenticación Simple (Simple Authentication Method). Provee tres mecanismos de autenticación:
- Autenticación anónima de enlace simple. Conexión LDAP sin usuario ni contraseña.
- Autenticación sin autenticación de enlace simple. Se debe utilizar el nombre de usuario de un usuario válido, pero no es necesario proveer contraseña.
- Autenticación de Usuario/Contraseña de enlace simple. En este caso se utiliza usuario y password para la autenticación, pero el password se transmite de forma plana.
- Autenticación Simple y Capa de Seguridad (Simple Authentication and Security Layer - SASL). SASL es un framework para proveer autenticación y servicios seguros de datos a través de mecanismos reemplazables. El estándar de SASL sólo define uno de estos mecanismos (denominado EXTERNAL) pero las implementaciones más utilizadas soportan los siguientes:
- DIGEST-MD5: provee un mecanismo para utilizar la autenticación HTTP Digest dentro del framework SASL. Este mecanismo envía un MD5 del password en lugar del password en texto plano, sobre una conexión sin encripción.
- EXTERNAL: permite al cliente requerir que el servidor use credenciales provistas por un mecanismo externo al mecanismo de autenticación del cliente. La autenticación externa puede ser a través de la información de login del sistema operativo, IPSec, TLS o algún otro medio.
- GSSAPI: permite al cliente utilizar tokens GSSAPI como credenciales para la autenticación. El token GSSAPI pueden ser Kerberos TGT o token NTLM.
- GSSAPI-SPNEGO (Active Directory): es un mecanismo GSSAPI pero que contiene una negociación cliente-servidor para elegir el mecanismo de seguridad preferido según lo soportado por el cliente y el servidor.
- SASL usando GSSAPI con kerberos y sobre conexión encriptada.
- SASL usando GSSAPI con NTLMv2 y sobre conexión encriptada (sólo en Active Directory).
- SASL usando GSSAPI con kerberos.
- SASL usando GSSAPI con NTLMv2 (sólo en AD).
- SASL usando GSSAPI con NTLM y sobre conexión encriptada (sólo en Active Directory).
- Autenticación Simple, usuando usuario/contraseña sobre conexión encriptada.
- SASL usando GSSAPI con NTLM (sólo en AD).
Búsquedas en el directorio
La sintaxis para realizar búsquedas no es muy intuitiva y muy distinta a la forma en que consultamos bases de datos relacionales a través de SQL, pero con el tiempo (como todo) uno se acostumbra.
Los parámetros son los siguientes:
- baseObject: el DN de la entrada donde deseamos comenzar la búsqueda (ej: dc=demasiadovivo,dc=org)
- scope: qué elementos bajo el baseObject buscar.
- filer: criterio para seleccionar elementos dentro del scope. Los fitros se construyen utilizando operadores de igualdad y se pueden concatenar utilizando operadores booleanos en notación prefija. Pueden encontrar una buena explicación sobre construcción de filtros en Red Hat - LDAP Search Filters, Appendix A - LDAP: Text Search Filter y MS LDAP Query Basics.
- derefAliases: cuando y cómo seguir entradas que son alias.
- atributos: que atributos retornar en el resultado (ej: cn mail).
- sizeLimit, timeLimit: máxima cantidad de entradas a retornar y el tiempo máximo permitido para ejecutar la búsqueda.
- typesOnly: retornar sólo el tipo de los atributos, sin los valores.
Una excelente herramienta para realizar búsquedas en LDAP es ldapsearch, la cual viene en el paquete ldap-utils. Un ejemplo es el siguiente:
ldapsearch -b dc=itfreekzone,dc=blogspot,dc=com "(cn=demasiadovivo)" maildonde usamos como baseObject "dc=itfreekzone,dc=blogspot,dc=com", como filtro (cn=demasiadovivo), y el atributo que deseamos traer es "mail".
Lo que viene...
Próximamente publicaré un artículo sobre cómo instalar y configurar el servicio de directorio más utilizando en entornos *nix (principalmente GNU/Linux), denominado OpenLDAP.
Referencias
- OpenLDAP - 1. Introduction to OpenLDAP Directory Services
- LDAP Wiki
- Chapter 3. LDAP Schemas, objectClasses and Attributes
- 6. LDAP Lightweight Directory Access Protocol
- LDAP for Rocket Scientists
Etiquetas:
Active Directory,
administracion,
articulos,
LDAP,
OpenLDAP,
Protocolos
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)



