{"id":735,"date":"2009-05-23T17:59:22","date_gmt":"2009-05-23T15:59:22","guid":{"rendered":"http:\/\/www.marblestation.com\/blog\/?p=735"},"modified":"2012-04-26T16:16:53","modified_gmt":"2012-04-26T14:16:53","slug":"gestion-centralizada-de-usuarios-con-openldap","status":"publish","type":"post","link":"https:\/\/www.marblestation.com\/?p=735","title":{"rendered":"Gesti\u00f3n centralizada de usuarios con OpenLDAP"},"content":{"rendered":"<p>En uno de los \u00faltimos art\u00edculos habl\u00e1bamos de <a href=\"http:\/\/www.marblestation.com\/blog\/?p=674\">c\u00f3mo podemos hacer que nuestra Ubuntu sea m\u00e1s segura<\/a> siguiendo las buenas pr\u00e1cticas reconocidas por los est\u00e1ndares internacionales. Si bien en ese mismo texto explic\u00e1bamos como gestionar los usuarios locales, no valoramos c\u00f3mo realizar dicha gesti\u00f3n cuando disponemos de una red con m\u00e1s de un servidor.<\/p>\n<p>Con el objetivo de tener un mayor control sobre los usuarios definidos y una pol\u00edtica de contrase\u00f1as homog\u00e9nea, lo ideal en una red es disponer de un servicio centralizado de autenticaci\u00f3n. Imaginaros que disponemos de una red con 20 servidores y necesit\u00e1semos dar de alta un nuevo usuario, deber\u00edamos ejecutar las pertinentes modificaciones en los 20 diferentes entornos con el riesgo de errores e inconsistencias que \u00e9sto implica. Por otra parte, desde la perspectiva del usuario nos encontramos con 20 contrase\u00f1as que no tienen porque estar sincronizadas, diferentes pol\u00edticas, etc&#8230; al final es m\u00e1s que probable que el usuario utilice contrase\u00f1as d\u00e9biles o que las anote en un postit pegado al monitor.<\/p>\n<p>Por esos motivos, desde el punto de vista de la seguridad, es recomendable disponer de un servicio centralizado de autenticaci\u00f3n. Hist\u00f3ricamente en el mundo Unix se ha utilizado <a href=\"http:\/\/es.wikipedia.org\/wiki\/Network_Information_Service\">NIS (Network Information Service)<\/a>, pero actualmente ya se encuentra en desuso y se recomienda <a href=\"http:\/\/es.wikipedia.org\/wiki\/LDAP\">LDAP<\/a> por tratarse de un sistema m\u00e1s moderno y seguro.<\/p>\n<p>Entre las implementaciones de LDAP m\u00e1s conocidas tenemos el <a href=\"http:\/\/en.wikipedia.org\/wiki\/Active_Directory\">Directorio Activo<\/a> de Windows y <a href=\"http:\/\/en.wikipedia.org\/wiki\/OpenLDAP\">OpenLDAP<\/a> para sistemas Linux\/Unix (tambi\u00e9n puede integrarse con clientes Windows). Veamos como podemos montar un servicio centralizado de autenticaci\u00f3n con OpenLDAP que cumpla los siguientes requisitos:<\/p>\n<ul>\n<li>Autenticaci\u00f3n contra un \u00fanico punto centralizado de la red.<\/li>\n<li>Conexiones cifradas con TLS.<\/li>\n<li>Identificaci\u00f3n de estaciones mediante certificados digitales (\u00fanicamente podr\u00e1n conectarse al servidor los clientes que dispongan de un certificado creado por nosotros y viceversa)<\/li>\n<li>Pol\u00edtica de contrase\u00f1as homog\u00e9nea y robusta.<\/li>\n<li>Los usuarios definidos en OpenLDAP dispondr\u00e1n de campos donde se especificar\u00e1 a que m\u00e1quinas tienen acceso. La autorizaci\u00f3n a que servicios de cada m\u00e1quina se delegar\u00e1 a cada servidor para no perder flexibilidad.<\/li>\n<li>Cuando el usuario se autentica por primera vez en un sistema, se almacenan sus credenciales en una cache local, de forma que si el servidor de LDAP cae temporalmente, el usuario puede seguir conect\u00e1ndose.<\/li>\n<\/ul>\n<p><!--more--><\/p>\n<h3>Entidad certificadora SSL<\/h3>\n<p>C\u00f3mo comentabamos en la introducci\u00f3n, vamos a configurar LDAP para que se realicen conexiones cifradas. Para \u00e9sto tenemos la opci\u00f3n de generar un certificado SSL auto-firmado:<\/p>\n<pre>\r\nmkdir \/etc\/ldap\/ssl\r\ncd \/etc\/ldap\/ssl\r\nopenssl req -newkey rsa:1024 -x509 -nodes -out server.pem -keyout server.pem -days 3650\r\n<\/pre>\n<p>Con este certificado \u00fanicamente podemos cifrar las conexiones pero no identificar los clientes o el servidor. Por tanto, cualquiera ordenador de la red puede conectarse al servidor sin que \u00e9ste pueda verificar si se trata de un cliente autorizado, o a la inversa, los clientes no pueden verificar que se estan conectando al servidor autorizado y por ejemplo podr\u00edan enviar informaci\u00f3n confidencial (p.ej. contrase\u00f1as).<\/p>\n<p>Para evitar esa situaci\u00f3n, la configuraci\u00f3n m\u00e1s segura consiste en crear nuestra propia <a href=\"http:\/\/es.wikipedia.org\/wiki\/Autoridad_de_certificaci%C3%B3n\">Autoridad Certificadora<\/a> (CA) y emitir tantos certificados como necesitamos (1 por cliente + el servidor) firmados por la misma. As\u00ed podremos especificar que el servidor y el cliente solo acepten conexiones con certificados firmados por nuestra Autoridad Certificadora:<\/p>\n<pre>\r\nmkdir \/etc\/ssl\/marblestationCA\r\nmkdir \/etc\/ssl\/marblestationCA\/certs\r\nmkdir \/etc\/ssl\/marblestationCA\/private\r\n\r\necho \"01\" > \/etc\/ssl\/marblestationCA\/serial\r\ntouch \/etc\/ssl\/marblestationCA\/index.txt\r\n<\/pre>\n<p>Creamos &#8220;\/etc\/ssl\/marblestationCA\/caconfig.cnf&#8221;:<\/p>\n<pre>\r\n# My sample caconfig.cnf file.\r\n#\r\n# Default configuration to use when one is not provided on the command line.\r\n#\r\n[ ca ]\r\ndefault_ca      = local_ca\r\n#\r\n#\r\n# Default location of directories and files needed to generate certificates.\r\n#\r\n[ local_ca ]\r\ndir             = \/etc\/ssl\/marblestationCA\r\ncertificate     = $dir\/cacert.pem\r\ndatabase        = $dir\/index.txt\r\nnew_certs_dir   = $dir\/certs\r\nprivate_key     = $dir\/private\/cakey.pem\r\nserial          = $dir\/serial\r\n\r\n#       \r\n#\r\n# Default expiration and encryption policies for certificates.\r\n#\r\ndefault_crl_days        = 3650\r\ndefault_days            = 1825\r\ndefault_md              = md5\r\n#       \r\npolicy          = local_ca_policy\r\nx509_extensions = local_ca_extensions\r\n#       \r\n#\r\n# Default policy to use when generating server certificates.  The following\r\n# fields must be defined in the server certificate.\r\n#\r\n[ local_ca_policy ]\r\ncommonName              = supplied\r\nstateOrProvinceName     = supplied\r\ncountryName             = supplied\r\nemailAddress            = supplied\r\norganizationName        = supplied\r\n#       \r\n#\r\n# x509 extensions to use when generating server certificates.\r\n#\r\n[ local_ca_extensions ]\r\n#subjectAltName          = DNS:host.ejemplo.com,DNS:xenhost.ejemplo.com\r\nbasicConstraints        = CA:false\r\n#nsCertType              = server\r\n#       \r\n#\r\n# The default root certificate generation policy.\r\n#\r\n[ req ]\r\ndefault_bits    = 2048\r\ndefault_keyfile = \/etc\/ssl\/marblestationCA\/private\/cakey.pem\r\ndefault_md      = md5\r\n#       \r\nprompt                  = no\r\ndistinguished_name      = root_ca_distinguished_name\r\nx509_extensions         = root_ca_extensions\r\n#\r\n#\r\n# Root Certificate Authority distinguished name.  Change these fields to match\r\n# your local environment!\r\n#\r\n[ root_ca_distinguished_name ]\r\ncommonName              = Marble Station Root Certificate Authority\r\nstateOrProvinceName     = Catalunya\r\ncountryName             = ES\r\nemailAddress            = root@host.ejemplo.com\r\norganizationName        = Marble Station\r\norganizationalUnitName  = Host\r\n#       \r\n[ root_ca_extensions ]\r\nbasicConstraints        = CA:true\r\n<\/pre>\n<p>A continuaci\u00f3n creamos las claves que usar\u00e1 el CA, la contrase\u00f1a que establezcamos ahora ser\u00e1 solicitada cada vez que queramos firmar un nuevo certificado:<\/p>\n<pre>\r\nOPENSSL_CONF=\/etc\/ssl\/marblestationCA\/caconfig.cnf openssl req -x509 -newkey rsa:2048 -out cacert.pem -outform PEM -days 3650\r\n<\/pre>\n<p>Este comando generar\u00e1 el certificado &#8220;\/etc\/ssl\/marblestationCA\/cacert.pem&#8221; y la clave privada de CA &#8220;\/etc\/ssl\/marblestationCA\/private\/cakey.pem&#8221;.<\/p>\n<p>A continuaci\u00f3n crearemos una clave para el servidor que ofrece el servicio LDAP y otro para un cliente, para ello creamos el fichero &#8220;\/etc\/ssl\/marblestationCA\/host-server.cnf&#8221;:<\/p>\n<pre>\r\n#\r\n# desktop-server.cnf\r\n#\r\n\r\n[ req ]\r\nprompt                  = no\r\ndistinguished_name      = server_distinguished_name\r\n\r\n[ server_distinguished_name ]\r\ncommonName              = host.ejemplo.com\r\nstateOrProvinceName     = Catalunya\r\ncountryName             = ES\r\nemailAddress            = root@host.ejemplo.com\r\norganizationName        = Marble Station\r\norganizationalUnitName  = Host\r\n<\/pre>\n<p><b>NOTA:<\/b> Es muy importante tener en cuenta que el dominio que indiquemos en &#8220;commonName&#8221; debe coincidir con el dominio de la m\u00e1quina que va a utilizar el certificado, de lo contrario las conexiones ser\u00e1n rechazadas. Por ejemplo, algo tan sencillo como un servidor con 2 dominios &#8216;uno.com&#8217; y &#8216;dos.com&#8217; apuntando a la misma IP, si el certificado se genera indicando &#8216;uno.com&#8217;, los clientes que se conecten deben hacerlo mediante ese dominio y no &#8216;dos.com&#8217;. A pesar de apuntar a la misma IP, OpenLDAP verificar\u00e1 el dominio utilizado.<\/p>\n<p>Generamos la clave sin contrase\u00f1a (argumento &#8220;-nodes&#8221;) dado que de lo contrario el servicio no podr\u00eda arrancar de forma autom\u00e1tica:<\/p>\n<pre>\r\nOPENSSL_CONF=\/etc\/ssl\/marblestationCA\/host-server.cnf openssl req -newkey rsa:1024 -keyout host-server_key.pem -keyform PEM -out host-server_req.pem -outform PEM -nodes\r\n<\/pre>\n<p>Utilizamos la petici\u00f3n de firma para el CA que acabamos de crear (&#8220;host-server_req.pem&#8221;) para generar el certificado final firmado:<\/p>\n<pre>\r\nOPENSSL_CONF=\/etc\/ssl\/marblestationCA\/caconfig.cnf openssl ca -in host-server_req.pem -out host-server_crt.pem\r\n<\/pre>\n<p>A continuaci\u00f3n podemos repetir el proceso para generar m\u00e1s certificados firmados por el CA, creando un nuevo fichero de configuraci\u00f3n (p.ej. &#8220;\/etc\/ssl\/marblestationCA\/desktop-server.cnf&#8221;) y repitiendo los pasos anteriores:<\/p>\n<pre>\r\nOPENSSL_CONF=\/etc\/ssl\/marblestationCA\/desktop-server.cnf openssl req -newkey rsa:1024 -keyout desktop-server_key.pem -keyform PEM -out desktop-server_req.pem -outform PEM -nodes\r\nOPENSSL_CONF=\/etc\/ssl\/marblestationCA\/caconfig.cnf openssl ca -in desktop-server_req.pem -out desktop-server_crt.pem\r\n<\/pre>\n<h3>Servidor OpenLDAP<\/h3>\n<p>En el apartado anterior hemos preparado los certificados que vamos a utilizar, ahora ha llegado la hora de instalar el servidor OpenLDAP:<\/p>\n<pre>\r\napt-get install slapd ldap-utils db4.2-util\r\napt-get install libpam-ldap\r\n<\/pre>\n<p>Los certificados de la anterior secci\u00f3n, concretamente el certificado que ser\u00e1 utilizado por el servidor y el certificado del CA los copiaremos a su lugar correspondiente:<\/p>\n<pre>\r\nsudo -s\r\nmkdir \/etc\/ldap\/ssl\/\r\ncp \/etc\/ssl\/marblestationCA\/host-server_key.pem \/etc\/ldap\/ssl\/\r\ncp \/etc\/ssl\/marblestationCA\/host-server_crt.pem \/etc\/ldap\/ssl\/\r\ncp \/etc\/ssl\/marblestationCA\/cacert.pem \/etc\/ldap\/ssl\/\r\nchown openldap:openldap \/etc\/ldap\/ssl\/*\r\nchmod 640 \/etc\/ldap\/ssl\/*\r\n<\/pre>\n<p>Copiamos el esquema que nos permitir\u00e1 indicar a que hosts se pueden conectar los usuarios (atributos &#8216;host&#8217;, que pueden contener el hostname de las m\u00e1quinas o un &#8216;*&#8217; para permitir acceso a todas):<\/p>\n<pre>\r\ncp \/usr\/share\/doc\/libpam-ldap\/ldapns.schema \/etc\/ldap\/schema\/\r\n<\/pre>\n<p>A continuaci\u00f3n editamos la configuraci\u00f3n del servidor &#8216;\/etc\/ldap\/slapd.conf&#8217;:<\/p>\n<pre>\r\n# Schema and objectClass definitions\r\ninclude         \/etc\/ldap\/schema\/core.schema\r\ninclude         \/etc\/ldap\/schema\/cosine.schema\r\ninclude         \/etc\/ldap\/schema\/nis.schema\r\ninclude         \/etc\/ldap\/schema\/inetorgperson.schema\r\n\r\ninclude         \/etc\/ldap\/schema\/misc.schema\r\ninclude         \/etc\/ldap\/schema\/ppolicy.schema\r\ninclude         \/etc\/ldap\/schema\/ldapns.schema\r\n\r\n# Where the pid file is put. The init.d script\r\n# will not stop the server if you change this.\r\npidfile         \/var\/run\/slapd\/slapd.pid\r\n\r\n# List of arguments that were passed to the server\r\nargsfile        \/var\/run\/slapd\/slapd.args\r\n\r\n# Read slapd.conf(5) for possible values\r\nloglevel        none\r\n\r\n# Where the dynamically loaded modules are stored\r\nmodulepath  \/usr\/lib\/ldap\r\nmoduleload  back_hdb\r\nmoduleload ppolicy.la\r\n\r\n# The maximum number of entries that is returned for a search operation\r\nsizelimit 500\r\n\r\n# The tool-threads parameter sets the actual amount of cpu's that is used\r\n# for indexing.\r\ntool-threads 1\r\n\r\nbackend     hdb\r\ndatabase        hdb\r\n\r\n# The base of your directory in database #1\r\nsuffix          \"dc=marblestation,dc=com\"\r\n\r\noverlay ppolicy\r\nppolicy_default \"cn=Standard,ou=Policies,dc=marblestation,dc=com\"\r\nppolicy_use_lockout\r\n\r\n# rootdn directive for specifying a superuser on the database. This is needed\r\n# for syncrepl.\r\nrootdn          \"cn=admin,dc=marblestation,dc=com\"\r\n\r\n# Where the database file are physically stored for database #1\r\ndirectory       \"\/var\/lib\/ldap\"\r\n\r\nindex   uid eq\r\n\r\n# For the Debian package we use 2MB as default but be sure to update this\r\n# value if you have plenty of RAM\r\ndbconfig set_cachesize 0 2097152 0\r\n\r\n# Sven Hartge reported that he had to set this value incredibly high\r\n# to get slapd running at all. See http:\/\/bugs.debian.org\/303057 for more\r\n# information.\r\n\r\n# Number of objects that can be locked at the same time.\r\ndbconfig set_lk_max_objects 1500\r\n# Number of locks (both requested and granted)\r\ndbconfig set_lk_max_locks 1500\r\n# Number of lockers\r\ndbconfig set_lk_max_lockers 1500\r\n\r\n# Indexing options for database #1\r\nindex           objectClass eq\r\n\r\n# Save the time that the entry gets modified, for database #1\r\nlastmod         on\r\n\r\n# Checkpoint the BerkeleyDB database periodically in case of system\r\n# failure and to speed slapd shutdown.\r\ncheckpoint      512 30\r\n\r\n# The userPassword by default can be changed\r\n# by the entry owning it if they are authenticated.\r\n# Others should not be able to see it, except the\r\n# admin entry below\r\n# These access lines apply to database #1 only\r\n# #,shadowLastChange\r\naccess to attrs=userPassword\r\n        by dn=\"cn=admin,dc=marblestation,dc=com\" write\r\n        by anonymous auth\r\n        by self write\r\n        by * none\r\n\r\naccess to attrs=shadowLastChange\r\n  by self write\r\n  by * read\r\n\r\n# Ensure read access to the base for things like\r\n# supportedSASLMechanisms.  Without this you may\r\n# have problems with SASL not knowing what\r\n# mechanisms are available and the like.\r\n# Note that this is covered by the 'access to *'\r\n# ACL below too but if you change that as people\r\n# are wont to do you'll still need this if you\r\n# want SASL (and possible other things) to work \r\n# happily.\r\naccess to dn.base=\"\" by * read\r\n\r\n# The admin dn has full write access, everyone else\r\n# can read everything.\r\naccess to *\r\n        by dn=\"cn=admin,dc=marblestation,dc=com\" write\r\n        by * read\r\n\r\nTLSCertificateFile \/etc\/ldap\/ssl\/host-server_crt.pem\r\nTLSCertificateKeyFile \/etc\/ldap\/ssl\/host-server_key.pem\r\nTLSCACertificateFile \/etc\/ldap\/ssl\/cacert.pem\r\nTLSVerifyClient demand\r\n<\/pre>\n<p>En este fichero, respecto al original, se han realizado la siguientes modificaciones:<\/p>\n<ul>\n<li>Se han a\u00f1adido nuevos esquemas mediante el comando &#8216;include&#8217;.<\/li>\n<li>Se realiza la carga del m\u00f3dulo &#8216;ppolicy&#8217; y se establece la configuraci\u00f3n b\u00e1sica.<\/li>\n<li>Se especifica el sufijo que ser\u00e1 utilizado para la identificaci\u00f3n de los datos que contendr\u00e1 LDAP (&#8220;dc=marblestation,dc=com&#8221;) <\/li>\n<li>Se establece el usuario administrador mediante el comando &#8216;rootdn&#8217; (teniendo en cuenta el mismo sufijo que hemos especificado)<\/li>\n<li>Se configuran los certificados TLS para que estos sean requeridos y validados.<\/li>\n<\/ul>\n<p>Por otra parte, en el fichero &#8216;\/etc\/default\/slapd&#8217; activaremos el servicio SSL y Unix sockets:<\/p>\n<pre>\r\nSLAPD_SERVICES=\"ldaps:\/\/\/ ldapi:\/\/\/\"\r\n<\/pre>\n<p>Con esto ya podemos reiniciar nuestro servidor OpenLDAP:<\/p>\n<pre>\r\n\/etc\/init.d\/slapd restart\r\n<\/pre>\n<p>Ahora nos falta definir la estructura base de los datos internos.<\/p>\n<h3>Estructura del directorio<\/h3>\n<p>La informaci\u00f3n en LDAP se almacena mediante objetos que son construidos a partir de clases definidas en los esquemas (\u00e9stos se cargan autom\u00e1ticamente en base a las &#8216;includes&#8217; del fichero de configuraci\u00f3n de slapd). Veamos una definici\u00f3n de ejemplo:<\/p>\n<pre>\r\ndn: cn=admin,dc=marblestation,dc=com\r\nobjectClass: organizationalRole\r\nobjectClass: simpleSecurityObject\r\ncn: admin\r\ndescription: LDAP administrator\r\nuserPassword: {SSHA}HHWw45HYVamEIUFHp1emGejTkbY1bntB\r\n<\/pre>\n<p>Elementos de la definici\u00f3n anterior:<\/p>\n<ul>\n<li>En primer lugar tenemos el nombre un\u00edvoco (Distinguished Name) del objeto: &#8220;cn=admin,dc=marblestation,dc=com&#8221;. Siempre acompa\u00f1ado del sufijo que hemos especificado en la configuraci\u00f3n (en este caso &#8220;dc=marblestation,dc=com&#8221;).<\/li>\n<li>El objeto tendr\u00e1 los atributos de las clases &#8216;organizationalRole&#8217; y &#8216;simpleSecurityObject&#8217;. Estas clases se encuentran definidos en los esquemas &#8216;\/etc\/ldap\/schema\/&#8217; que son cargados por LDAP al iniciarse. Un objeto puede estar compuesto por tantas clases auxiliares (p.ej. simpleSecurityObject) y abstractas (p.ej. top) como se requiera pero solo puede haber una de tipo estructural (organizationalRole en este caso).<\/li>\n<li>Finalmente se listan los atributos, en este caso &#8216;cn&#8217;, &#8216;description&#8217; y &#8216;userPassword&#8217;.<\/li>\n<\/ul>\n<p>Todos los objetos en LDAP siguen siempre esa estructura, la cual dista bastante de las t\u00edpicas bases de datos relacionales (SQL). Otra diferencia importante respecto a esas BBDD es que LDAP est\u00e1 optimizado para realizar consultas de lectura muy r\u00e1pidas, por eso LDAP se utiliza en entornos que utilizan datos que no van a ser modificados frecuentemente (a diferencia de una BBDD relacional como MySQL).<\/p>\n<p>Pasemos a construir la estructura b\u00e1sica de nuestro servidor LDAP, nos situamos en un directorio temporal de trabajo y creamos el fichero &#8216;structure.ldif&#8217;:<\/p>\n<pre>\r\n##### Raiz\r\ndn: dc=marblestation,dc=com\r\nobjectClass: dcObject\r\nobjectClass: organizationalUnit\r\ndc: marblestation\r\nou: marblestation Dot Com\r\n\r\n##### Administrador de LDAP\r\ndn: cn=admin,dc=marblestation,dc=com\r\nobjectClass: simpleSecurityObject\r\nobjectClass: organizationalRole\r\ncn: admin\r\ndescription: LDAP administrator\r\nuserPassword: {SSHA}HHWw45HYVamEIUFHp1emGejTkbY1bntB\r\n## Password genered with slappasswd\r\n\r\n##### Usuarios\r\ndn: ou=People,dc=marblestation,dc=com\r\nobjectClass: organizationalUnit\r\nou: people\r\n\r\n##### Grupos\r\ndn: ou=Group,dc=marblestation,dc=com\r\nobjectClass: organizationalUnit\r\nou: group\r\n\r\n##### Politicas de contrase\u00f1as\r\ndn: ou=Policies,dc=marblestation,dc=com\r\nobjectClass: organizationalUnit\r\nou: policies\r\n<\/pre>\n<p>En ese fichero hemos definido la raiz donde colgar\u00e1n todos los datos, el administrador del sistema LDAP y unidades organizativas donde a\u00f1adiremos los usuarios, los grupos y las pol\u00edticas de contrase\u00f1a. <\/p>\n<p>Cabe destacar que todas las contrase\u00f1as que necesitemos para definir la estructura las generaremos mediante el comando &#8216;slappasswd&#8217; (por ejemplo, la del usuario administrador anterior):<\/p>\n<pre>\r\n$ slappasswd\r\nNew password:\r\nRe-enter password:\r\n{SSHA}d2BamRTgBuhC6SxC0vFGWol31ki8iq5m\r\n<\/pre>\n<p>Continuemos con el contenido del servidor LDAP. A\u00f1adiremos una pol\u00edtica de contrase\u00f1as que definiremos en el fichero &#8216;policy.ldif&#8217;:<\/p>\n<pre>\r\n##### Pol\u00edtica est\u00e1ndard\r\ndn: cn=Standard,ou=Policies,dc=marblestation,dc=com\r\nobjectClass: top\r\nobjectClass: device\r\nobjectClass: pwdPolicy\r\ncn: Standard\r\n# Field were password is stored:\r\npwdAttribute: userPassword\r\n#### Expiration rules\r\n# Number of seconds that must elapse between modifications allowed to  the  password:\r\n# 1 day\r\npwdMinAge: 86400\r\n# 60 days\r\npwdMaxAge: 5184000\r\n# 7 days\r\npwdExpireWarning: 604800\r\n# if its value is zero (0), users  with  expired  passwords will not be allowed to authenticate to the directory.\r\npwdGraceAuthnLimit: 0\r\n# User must change its password after an admin has set it\r\npwdMustChange: TRUE\r\n# Users can change their password\r\npwdAllowUserChange: TRUE\r\n# It is needed the old password to set a new one\r\n# NOTA: Si lo activamos no podremos cambiar la contrase\u00f1a mediante pam_ldap\r\npwdSafeModify: FALSE\r\n##### Password quality\r\n# Maximum number of used passwords that will be stored in the pwdHistory attribute:\r\npwdInHistory: 12\r\n# If its value is one (1), the server will check  the  syntax,  and  if  the\r\n# server  is  unable  to  check  the syntax, whether due to a client-side\r\n# hashed password or some other reason, it will be accepted. If its value\r\n# is  two  (2),  the  server  will check the syntax, and if the server is\r\n# unable to check the syntax it will return an error refusing  the  password.\r\npwdCheckQuality: 2\r\n# Minimum  number  of  characters\r\npwdMinLength: 8\r\n##### Automatic locks\r\n# Lock user accounts after 5 failed authentications\r\npwdMaxFailure: 5\r\npwdLockout: TRUE\r\n# 10 minutes\r\npwdLockoutDuration: 600\r\n# if its value is zero (0), the failure counter will only be reset by a successful authentication\r\npwdFailureCountInterval: 0\r\n<\/pre>\n<p>\u00c9sta pol\u00edtica ser\u00e1 la que aplicar\u00e1 a todos los usuarios (excepto al administrador LDAP) y el propio fichero es auto-explicativo.<\/p>\n<p>Vamos a crear un usuario de prueba en el fichero &#8216;users.ldif&#8217;:<\/p>\n<pre>\r\ndn: uid=marble,ou=people,dc=marblestation,dc=com\r\nobjectClass: account\r\nobjectClass: posixAccount\r\nobjectClass: top\r\nobjectClass: shadowAccount\r\nobjectClass: inetLocalMailRecipient\r\nobjectClass: hostObject\r\nobjectClass: authorizedServiceObject\r\n#objectClass: kerberosSecurityObject\r\n#######################################\r\n### Posix Account\r\nuid: marble\r\ncn: Sergi Blanco Cuaresma\r\ngecos: Sergi Blanco Cuaresma\r\nuidNumber: 1000\r\ngidNumber: 1000\r\nloginShell: \/bin\/bash\r\nhomeDirectory: \/home\/marble\r\n#######################################\r\n### Password\r\nuserPassword: {SSHA}PFIJb4fTH4klVKd5nE4J0WDUs3Rtmxtd\r\npwdReset: TRUE\r\n#pwdPolicySubEntry: cn=Standard,ou=Policies,dc=marblestation,dc=com\r\n#pwdPolicySubEntry: cn=No Policy, ou=Policies, dc=example, dc=com\r\n## Discarted\r\n#shadowExpire: -1\r\n#shadowFlag: 0\r\n#shadowMin: 1\r\nshadowWarning: 7\r\nshadowMax: 60\r\nshadowLastChange: 0\r\n#shadowMax: 99999\r\n#shadowLastChange: 14156\r\n#######################################\r\n### Kerberos\r\n#krbname: marble@EJEMPLO.COM\r\n#######################################\r\n### Authorization (e.g. host: desktop, authorizedService: sshd)\r\nhost: *\r\nauthorizedService: *\r\n### Mail\r\nmailRoutingAddress: marble@host.ejemplo.com\r\nmailHost: host.ejemplo.com\r\n<\/pre>\n<p>\u00c9sta sera la definici\u00f3n habitual de los usuarios de los sistemas, la mayor\u00eda de atributos corresponden con la informaci\u00f3n que habitualmente se almacena en sistemas Unix. Adicionalmente, tenemos otros atributos como &#8216;host&#8217;, que define a que m\u00e1quinas podr\u00e1 conectarse (el &#8216;*&#8217; significa &#8220;a todas&#8221;, si quisi\u00e9ramos especificar m\u00e1quinas tendr\u00edamos que repetir el atributo tantas veces como m\u00e1quinas queramos especificar).<\/p>\n<p>Cabe destacar que utilizaremos los atributos shadow para replicar la pol\u00edtica global que hemos establecido con &#8216;ppolicy&#8217;. Si bien podr\u00edamos ignorarlos, no nos cuesta nada indicar la misma pol\u00edtica de contrase\u00f1a para asegurarnos que se cumple bajo cualquier circunstancia (p.ej. si tenemos conexiones SSH con autenticaci\u00f3n por claves RSA\/DSA, PAM \u00fanicamente comprueba los campos shadow y por tanto &#8216;ppolicy&#8217; no tiene efecto hasta que el usuario no realiza una conexi\u00f3n utilizando su clave normal).<\/p>\n<p>Finalmente nos falta definir los grupos del sistema, a\u00f1adamos un par de ejemplo en un fichero &#8216;groups.ldif&#8217;:<\/p>\n<pre>\r\ndn: cn=marble,ou=group,dc=marblestation,dc=com\r\nobjectClass: posixGroup\r\ncn: marble\r\ngidNumber: 1000\r\n\r\ndn: cn=users,ou=group,dc=marblestation,dc=com\r\nobjectClass: posixGroup\r\ncn: users\r\nmemberUid: marble\r\ngidNumber: 100\r\n<\/pre>\n<p>Ahora que ya tenemos todos los ficheros con la estructura y los datos iniciales, ha llegado el momento de cargarlos en el servidor. Para ello borraremos todos los datos actuales de LDAP (no hemos introducido nada todavia, por tanto no deber\u00eda haber nada de valor) y cargamos la informaci\u00f3n:<\/p>\n<pre>\r\nsudo \/etc\/init.d\/slapd stop\r\nsudo rm -rf \/var\/lib\/ldap\/*\r\nsudo slapadd -l structure.ldif\r\nsudo slapadd -l policy.ldif\r\nsudo slapadd -l users.ldif\r\nsudo slapadd -l groups.ldif\r\nsudo chown -R openldap:openldap \/var\/lib\/ldap\r\nsudo \/etc\/init.d\/slapd start\r\n<\/pre>\n<p>Si todo ha ido bien, ya tenemos nuestro servidor LDAP en marcha con la estructura base y un usuario de prueba.<\/p>\n<h3>Consultas locales a OpenLDAP<\/h3>\n<p>Para poder hacer consultas desde el propio servidor donde hemos instalado LDAP editamos &#8216;\/etc\/ldap\/ldap.conf&#8217;:<\/p>\n<pre>\r\nBASE    dc=marblestation,dc=com\r\nURI ldapi:\/\/\/\r\n<\/pre>\n<p>De esta forma los comandos &#8216;ldap&#8217; se conectaran al servidor utilizando <a href=\"http:\/\/en.wikipedia.org\/wiki\/Unix_domain_sockets\">Unix sockets<\/a> y no necesitaremos configurar TLS dado que los datos no viajan por ninguna red.<\/p>\n<p>Podemos probar a realizar una consulta conectando como el administrador de LDAP (nos solicitar\u00e1 la contrase\u00f1a que le hayamos asignado en la definici\u00f3n del mismo) y preguntando sobre los objetos con el atributo &#8216;uid=marble&#8217;:<\/p>\n<pre>\r\nldapsearch -x -D \"cn=admin,dc=marblestation,dc=com\" -W uid=marble\r\n<\/pre>\n<p>Si queremos evitar tener que escribir siempre el nombre del administrador, podemos crear el archivo &#8216;~\/.ldaprc&#8217;:<\/p>\n<pre>\r\nBASE    dc=marblestation,dc=com\r\nURI ldapi:\/\/\/\r\nBINDDN  cn=admin,dc=marblestation,dc=com\r\n<\/pre>\n<p>As\u00ed simplemente bastar\u00e1 con ejecutar:<\/p>\n<pre>\r\nldapsearch -x -W uid=marble\r\n<\/pre>\n<h3>Administraci\u00f3n LDAP y gesti\u00f3n de usuarios<\/h3>\n<h4>Comandos LDAP<\/h4>\n<p>OpenLDAP proporciona diversos comandos para la administraci\u00f3n del servicio:<\/p>\n<ul>\nldapdelete: Borra entradas.<br \/>\nldapmodrdn: Modifica RDN (Relative Distinguised Names), por ejemplo permite mover &#8220;uid=marble,<b>ou=people<\/b>,dc=marblestation,dc=com&#8221; a &#8220;uid=marble,<b>ou=gente<\/b>,dc=marblestation,dc=com&#8221;<br \/>\nldapsearch: Realiza consultas.<br \/>\nldapcompare: Comparaciones.<br \/>\nldapmodify: Permite a\u00f1adir entradas o realizar modificaciones.<br \/>\nldappasswd: Establece la contrase\u00f1a del usuario.<br \/>\nldapwhoami: Indica el usuario con el que nos conectamos a LDAP.\n<\/ul>\n<p>Su uso no es sencillo y para aprender a utilizarlas lo mejor es consultar sus respectivos manuales. No obstante, disponemos de otras interf\u00edcies que nos facilitaran la gesti\u00f3n de LDAP.<\/p>\n<h4>phpLDAPadmin<\/h4>\n<p>Para la administraci\u00f3n general del LDAP, si tenemos ya <a href=\"http:\/\/www.marblestation.com\/blog\/?p=674#6\">configurado Apache2<\/a>, una de las opciones m\u00e1s c\u00f3modas es la instalaci\u00f3n de <a href=\"http:\/\/phpldapadmin.sourceforge.net\">phpldapadmin<\/a>:<\/p>\n<pre>\r\napt-get install phpldapadmin\r\n<\/pre>\n<p>Editamos &#8216;\/etc\/phpldapadmin\/config.php&#8217; y establecemos los siguientes par\u00e1metros (acceso local por Unix sockets, etc.):<\/p>\n<pre>\r\n...\r\n$ldapservers->SetValue($i,'server','host','ldapi:\/\/');\r\n...\r\n$ldapservers->SetValue($i,'server','base',array('dc=marblestation,dc=com'));\r\n...\r\n$ldapservers->SetValue($i,'login','dn','cn=admin,dc=marblestation,dc=com');\r\n...\r\n<\/pre>\n<p>Podremos acceder a la aplicaci\u00f3n mediante &#8216;http:\/\/localhost\/phpldapadmin\/&#8217; y desde all\u00ed la aplicaci\u00f3n nos permitir\u00e1 realizar consultar, modificaciones, duplicar objetos, etc.<\/p>\n<h4>CPU &#8211; Change Passowrd Utility<\/h4>\n<p>Si bien con phpLDAPadmin podremos realizar casi cualquier operaci\u00f3n sobre LDAP v\u00eda web, CPU nos proporciona comandos de consola an\u00e1logos a los tradicionales &#8216;useradd&#8217;, &#8216;usermod&#8217;, &#8216;userdel&#8217;, &#8216;groupadd&#8217;, etc. \u00c9sto puede facilitar al administrador la tarea de gesti\u00f3n de usuarios:<\/p>\n<pre>\r\napt-get install cpu\r\n<\/pre>\n<p>Editamos &#8216;\/etc\/cpu\/cpu.conf&#8217; para establecer las opciones de conexi\u00f3n (v\u00eda local por Unix Socket), usuario administrador LDAP (no indicamos la contrase\u00f1a, haremos que nos la pregunte cada vez que ejecutemos cpu) y otros par\u00e1metros:<\/p>\n<pre>\r\n# See cpu.conf(5) for documentation\r\n\r\n[GLOBAL]\r\nDEFAULT_METHOD  = ldap\r\nCRACKLIB_DICTIONARY = \/var\/cache\/cracklib\/cracklib_dict\r\n\r\n[LDAP]\r\nLDAP_URI                = ldapi:\/\/\/\r\nBIND_DN                 = \"cn=admin,dc=marblestation,dc=com\"\r\nBIND_PASS               = \"\"\r\nUSER_BASE               = \"ou=People,dc=marblestation,dc=com\"\r\nGROUP_BASE              = \"ou=Group,dc=marblestation,dc=com\"\r\nUSER_OBJECT_CLASS       = account,posixAccount,shadowAccount,top,inetLocalMailRecipient,hostObject,authorizedServiceObject\r\n#kerberosSecurityObject\r\nGROUP_OBJECT_CLASS  = posixGroup,top\r\nUSER_FILTER = (objectClass=posixAccount)\r\nGROUP_FILTER    = (objectClass=posixGroup)\r\nUSER_CN_STRING  = uid\r\nGROUP_CN_STRING = cn\r\nSKEL_DIR    = \/etc\/skel\r\nDEFAULT_SHELL   = \/bin\/bash\r\nHOME_DIRECTORY  = \/home\r\nMAX_UIDNUMBER = 10000\r\nMIN_UIDNUMBER = 1000\r\nMAX_GIDNUMBER = 10000\r\nMIN_GIDNUMBER = 1000\r\nID_MAX_PASSES = 1000\r\n# Whether each user should have its own group created or not\r\nUSERGROUPS = yes\r\n# If you change usergroup set this to the default group a user should have\r\n#USERS_GID = 100\r\nRANDOM = \"false\"\r\nPASSWORD_FILE = \"\/etc\/passfile\"\r\nSHADOW_FILE = \"\/etc\/shadowfile\"\r\nHASH = \"clear\"\r\nSHADOWLASTCHANGE    = 11192\r\nSHADOWMAX       = 99999\r\nSHADOWWARING        = 7\r\nSHADOWEXPIRE        = -1\r\nSHADOWFLAG      = 134538308\r\nSHADOWMIN       = -1\r\nSHADOWINACTIVE      = -1\r\n<\/pre>\n<p>Adicionalmente, crearemos el fichero &#8216;\/etc\/cpu\/attributes.ldif&#8217;:<\/p>\n<pre>\r\npwdReset: TRUE\r\nhost: *\r\nauthorizedService: *\r\n<\/pre>\n<p>De esta forma, cuando creemos usuarios se a\u00f1adir\u00e1n los atributos anteriores por defecto (el usuario esta obligado a resetear la contrase\u00f1a y tiene acceso a todos los sistemas). Hagamos una prueba a\u00f1adiendo un nuevo usuario (la primera contrase\u00f1a que nos solicita corresponde a la del administrador LDAP):<\/p>\n<pre>\r\ncpu -w -a \/etc\/cpu\/attributes.ldif useradd -p test01\r\n<\/pre>\n<p>El anterior comando generar\u00e1 el usuario &#8216;test01&#8217; y el grupo &#8216;test01&#8217;.<\/p>\n<p>Si queremos listar los usuarios definidos:<\/p>\n<pre>\r\ncpu -w cat\r\n<\/pre>\n<p>Bloqueo y desbloqueo de usuarios:<\/p>\n<pre>\r\ncpu -w usermod -L test01\r\ncpu -w usermod -U test01\r\n<\/pre>\n<p>Borrado de usuarios:<\/p>\n<pre>\r\ncpu -w userdel prueba22\r\n<\/pre>\n<p>Para consultar el listado completo de comandos que podemos ejecutar con &#8216;cpu&#8217; podemos consultar el manual:<\/p>\n<pre>\r\nman cpu-ldap\r\n<\/pre>\n<h3>Clientes OpenLDAP<\/h3>\n<p>A continuaci\u00f3n vamos a configurar una m\u00e1quina que se conectar\u00e1 contra el servidor OpenLDAP para autenticar a sus usuarios:<\/p>\n<pre>\r\napt-get install libpam-ldap libnss-ldap nss-updatedb libnss-db ldap-utils libpam-ccreds\r\n<\/pre>\n<p>Para la conexi\u00f3n, necesitaremos disponer de un certificado firmado por la CA que hemos generado tal y como se especificaba al inicio del art\u00edculo. Una vez generados los certificados (clave privada, clave p\u00fablica firmada y certificado CA), los copiaremos mediante sftp y los moveremos al lugar correspondiente:<\/p>\n<pre>\r\nsudo -s\r\nmkdir \/etc\/ldap\/ssl\/\r\ncp \/etc\/ssl\/marblestationCA\/desktop-server_key.pem \/etc\/ldap\/ssl\/\r\ncp \/etc\/ssl\/marblestationCA\/desktop-server_crt.pem \/etc\/ldap\/ssl\/\r\ncp \/etc\/ssl\/marblestationCA\/cacert.pem \/etc\/ldap\/ssl\/\r\nchmod 644 \/etc\/ldap\/ssl\/*\r\nchown root:root \/etc\/ldap\/ssl\/*\r\n<\/pre>\n<p>A continuaci\u00f3n vamos a configurar LDAP como cliente, editamos &#8216;\/etc\/ldap\/ldap.conf&#8217;:<\/p>\n<pre>\r\nBASE    dc=marblestation,dc=com\r\nURI     ldaps:\/\/host.ejemplo.com\r\n\r\nTLS_CACERT \/etc\/ldap\/ssl\/cacert.pem\r\nTLS_REQCERT demmand\r\n#TLS_REQCERT never # Useful to check if \"Can't contact LDAP server\" because of certificate problems\r\n<\/pre>\n<p>Utilizando el usuario que vayamos a utilizar para conectarnos al servidor, creamos &#8216;~\/.ldaprc&#8217;:<\/p>\n<pre> \r\nBASE    dc=marblestation,dc=com\r\nURI     ldaps:\/\/host.ejemplo.com\r\nBINDDN  cn=admin,dc=marblestation,dc=com\r\n\r\nTLS_CACERT \/etc\/ldap\/ssl\/cacert.pem\r\nTLS_REQCERT demmand\r\n#TLS_REQCERT never # Useful to check if \"Can't contact LDAP server\" because of certificate problems\r\n\r\n#### User only (need to copy \/etc\/ldap\/ldap.conf to ~\/.ldaprc)\r\n# Client certificate and key\r\n# Use these, if your server requires client authentication.\r\nTLS_CERT \/etc\/ldap\/ssl\/desktop-server_crt.pem\r\nTLS_KEY \/etc\/ldap\/ssl\/desktop-server_key.pem\r\n<\/pre>\n<p>En esos dos ficheros hemos especificado:<\/p>\n<ul>\n<li>El nombre base &#8220;dc=marblestation,dc=com&#8221;.<\/li>\n<li>El servidor al que nos vamos a conectar y el protocolo que vamos a utilizar, en este caso nos conectaremos mediante SSL al puerto 636 LDAP del servidor &#8216;host.ejemplo.com&#8217;. Es muy importante que este dominio coincida con el &#8216;commonName&#8217; especificado en el servidor al cual nos vamos a conectar, de lo contrario la conexi\u00f3n no se establecer\u00e1.<\/li>\n<li>El usuario con el que vamos a realizar la conexi\u00f3n (corresponde al administrador).<\/li>\n<li>Certificado privado, p\u00fablico firmado y CA, as\u00ed como la solicitud de validaci\u00f3n del certificado del servidor.<\/li>\n<\/ul>\n<p>A continuaci\u00f3n podemos probar la conexi\u00f3n realizando una consulta al servidor:<\/p>\n<pre>\r\nldapsearch -x -W uid=marble\r\n<\/pre>\n<p>Ahora que ya hemos podido comprobar que podemos conectarnos sin problemas desde el cliente, vamos a configurar el sistema para que autentique los usuarios contra LDAP.<\/p>\n<p>Lo primero ser\u00e1 editar el fichero &#8216;\/etc\/ldap.conf&#8217; para establecer los par\u00e1metros de conexi\u00f3n utilizados por <a href=\"http:\/\/es.wikipedia.org\/wiki\/Pluggable_Authentication_Modules\">PAM<\/a> (sistema habitual de autenticaci\u00f3n):<\/p>\n<pre>\r\n# Your LDAP server. Must be resolvable without using LDAP.\r\nuri ldaps:\/\/host.ejemplo.com\r\n\r\n# The distinguished name of the search base.\r\nbase dc=marblestation,dc=com\r\n\r\nldap_version 3\r\n\r\n# The distinguished name to bind to the server with\r\n# if the effective user ID is root. Password is\r\n# stored in \/etc\/ldap.secret (mode 600)\r\n# NOTA: No activar o dejar\u00e1 de ser efectiva la politica de contrase\u00f1as (ppolicy)\r\n#rootbinddn cn=admin,dc=marblestation,dc=com\r\n\r\n# Search timelimit\r\ntimelimit 5\r\n\r\n# Bind\/connect timelimit\r\nbind_timelimit 5\r\n\r\n# Reconnect policy: hard (default) will retry connecting to\r\n# the software with exponential backoff, soft will fail\r\n# immediately.\r\nbind_policy soft\r\n\r\n# Filter to AND with uid=%s\r\n#pam_filter objectclass=posixAccount\r\n#pam_filter gidNumber=1000\r\n\r\n# check for login rights on the host\r\npam_check_host_attr yes\r\n#pam_filter (&(objectClass=posixAccount)(authorizedService=site-admin))\r\n#pam_filter |(host=desktop)(host=\\*)\r\n\r\n#pam_check_service_attr yes\r\n\r\npam_lookup_policy yes\r\n\r\n# Specify a minium or maximum UID number allowed\r\n#pam_min_uid 1000\r\n#pam_max_uid 0\r\n\r\n# Do not hash the password at all; presume\r\n# the directory server will do it, if\r\n# necessary. This is the default.\r\n#pam_password md5\r\npam_password clear\r\n\r\n# OpenLDAP SSL mechanism\r\n# start_tls mechanism uses the normal LDAP port, LDAPS typically 636\r\nssl start_tls\r\nssl on\r\n\r\n# OpenLDAP SSL options\r\n# Require and verify server certificate (yes\/no)\r\ntls_checkpeer yes\r\n# tls_checkpeer no # Useful to check if \"Can't contact LDAP server\" because of certificate problems\r\n\r\n# CA certificates for server certificate verification\r\n#tls_cacertdir \/etc\/ssl\/certs\r\ntls_cacertfile \/etc\/ldap\/ssl\/cacert.pem\r\n\r\n# Client certificate and key\r\ntls_cert \/etc\/ldap\/ssl\/desktop-server_crt.pem\r\ntls_key \/etc\/ldap\/ssl\/desktop-server_key.pem\r\n\r\n\r\nuse_sasl off\r\nrootuse_sasl off\r\nsasl_secprops maxssf=0\r\nidle_timelimit 3600\r\nnss_reconnect_tries 1\r\nnss_reconnect_sleeptime 1\r\nnss_reconnect_maxsleeptime 8\r\nnss_reconnect_maxconntries 2\r\nnss_paged_results yes\r\nnss_base_passwd ou=people,dc=marblestation,dc=com?one\r\nnss_base_shadow ou=people,dc=marblestation,dc=com?one\r\nnss_base_group ou=group,dc=marblestation,dc=com?one\r\n\r\nnss_initgroups_ignoreusers avahi,avahi-autoipd,backup,bin,chipcard,daemon,dhcp,ftp,games,gdm,gnats,haldaemon,hplip,irc,klog,landscape,libuuid,list,lp,mail,man,messagebus,news,nx,polkituser,proxy,pulse,root,snmp,sshd,sync,sys,syslog,uucp,www-data\r\n<\/pre>\n<p>En este fichero hemos especificado:<\/p>\n<ul>\n<li>Host al que nos conectaremos. Como siempre, es importante que coincida con el &#8216;commonName&#8217; del certificado del servidor, de lo contrario la conexi\u00f3n no se establecer\u00e1.<\/li>\n<li>Opciones de conexi\u00f3n varias (el puerto 636 corresponde a ldaps:\/\/).<\/li>\n<li>Configuraciones PAM:\n<ul>\n<li>Validaci\u00f3n del atributo &#8216;host&#8217;. Si el usuario dispone de un atributo &#8216;host&#8217; con valor &#8216;*&#8217; o con el nombre de la m\u00e1quina (debe coincidir con el resultado del comando &#8216;hostname&#8217;), entonces podr\u00e1 logearse en el sistema. De lo contrario, se deniega el acceso.<\/li>\n<li>Validaci\u00f3n de la pol\u00edtica de contrase\u00f1as.<\/li>\n<li>Env\u00edo de contrase\u00f1as en claro. Este requisito es necesario para que la pol\u00edtica de contrase\u00f1as pueda ser validada en el servidor y por otra parte, tampoco supone un riesgo de seguridad dado que la conexi\u00f3n ser\u00e1 cifrada.<\/li>\n<\/ul>\n<\/li>\n<li>Configuraci\u00f3n de los certificados a utilizar.<\/li>\n<li>Rutas donde encontrar la informaci\u00f3n de usuarios, grupos, etc.<\/li>\n<\/ul>\n<p>A continuaci\u00f3n vamos a preparar el sistema para que si perdemos conectividad, podamos seguir asociando uid y gid con los nombres asignados. Para esto se copiaran todos los usuarios y grupos (solo uid\/gid y nombres) en local mediante el comando:<\/p>\n<pre>\r\nsudo nss_updatedb ldap\r\n<\/pre>\n<p>Es necesario que esta actualizaci\u00f3n se haga de forma peri\u00f3dica mediante cron (al menos 1 vez al d\u00eda) por si hay cambios en el servidor:<\/p>\n<pre>\r\necho '#!\/bin\/sh'               | sudo tee    \/etc\/cron.daily\/upd-local-nss-db\r\necho `which nss_updatedb` ldap | sudo tee -a \/etc\/cron.daily\/upd-local-nss-db\r\nsudo chmod +x \/etc\/cron.daily\/upd-local-nss-db\r\n<\/pre>\n<p>En este punto estamos preparados para indicarle al sistema de donde debe obtener la informaci\u00f3n sobre usuarios, contrase\u00f1as y grupos, para ello editamos &#8216;\/etc\/nsswitch.conf&#8217; y cambiamos:<\/p>\n<pre>\r\n#passwd:         compat\r\n#group:          compat\r\n#shadow:         compat\r\n<\/pre>\n<p>Por:<\/p>\n<pre>\r\npasswd:         files ldap [NOTFOUND=return] db\r\ngroup:          files ldap [NOTFOUND=return] db\r\nshadow:     files ldap\r\n<\/pre>\n<p>En estas l\u00edneas estamos indicando que el sistema debe buscar la informaci\u00f3n de usuarios y grupos primero en los archivos locales (\/etc\/passwd y \/etc\/group) y despu\u00e9s en LDAP, pero en caso de que este \u00faltimo falle entonces debe consultar la copia local que hemos realizado con &#8216;nss_updatedb&#8217;. En el caso de las contrase\u00f1as, \u00fanicamente consultar\u00e1 el fichero local (&#8216;\/etc\/shadow&#8217;) y el servidor (el cacheo de credenciales lo realizaremos por otra v\u00eda).<\/p>\n<p>Con esta configuraci\u00f3n tendremos m\u00e1xima flexibilidad dado que podremos optar por tener usuario\/grupos locales y usuarios\/grupos centralizados de forma simultanea. O bien, podemos migrar todas las cuentas a LDAP y dejar en blanco los archivos locales.<\/p>\n<p>Para validar la configuraci\u00f3n, podemos comprobar el listado de usuarios\/grupos actuales de nuestro sistema (combinar\u00e1 los definidos localmente con los usuarios creados en LDAP):<\/p>\n<pre>\r\nsudo getent passwd\r\nsudo getent group\r\n<\/pre>\n<p>Finalmente nos falta configurar los archivos de autenticaci\u00f3n PAM. <\/p>\n<p><b>NOTA:<\/b> Si estamos accediendo remotamente al servidor que estamos modificando, es importante tener en cuenta que estos cambios pueden bloquearnos futuros accesos y por tanto debemos probar cada cambio que hagamos. <\/p>\n<p>Comenzaremos editando &#8216;\/etc\/pam.d\/common-auth&#8217; para que quede con el siguiente contenido:<\/p>\n<pre>\r\nauth    [success=done default=ignore]   pam_unix.so nullok_secure try_first_pass\r\n# If LDAP is unavailable, go to next line.  If authentication via LDAP is successful, skip 1 line.\r\n# If LDAP is available, but authentication is NOT successful, skip 2 lines.\r\nauth    [authinfo_unavail=ignore success=1 default=2] pam_ldap.so use_first_pass\r\nauth    [default=done]  pam_ccreds.so action=validate use_first_pass\r\nauth    [default=done]  pam_ccreds.so action=store\r\nauth    [default=bad]   pam_ccreds.so action=update\r\n<\/pre>\n<p>En este fichero hemos indicado que primero debe intentar autenticar los usuarios utilizando la informaci\u00f3n local, de lo contrario trata de autenticar contra el servidor LDAP (utilizando la configuraci\u00f3n &#8216;\/etc\/ldap.conf&#8217; que ya hemos preparado). Si este \u00faltimo falla, comprobar\u00e1 si las credenciales se encuentran cacheadas en local e intentar\u00e1 autenticarlo (antepen\u00faltima l\u00ednea).<\/p>\n<p>Por otra parte, cada vez que se realice una autenticaci\u00f3n exitosa contra LDAP, se ejecutar\u00e1 la pen\u00faltima l\u00ednea y se guardar\u00e1n las credenciales en local (concretamente en \/var\/cache\/.security.db). En caso que la cuenta haya sido bloqueada\/eliminada de LDAP, se ejecutar\u00e1 la \u00faltima l\u00ednea con la cual se borraran las credenciales cacheadas del usuario.<\/p>\n<p>Editemos ahora &#8216;\/etc\/pam.d\/common-account&#8217; para que quede con el siguiente contenido:<\/p>\n<pre>\r\naccount     [user_unknown=ignore authinfo_unavail=ignore default=done] pam_ldap.so\r\naccount     [user_unknown=ignore authinfo_unavail=ignore default=done] pam_unix.so\r\naccount     required       pam_permit.so\r\n<\/pre>\n<p>Editamos &#8216;\/etc\/pam.d\/common-session&#8217; y lo dejamos as\u00ed:<\/p>\n<pre>\r\nsession    required     pam_limits.so\r\n#session    required     pam_mkhomedir.so skel=\/etc\/skel\/\r\nsession    required     pam_unix.so\r\nsession    optional     pam_ldap.so\r\n\r\n<\/pre>\n<p>Editamos &#8216;\/etc\/pam.d\/common-password&#8217; para que contenga:<\/p>\n<pre>\r\npassword   required   pam_ldap.so ignore_unknown_user\r\npassword   optional   pam_unix.so shadow md5 try_first_pass\r\n<\/pre>\n<p>A continuaci\u00f3n podemos probar a autenticarnos en el sistema (login normal, ssh o &#8216;su &#8211; usuario&#8217;) utilizando usuarios locales y usuarios definidos en LDAP (p.ej. el que hemos creado de prueba).<\/p>\n<p>Cuando conectemos con el usuario de LDAP, las credenciales han debido ser cacheadas y podemos validarlo mediante:<\/p>\n<pre>\r\nsudo cc_dump\r\n  Credential Type  User             Service  Cached Credentials\r\n  ----------------------------------------------------------------------------------\r\n  Salted SHA1      fred             any     4a985b233701cf106ed450a0168fa8e0aa86ef5d\r\n<\/pre>\n<p>En caso de que queramos borrar manualmente alguna credencial cacheada, podemos ejecutar:<\/p>\n<pre>\r\nsudo cc_test -update any usuario -\r\n<\/pre>\n<p>Con esto ya tenemos montado el sistema de autenticaci\u00f3n centralizado cliente-servidor \ud83d\ude42<\/p>\n","protected":false},"excerpt":{"rendered":"<p>En uno de los \u00faltimos art\u00edculos habl\u00e1bamos de c\u00f3mo podemos hacer que nuestra Ubuntu sea m\u00e1s segura siguiendo las buenas pr\u00e1cticas reconocidas por los est\u00e1ndares internacionales. Si bien en ese mismo texto explic\u00e1bamos como gestionar los usuarios locales, no valoramos c\u00f3mo realizar dicha gesti\u00f3n cuando disponemos de una red con m\u00e1s de un servidor. Con &hellip; <a href=\"https:\/\/www.marblestation.com\/?p=735\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Gesti\u00f3n centralizada de usuarios con OpenLDAP<\/span> <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1,6],"tags":[],"class_list":["post-735","post","type-post","status-publish","format-standard","hentry","category-espanyol","category-tecnologia"],"_links":{"self":[{"href":"https:\/\/www.marblestation.com\/index.php?rest_route=\/wp\/v2\/posts\/735","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.marblestation.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.marblestation.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.marblestation.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.marblestation.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=735"}],"version-history":[{"count":18,"href":"https:\/\/www.marblestation.com\/index.php?rest_route=\/wp\/v2\/posts\/735\/revisions"}],"predecessor-version":[{"id":1218,"href":"https:\/\/www.marblestation.com\/index.php?rest_route=\/wp\/v2\/posts\/735\/revisions\/1218"}],"wp:attachment":[{"href":"https:\/\/www.marblestation.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=735"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.marblestation.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=735"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.marblestation.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=735"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}