LDAP definisce un semplice protocollo basato su TCP per la ricerca e l'aggiornamento di informazioni contenute all'interno di un directory service (database gerarchico).
Un elemento in una directory LDAP è referenziato in modo non ambiguo tramite un nome, detto distinguished name (DN), per esempio “cn=John Doe,ou=people,dc=wikipedia,dc=org”. Ogni elemento inoltre comprende una collezione di attributi.
Ognuno degli attributi dell'elemento è definito come membro di una classe di oggetti, raggruppati in uno schema. Ogni elemento nel database è associato a una o più classi di oggetti, che definiscono se un attributo sia opzionale o meno e che tipo di informazioni questo contenga. I nomi degli attributi solitamente sono scelti per essere facilmente memorizzabili, per esempio “cn” per common name, o “mail” per un indirizzo e-mail.
È possibile utilizzare LDAP per numerosi scopi; come database per l'autenticazione degli utenti Unix, come rubrica di contatti email, ecc.
Utilizzando LDAP per l'autenticazione è interessante la possibile integrazione con il sottosistema Kerberos versione 5. Le informazioni relative all'autenticazione (estremamente sensibili dal punto di vista della sicurezza) vengono tolte dal database LDAP e memorizzate nel più sicuro database Kerberos, inoltre si viene ad usufruire del sistema di ticketing di Kerberos, utilie ad esempio per abbinare il montaggio sicuro delle home directory via NFSv4.
Questo è un elenco degli attributi più comuni utilizzati in una directory LDAP:
DN | Distinguished_Name | As the word 'distinguished' suggests, this is THE LDAP attribute that uniquely defines an object. Each DN must have a different name and location from all other objects. The other side of the coin is that DN provides a way of selecting any object in the LDAP directory. Once you have select the object, then you can change its attributes. |
---|---|---|
DC | Domain_Content | Example: DC=rigacci, DC=org . Note that DC=rigacci.org would be wrong. |
CN | Common Name | From RFC2256: This is the X.500 commonName attribute, which contains a name of an object. If the object corresponds to a person, it is typically the person's full name. |
OU | Organizational_Unit | |
O | OrganizationName | |
C | CountryName | |
ST | StateOrProvinceName | |
SN | SurName | From RFC2256: This is the X.500 surname attribute, which contains the family name of a person. |
Ognuno è libero di creare lo schema LDAP (struttura del database) che preferisce, è possibile anche disattivare l'opzione schemacheck in modo da poter inserire nel database oggetti non conformi allo schema (altamente sconsigliato).
Esistono comunque degli schemi predefiniti molto utilizzati, conviene adottare questi schemi in modo che i vari applicativi trovino il database nella forma in cui se lo aspettano. Ad esempio per memorizzare un archivio di contatti e-mail utilizzabile direttamente da Firefox si può utilizzare lo schema InetOrgPerson
(RFC2798), un database per l'autenticazione può essere invece basato sullo schema posixAccount
(nisSchema in RFC2307).
Il pacchetto slapd di Debian arriva con alcuni schemi predefiniti memorizzati in /etc/ldap/schema
; fare riferimento ad essi anche per sapere quali sono gli attributi obbligatori (MUST
) e quali facoltativi (MAY
) di un oggetto, ad esempio:
objectclass ( 1.3.6.1.1.1.2.0 NAME 'posixAccount' SUP top AUXILIARY DESC 'Abstraction of an account with POSIX attributes' MUST ( cn $ uid $ uidNumber $ gidNumber $ homeDirectory ) MAY ( userPassword $ loginShell $ gecos $ description ) )
Fare attenzione che gli schemi possono essere di tipo STRUCTURAL, AUXILIARY o ABSTRACT (si guardi le definizioni dentro i file /etc/ldap/schema
):
STRUCTURAL | Indicates the attributes that the entry may have and where each entry may occur in the DIT. |
---|---|
AUXILIARY | Indicates the attributes that the entry may have. |
ABSTRACT | Indicates a “partial” specification in the object class hierarchy; only structural and auxiliary subclasses may appear as entries in the directory. |
Quindi quando si carica un oggetto dentro LDAP bisogna che sia riconducibile ad una objectClass
di tipo STRUCTURAL. Ad esempio un oggetto non può essere dichiarato come semplice objectClass: posixAccount
(che è una classe AUXILIARY
); lo si deve completare dichiarando almeno una classe STRUCTURAL
.
Tra le classi STRUCTURAL predefinite si potrebbe optare per la objectClass: top
che è la più generica di tutte, infatti non impone la presenza di alcun attributo salvo un altro objectClass. In alternativa si potrebbe scegliere una objectClass: organizationalUnit
adatta a descrivere persone ma anche gruppi, oppure la più specifica objectClass: person
.
In questo esempio si configura un server ed un client LDAP per effettuare l'autenticazione (login, ecc.). La distribuzione di riferimento è una Debian Lenny. In pratica dovremmo configurare il sistema di autenticazione PAM (il più usato in ambiente GNU/Linux) in modo tale che sia client di un server LDAP.
Dopo aver configurato il server potrebbe essere utile configurare un altro server che replichi lo stesso database, utilizzando Syncrepl.
I pacchetti da installare sul server sono:
L'installazione predefinita di Debian Lenny crea un database la cui radice ha un DN (Distinguished Name) dc=rigacci,dc=org che segue lo standard RFC2247 e un amministratore cn=admin con password:
dn: dc=rigacci,dc=org dn: cn=admin,dc=rigacci,dc=org
Tutto è memorizzato nel database bdb (Berkeley DB) contenuto in /var/lib/ldap/
, quindi nel file di configurazione /etc/ldap/slapd.conf
non viene scritta alcuna password. Queste le parti salienti del file di configurazione:
# Database specific directives apply to this databasse until another # 'database' directive occurs database bdb # The base of your directory in database #1 suffix "dc=rigacci,dc=org" # rootdn directive for specifying a superuser on the database. # rootdn "cn=admin,dc=rigacci,dc=org" # rootpw {SSHA}lzz5HF6eP7fRaB3G6L85zhk6zWWP8+Fk # Where the database file are physically stored for database #1 directory "/var/lib/ldap" # Who can change the userPassword. access to attrs=userPassword,shadowLastChange by dn="cn=admin,dc=rigacci,dc=org" write by anonymous auth by self write by * none # The admin dn has full write access, everyone else # can read everything. access to * by dn="cn=admin,dc=rigacci,dc=org" write by * read
Attenzione: l'intero database è accessibile in lettura anche agli utenti anonimi. Eventualmente aggiungere una clausola by anonymous auth
anche alla seconda ACL.
Le voci rootdn e rootpw (sopra commentate) possono essere utilizzate per memorizzare le credenziali di amministratore nel file di configurazione invece che nel database.
Volendo utilizzare LDAP per l'autenticazione è opportuno attivare la cifratura TLS. Bisogna creare un certificato, per semplificare le cose si crea un certificato auto-firmato e quindi faremo a meno di una Certification Authority. Questo è il file di configurazione utilizzato per creare il certificato, nei commenti le istruzioni per utilizzarlo:
#---------------------------------------------------------------- # Create an RSA key and a self-signed Certificate with the # following command: # # openssl req -config /etc/ldap/ssl/ldap.rigacci.org.cnf \ # -new -x509 -days 1461 -nodes \ # -keyout /etc/ldap/ssl/ldap.rigacci.org.pem \ # -out /etc/ldap/ssl/ldap.rigacci.org.pem # # The resulting file (unencrypted otherwise Slapd can't start # automatically) will contains the RSA private key, so be sure # to set its mode to 0400. #---------------------------------------------------------------- [ req ] prompt = no default_bits = 2048 distinguished_name = ldap.rigacci.org_distinguished_name [ ldap.rigacci.org_distinguished_name ] countryName = IT stateOrProvinceName = Italy localityName = Firenze organizationName = Rigacci.Org organizationalUnitName = Information and Communications Technology commonName = ldap.rigacci.org emailAddress = webmaster@rigacci.org
Il certificato /etc/ldap/ssl/ldap.rigacci.org.pem
deve essere protetto con permessi 0400 e deve appartenere all'utente LDAP (openldap:openldap in Debian). Per utilizzarlo si aggiunge a /etc/ldap/slapd.conf
le righe:
# Allow the server to picks-up the default cypher. # TLSCipherSuite HIGH:MEDIUM:+SSLv2 TLSCertificateFile /etc/ldap/ssl/ldap.rigacci.org.pem TLSCertificateKeyFile /etc/ldap/ssl/ldap.rigacci.org.pem
Conviene limitare il protocollo ldap all'indirizzo loopback e attivare pubblicamente solo ldaps. Questo in Debian Lenny si ottiene modificando /etc/default/slapd
:
SLAPD_SERVICES="ldap://127.0.0.1:389/ ldaps:///"
Se il server ldap è protetto da firewall bisogna aprire la porta 389 TCP e UDP, il protocollo ldpas (LDAP su SSL) invece è sulla porta 636 TCP e UDP.
In generale si dovrà indicare al client di accettare il certificato del server che non è firmato da alcuna Certificate Authority. Dovrebbe essere sufficiente aggiungere a /etc/ldap/ldap.conf
la riga:
TLS_REQCERT allow
Attenzione ai nomi! Se il certificato contiene un commonName diverso dal nome del server che useranno i client, bisogna rilassare ancora di più i vincoli del client, impostando:
TLS_REQCERT never
Invece di usare ldaps (LDAP su SSL) Si potrebbe usare StartTLS, cioè una connessione cifrata sulla porta standard 389. Sarebbe però necessario configurare ulteriori vincoli (vedi Security Strength Factors) per evitare che i client usino connessioni non cifrate.
Per ottenere un dump del database in formato LDIF, da utente root si può usare il comando slapcat (che agisce direttamente sul database, senza passare per il demone slapd
):
slapcat -b "dc=rigacci,dc=org" dn: dc=rigacci,dc=org objectClass: top objectClass: dcObject objectClass: organization ... dn: cn=admin,dc=rigacci,dc=org objectClass: simpleSecurityObject objectClass: organizationalRole cn: admin description: LDAP administrator userPassword:: e2MyeXB0hXhlTk95V1pJMu9J8FU= structuralObjectClass: organizationalRole ...
Da utente non privilegiato si può utilizzare il comando ldapsearch. Nel primo esempio si utilizzano le credenziali di admin fornendo la relativa password (opzioni -D e -W). Nel secondo esempio si utilizza il protocollo ldaps, ma senza utilizzare credenziali privilegiate, pertanto si otterranno solo le informazioni pubbliche.
ldapsearch -x -D "cn=admin,dc=rigacci,dc=org" -W -b "dc=rigacci,dc=org" ldapsearch -x -H ldaps://127.0.0.1/ -b "dc=rigacci,dc=org" "(objectclass=*)"
Per effettuare il restore di un dump ottenuto con slapcat
si può utilizzare slapadd
. Anch'esso agisce direttamente sul database, quindi è necessario fermare il demone slapd
prima di eseguirlo. Questo è il modo giusto per fare il restore di tutti gli oggetti del database senza alterare gli attributi di sistema come createTimestamp
, ecc.
ATTENZIONE: I nomi utente verranno memorizzati nel ramo LDAP People, i gruppi invece nel ramo Group. Conviene rispettare questo schema nonostante l'inconsistenza tra plurale (People) e singolare (Group) in quanto libnss-ldap usa questo schema per default (forse segue l'RFC2307?).
L'installazione Debian ha provveduto a creare solo la radice del database, ora vogliamo creare alcuni rami che conterranno alcuni oggetti. Ad esempio creiamo il ramo People, definito dal seguente schema ldif (lo salviamo in un file people.rigacci.org.ldif
):
dn: ou=People,dc=rigacci,dc=org ou: People objectClass: top objectClass: organizationalUnit objectClass: domainRelatedObject associatedDomain: rigacci.org
Lo schema viene aggiunto al database con il comando ldapadd:
ldapadd -x -D "cn=admin,dc=rigacci,dc=org" -W -f people.rigacci.org.ldif Enter LDAP Password: adding new entry "ou=People,dc=rigacci,dc=org"
Il database adesso è pronto per ricevere gli utenti. Volendo memorizzare gli account di sistema conviene utilizzare gli schemi posixAccount e shadowAccount. La migrazione dai tradizionali /etc/passwd
e /etc/shadow
può essere facilitata dagli script Migration Tools. Ecco un estratto di un file LDIF con un account:
dn: uid=niccolo,ou=People,dc=rigacci,dc=org uid: niccolo cn: niccolo objectClass: account objectClass: posixAccount objectClass: top objectClass: shadowAccount userPassword: {crypt}$1$hr0T2eCW$L.Rk7J9R1oOzJ3qTgv1YB0 shadowLastChange: 13815 shadowMax: 99999 shadowWarning: 7 loginShell: /bin/bash uidNumber: 1000 gidNumber: 1000 homeDirectory: /home/niccolo gecos: Niccolo Rigacci,,,
Ecco il comando per aggiungere un record nel database a partire dal file.ldif:
ldapadd -v -H ldap://127.0.0.1/ -x -D "cn=admin,dc=rigacci,dc=org" -W -f file.ldif
Per la modifica invece è richiesto un file più complesso, in cui prima si seleziona il record e quindi si indicano le operazioni da effettuare:
dn: uid=niccolo,ou=People,dc=rigacci,dc=org changetype: modify add: objectClass objectClass: sambaSamAccount - replace: userPassword userPassword: {crypt}$1$hr0T2eCW$L.Rk7J9E3oTvJ6qTgv1YB0
e il comando necessario è ldapmodify:
ldapmodify -v -x -D "cn=admin,dc=rigacci,dc=org" -W -f file.ldif
Attenzione ai caratteri NON ASCII: bisogna codificarli in UTF-8, ad esempio usando iconv(1)
. Attenzione però anche ai vincoli imposti dallo schema; ad esempio lo schema posixAccount
non accetta caratteri non ASCII nel campo gecos e restituisce un errore del tipo:
Invalid Syntax additional info: gecos: value #0 invalid per syntax
Per eliminare qualcosa dal database si prepara un file.ldif con i DN che si vogliono eliminare, ad esempio:
uid=niccolo,ou=People,dc=rigacci,dc=org uid=angela,ou=People,dc=rigacci,dc=org
e poi si utilizza il comando ldapdelete
:
ldapdelete -v -x -D "cn=admin,dc=rigacci,dc=org" -W -f file.ldif
Per verificare che l'interrogazione dal client verso un server remoto funzioni si usa ldapsearch
(notare l'uso del protocollo LDAP su SSL):
ldapsearch -v -x -H ldaps://ldap.rigacci.org -b "uid=niccolo,ou=People,dc=rigacci,dc=org"
Operazione del tutto analoga per aggiungere il ramo Group, ecco lo schema (lo conserviamo nel file group_rigacci_org.ldif
):
dn: ou=Group,dc=rigacci,dc=org ou: Group objectClass: top objectClass: organizationalUnit
Dopo aver aggiunto il ramo, lo si può popolare con entry del tipo:
dn: cn=dialout,ou=Group,dc=rigacci,dc=org objectClass: posixGroup objectClass: top cn: dialout userPassword: {crypt}x gidNumber: 20 memberUid: niccolo memberUid: angela dn: cn=niccolo,ou=Group,dc=rigacci,dc=org objectClass: posixGroup objectClass: top cn: niccolo userPassword: {crypt}x gidNumber: 1000
Per una maggiore efficienza delle query sul database LDAP è necessario mantenere degli indici sulle chiavi di ricerca più utilizzate. Se vengono fatte richieste su campi non indicizzati (e con loglevel stats
) il file /var/log/syslog
riporta:
slapd[30935]: <= bdb_equality_candidates: (uid) not indexed
Si aggiungono direttive in /etc/ldap/slapd.conf
:
index uid,uidNumber,gidNumber,memberUid eq
Purtroppo per reindicizzare il database bisogna fermare il demone, eseguire il comando slapindex(8)
e riavviare il demone:
/etc/init.d/slapd stop slapindex -b "dc=rigacci,dc=org" chown -R openldap:openldap /var/lib/ldap/ /etc/init.d/slapd start
Per la scadenza delle password si utilizza il campo shadowMax dello schema shadowAccount, con la stessa semantica del file shadow(5)
. Se invece di un sistema basato completamente su LDAP si implementa un sistema misto LDAP + Kerberos, la scadenza delle password dovrebbe essere gestita da Kerberos (come?) e quindi il campo shadowMax si imposta convenzionalmente a 99999 per indicare nessuna scadenza (in realtà sono circa 273 anni).
Scompattati i sorgenti, modificato migrate_common.ph
impostando quanto segue:
# Default DNS domain $DEFAULT_MAIL_DOMAIN = "rigacci.org"; # Default base $DEFAULT_BASE = "dc=rigacci,dc=org";
per esportare gli utenti e i gruppi in un file LDIF è sufficiente eseguire:
./migrate_passwd.pl /etc/passwd > etc_passwd.ldif ./migrate_group.pl /etc/group > etc_group.ldif
Conviene ovviamente togliere gli account di sistema dal file LDIF risultante oppure (meglio!) far lavorare il migration tool su una versione emendata di /etc/passwd
. NOTA: in Debian gli account normali sono quelli con UID compreso tra 1000 e 29999.
Sul client che vuole fare autenticazione LDAP si devono configurare due componenti: PAM su LDAP (Pluggable Authentication Modules) e NSS su LDAP (Network Service Switch).
NOTA: Se la gestione delle password avviene tramite Kerberos single sign-on system, non si deve installare la componente PAM su LDAP. In tal caso si può comunque utilizzare NSS su LDAP.
Se si desidera amministrare il database LDAP dal client (non indispensabile) si installa il pacchetto ldap-utils.
I pacchetti da installare sono:
Il sistema PAM (Pluggable Authentication Modules) fornisce ai programmi che devono fare autenticazione una serie di servizi tramite una interfaccia di programmazione standard, in questo modo è possibile cambiare il sistema di autenticazione senza dover modificare i programmi.
I servizi offerti dai moduli PAM si dividono in quattro categorie:
account | Verifica se l'utente ha il permesso di compiere una determinata azione. |
---|---|
auth | Authentication: certifica l'identità dell'utente, in genere verificando una password. |
password | Funzioni per aggiornare il sistema di authentication (es. modifica password). |
session | Provvede funzioni per iniziare e chiudere una sessione, ad esempio il mount della home directory. |
In generale i servizi di authentication sono i più importanti. Per un modulo PAM non è obbligatorio fornire tutti i servizi; ad esempio alcuni moduli PAM potrebbero non fornire la possibilità di cambiare la password.
La procedura Debian (Squeeze) di configurazione per libpam-ldap richiede diversi parametri, si può ri-eseguire con dpkg-reconfigure libpam-ldap
:
LDAP server URI: ldaps://127.0.0.1/ Distinguished name of the search base: dc=rigacci,dc=org LDAP version to use: 3 Allow LDAP admin account to behave like local root? Yes Does the LDAP database require login? No LDAP administrative account: cn=admin,dc=rigacci,dc=org LDAP administrative password: **** Local encryption algorithm to use for passwords: crypt PAM profiles to enable: Unix authentication, LDAP Authentication
Le impostazioni vengono salvate in /etc/pam_ldap.conf
e in /etc/pam_ldap.secret
.
NOTA: L'help allegato alla domanda Allow LDAP admin account to behave like local root? non è chiaro: rispondendo No il file /etc/pam_ldap.secret
contenente la password di amministratore LDAP non viene creato, quindi PAM non sarà in grado di modificare il database con i privilegi di amministratore.
NOTA: Non dovrebbe essere strettamente necessario che l'utente root del client sia amministratore del database LDAP, quindi si dovrebbe poter evitare che la password relativa venga memorizzata sul client.
ATTENZIONE: per evitare che le password possano essere facilmente intercettate è obbligatorio utilizzare il protocollo ldaps. Poiché il server utilizza un certificato auto-firmato è necessario disabilitarne la verifica. Editare il file /etc/pam_ldap.conf
e aggiungere le opzioni:
ssl on tls_checkpeer no
Per testare la componente PAM si può creare il file /etc/pam.d/test_ldap
con le seguenti direttive:
auth required pam_ldap.so account required pam_ldap.so password required pam_ldap.so
ed utilizzare l'utility pamtester in questo modo:
./pamtester -v test_ldap niccolo authenticate pamtester: invoking pam_start(test_ldap, niccolo, ...) pamtester: performing operation - authenticate Password: pamtester: successfully authenticated
Contrariamente a quello che viene riportato in alcuni documenti pare che non sia obbligatorio risolvere l'indirizzo IP del server LDAP nel nome definito nel certificato del server stesso.
A questo punto, se le cose sembrano funzionare, si può configurare PAM in modo che utilizzi sempre LDAP, ritornando al tradizionale schema Unix in caso di fallimento. In Debian dovrebbe bastare modificare i file common-account, common-auth e common-password contenuti in /etc/pam.d/
/etc/pam.d/common-account
account sufficient pam_ldap.so account required pam_unix.so try_first_pass
/etc/pam.d/common-auth
auth sufficient pam_ldap.so auth required pam_unix.so nullok_secure try_first_pass
/etc/pam.d/common-password
password sufficient pam_ldap.so password required pam_unix.so nullok obscure md5 try_first_pass
La sintassi dei dei file sopra non mi convince, sonsultare anche i documenti Setting up OpenLDAP e Setting up MIT Kerberos 5.
La configurazione del demone ssh in Debian potrebbe non utilizzare PAM
Per aumentare la sicurezza viene abilitata l'opzione UsePrivilegeSeparation
rendendo non privilegiato il processo che riceve la connessione TCP, questo nelle vecchie versioni di OpenSSH creava problemi all'autenticazione PAM. Inoltre per mitigare un bug di sicurezza scoperto in passato si consigliava di impostare PAMAuthenticationViaKbdInt no
.
Con OpenSSH 4.4p1 il problema è risolto e si può impostare l'opzione UsePAM yes
. Consultare la man page di sshd_config(5)
e controllare in /etc/ssh/sshd_config
le seguenti opzioni:
UsePrivilegeSeparation yes PasswordAuthentication yes ChallengeResponseAuthentication no UsePAM yes
Tradizionalmente sui sistemi Unix alcune informazioni sugli utenti e sugli host sono contenute in file di configurazione (/etc/passwd
, /etc/shadow
, /etc/hosts
, …). Il Name Service Switch (NSS) è un servizio che consente di sostituire questi file con uno o più database. Nel nostro caso vogliamo che le informazioni sugli utenti e sui gruppi siano su un database LDAP.
I pacchetti Debian da installare sono:
libnss-ldap
: crea una copia locale dei database, usabile in modalità off-line
La procedura Debian di configurazione per libnss-ldap richiede diversi parametri (eseguire per vedere tutte le domande):
LDAP server Uniform Resource Identifier: ldap://127.0.0.1/ Distinguished name of the search base: dc=rigacci,dc=org LDAP version to use: 3 Does the LDAP database require login? No Special LDAP privileges for root? No Make the configuration file readable/writeable by its owner only? Yes
Le impostazioni vengono salvate in /etc/libnss-ldap.conf
. Attivare i privilegi speciali LDAP per root vorrebbe dire che l'utente root del client ha i privilegi di amministratore su LDAP, questo però richiederebbe di memorizzare in chiaro la password di amministratore LDAP nel file /etc/libnss-ldap.secret
.
NOTA: Forse è opportuno rispondere No all'ultima domanda, visto che anche gli utenti non privilegiati devono poter accedere (in modo anonimo) al database LDAP. Vedi avanti.
ATTENZIONE: Se in /etc/libnss-ldap.conf
viene impostata l'opzione binddn, allora il collegamento al server LDAP avviene con quel nome invece che in modo anonimo. Nel nostro caso si preferisce che l'utente non privilegiato faccia collegamenti anonimi, pertanto l'opzione viene omessa. Se l'utente è root allora l'accesso LDAP avviene con le credenziali specificate in rootbinddn e la password contenuta in /etc/libnss-ldap.secret
.
Anche in questo caso è necessario disabilitare la verifica del certificato dal momento che non è firmato da alcuna Certificate Authority. Forziamo anche l'uso di SSL che altrimenti fallisce nonostante la scelta del protocollo ldaps. Quindi in /etc/libnss-ldap.conf
si imposta:
ssl on tls_checkpeer no
L'opzione tls_checkpeer potrebbe essere impostata a livello di libldap nel file /etc/openldap/ldap.conf
, come dice il commento in libnss-ldap.conf
.
ATTENZIONE: Debian imposta i permessi di /etc/libnss-ldap.conf
a 0600 perché in questo file potrebbero trovarsi le credenziali per accedere al database LDAP. Non è il caso nostro, anzi le interrogazioni per i database passwd
e group
vengono fatte in modo anonimo e devono essere eseguibili dall'utente non privilegiato (ad es. con getent(1)
). Per ottenere questo risultato bisogna fare:
chmod 0644 /etc/libnss-ldap.conf
Nel caso serva memorizzare la password per accedere al database LDAP si utilizza il file /etc/libnss-ldap.secret
(contiene solo la passwrod, senza il newline!) e si protegge il file con chmod 0600
.
Rimane infine da configurare il file /etc/nsswitch.conf
, in questo esempio la ricerca su LDAP viene fatta solo se fallisce la ricerca sui tradizionali file:
passwd: files ldap group: files ldap shadow: files ldap
In Debian al posto della ricerca files si trova quella compat (che sta per NIS compatibility), questa modalità consente di utilizzare una speciale sintassi nel file /etc/passwd
per includere gruppi di utenti.
ATTENZIONE: la modifica del file /etc/nsswitch.conf
non ha effetto immediato su tutti i programmi in esecuzione, ogni programma infatti legge la configurazione del NSS solo al suo avvio. Se si cambia il file di configurazione ad esempio si deve riavviare il demone nscd, utile anche il comando per invalidare la cache di nscd:
/etc/init.d/nscd reload nscd --invalidate passwd
Per testare il funzionamento del NSS si può utilizzare il comando getent(1)
che cerca nei database (passwd, group, …) una specifica chiave:
getent passwd niccolo niccolo:x:1002:1002:Niccolo Rigacci,,,:/home/niccolo:/bin/bash
L'installazione di nscd è praticamente obbligatoria se il server LDAP è su una macchina diversa da localhost. Infatti anche la più semplice operazione (ad esempio un ls -l
) provoca numerose interrogazioni del NSS, ripetere le interrogazione su un database remoto risulterebbe in un rallentamento non accettabile.
Volendo una copia locale dei database passwd e group da usare quando disconnessi si può usare il pacchetto libnss-db e un cron-job che replica le informazioni dalla sorgente LDAP (pacchetto nss-updatedb).
Kerberos si propone come sistema di Single Sign-On (SSO), cioè con una sola autenticazione è possibile accedere a molti servizi. Il server di autenticazione Kerberos mantiene solo le informazioni su nome/password (chiamate principals) e poco altro (scadenza, ecc.), non contiene informazioni su UID, GID, ecc.
Al momento del login il server Kerberos autentica l'utente e rialscia un Ticket-granting Ticket (TGT), cioè un ticket che verrà utilizzato in seguito per ottenere i ticket specifici per accedere ai servizi, senza dover ripetere la procedura di autenticazione. Con il comando klist(1)
è possibile sapere quali ticket abbiamo ricevuto, con kinit(1) è possibile ottenere un nuovo TGT.
Grazie ad un robusto progetto di sicurezza, Kerberos non trasmette mail le password in rete.
L'accoppiata PAM + Kerberos può sostituire utilmente PAM + LDAP, migliorando la procedura di autenticazione. Ad esempio sarà possibile effettuare login su un host e montare una directory NFSv4 in modo sicuro, effettuando una sola autenticazione.
Configurando PAM opportunamente, non solo l'autenticazione del login verrà fatta sul server Kerberos, ma verrà anche rilasciato automaticamente il Ticket-granting Ticket, senza bisogno di eseguire kinit
e digitare nuovamente la password. Questo è il motivo per cui è importante configurare il modulo session di PAM.
Il resto delle informazioni utente (UID, GID, home directory, shell, …) non sono memorizzati nel database Kerberos, pertanto staranno nei tradizionali file Unix oppure su un server LDAP e gestiti dal Name Service Switch (NSS). Tradizionalmente la shadow password viene impostata a *K*, per significare che è nel database Kerberos.
Qui abbiamo una guida all'installazione di Kerberos per NFSv4 (utile per la configurazione del server KDC), esiste inoltre questa guida all'installazione di Kerberos per l'autenticazione: MIT Kerberos installation on Debian.
Sull'host che deve usufruire di questa autenticazione si installa il modulo PAM che si appoggia al server Kerberos e le utility di supporto Kerberos. In pratica servono i pacchetti Debian:
L'installazione di krb5-config genera il file di configurazione /etc/krb5.conf
che contiene il realm di appartenenza e il nome DNS del server KDC. Eventualmente eseguire dpkg-reconfigure krb5-config
per specificare nuovamente i parametri, ad esempio:
Default Kerberos version 5 realm: RIGACCI.ORG Does DNS contain pointers to your realm's Kerberos Servers? No Kerberos servers for your realm: kdc.soluzioni.per Administrative server for your Kerberos realm: kdc.soluzioni.per
Nel database Kerberos deve essere presente solo il principal (account) dell'utente. Non è necessario creare un principal per l'host su cui si effettua il login, né tantomeno sull'host è necessario creare una chiave nel keytab file.
Per verificare che l'autenticazione Kerberos funzioni un utente qualunque può utilizzare kinit
, verificare il risultato con klist
e rimuovere il ticket con kdestroy
:
# kinit angela@RIGACCI.ORG Password for angela@RIGACCI.ORG: # klist -5 Ticket cache: FILE:/tmp/krb5cc_0 Default principal: angela@RIGACCI.ORG Valid starting Expires Service principal 01/07/08 22:36:23 01/08/08 08:36:23 krbtgt/RIGACCI.ORG@RIGACCI.ORG renew until 01/08/08 22:36:19 # kdestroy
Per fare in modo che tutti i programmi PAM utilizzino Kerberos si modificano alcuni file in /etc/pam.d/
, aggiungendo al tradizionale pam_unix.so
il modulo pam_krb5.so
.
ATTENZIONE: Con Debian Squeeze queste aggiunte vengono effettuate automaticamente con l'installazione del pacchetto libpam-krb5, grazie al comando pam-auth-update
. Le regole sono in realtà molto più elaborate ed efficaci.
common-auth: auth sufficient pam_krb5.so minimum_uid=1000 auth required pam_unix.so try_first_pass nullok_secure common-session: session optional pam_krb5.so minimum_uid=1000 session required pam_unix.so common-account: account required pam_krb5.so minimum_uid=1000 account required pam_unix.so common-password: password sufficient pam_krb5.so minimum_uid=1000 password required pam_unix.so nullok obscure md5
La sintassi dei dei file sopra non mi convince, sonsultare anche i documenti Setting up OpenLDAP e Setting up MIT Kerberos 5.
Pare che il modulo pam_krb5
in alcune circostanze non cancelli il file temporaneo con il ticket rilasciato da Kerberos. Tali file si accumulano indefinitamente in /tmp
con nomi del tipo krb5cc_pam_*
, tale situazione si verifica ad esempio con il courier authdaemon per ogni login POP3.
Forse è possibile configurare meglio il modulo pam, nel dubbio si attiva un cronjob che cancella i ticket più vecchi di qualche ora (non ha senso tenere i ticket oltre le 10 ore, vedere qual'è il max_life
dei ticket):
#!/bin/sh # Remove temporary Kerberos ticket cache left by PAM subsystem. find /tmp -name "krb5cc_pam_*" -mmin +240 | xargs -r rm
La distribuzione di riferimento è una Debian Sarge. Si installano i seguenti pacchetti:
apt-get install slapd ldap-utils
Durante l'installazione viene chiesto come costruire il DN (Distinguished Name) dell'archivio LDAP, si suggerisce di usare il nome del dominio DNS. Ad esempio con il dominio rigacci.org
, la radice dell'albero LDAP diventa DN dc=rigacci, dc=org
. Ogni oggetto dovrà essere figlio di questo.
La porta da aprire sul firewall è la 389 TCP e UDP.
slapd
ldap-utils
db4.2-util
, libiodbc2
, libltdl3
, libsasl2-modules
, libslp1
phpldapadmin
, php4-ldap
Il pacchetto Debian Sarge propone di supportare solo la v.3 del protocollo.
/etc/ldap/slapd.conf
Dentro il file di configurazione del server LDAP ci sono alcune opzioni globali (già presenti nel file di configurazione), si aggiunge la definizione del database da gestire (oppure la si include da un file esterno). Una struttura di database d'esempio è la seguente:
# See man slapd.conf # Log connections/operations/results loglevel 256 database dbm suffix "o=ipbox" rootdn "cn=LdapAdmin,o=ipbox" #rootpw {SSHA}lxy7HF6eP7fRaA3G5L85zhk6zWZP8+Fk rootpw soloperprova schemacheck on lastmod on directory /var/lib/ldap/ipbox index cn,sn pres,eq,sub access to attrs=userPassword by dn="cn=LdapAdmin,o=ipbox" write by anonymous auth by self write by * none access to * by dn="cn=LdapAdmin,o=ipbox" write by * read
Come si vede nel file di configurazione viene indicato quali indici mantenere nel database ed acluni criteri di accesso. Nell'esempio sopra ciascun utente può cambiare la propria password, l'utente cn=LdapAdmin,o=ipbox
ha accesso completo in scrittura, tutti gli altri in sola lettura. L'utente privilegiato e la sua password è definito direttamente nel file di configurazione, quindi non è necessario inserirlo nel database vero e proprio.
Dopo aver modificato il file di configurazione si esegue /etc/init.d/slapd restart
, il log viene scritto in /var/log/syslog
.
NOTA: Prima di poter importare un oggetto nel database LDAP bisogna aver creato tutti gli oggetti parent, a partire dalla radice (ricordarsi che LDAP gestisce un database ad albero gerarchico). Ad esempio prima di aggiungere un distinguished name uid=jdoe,ou=people,dc=example,dc=com, bisogna che siano stati aggiunti gli oggetti dc=example,dc=com e ou=people,dc=example,dc=com.
In questo esempio si crea l'oggetto o=ipbox
prima di poter aggiungere le persone del tipo cn=Mario,o=ipbox
. Questo si può fare con un primo file .ldif
(vedere più avanti com caricare un file .ldif
):
dn: o=ipbox objectClass: top objectClass: organization o: ipbox
Si possono importare dei dati nel database a partire da un file .ldif
, ecco ad esempio rubrica.ldif
con un record:
dn: cn=Mario Rossi,o=ipbox objectClass: top objectClass: inetOrgPerson cn: Mario Rossi displayName: Mario Rossi givenName: Mario sn: Rossi uid: oqY6hwrjK3 mail: mario.rossi@texnet.it
Si importa il file nel database con comandi del tipo:
ldapadd -h 127.0.0.1 -D "cn=LdapAdmin,o=ipbox" -W -xv -f rubrica.ldif ldapadd -H ldap://127.0.0.1/ -D "cn=LdapAdmin,o=ipbox" -W -xv -f rubrica.ldif
Per esportare il contenuto del database in un file .ldif
invece si usa il comando:
slapcat -b "o=ipbox"
Per creare una rubrica si consiglia di seguire uno dei due schemi più diffusi: inetOrgPerson
oppure mozillaOrgPerson
. Il secondo è più ricco di attributi, ma non è compreso nella pacchettizzazione standard Debian. Si scarica il file .schema
da Internet, lo si salva in /etc/ldap/schema/
, si aggiunge a /etc/ldap/slapd.conf
una riga:
include /etc/ldap/schema/mozillaorgperson.schema
Pare che Outlook e Outlook Express si trovino a proprio agio con entrambe le strutture dati, altrettanto per Kmail.
Come client possiamo utilizzare KAddressBook (la rubrica di KDE), oppure LDAP Explorer (un applicativo in PHP basato sul web, puntare il browser su http://ldapserver/ldapexplorer/). I parametri necessari alla connessione in lettura/scrittura sono i seguenti:
Server LDAP | 10.0.1.111 |
---|---|
Porta | TCP 389 |
Base DN | o=ipbox |
Query type | One level (not recursive) |
User (Bind DN as) | cn=LdapAdmin,o=ipbox |
Password | soloperprova |
Per un accesso in sola consultazione si immettono gli stessi dati, omettendo User e Password.
Si installa il pacchetto Debian phpldapadmin. Il file di configurazione /etc/phpldapadmin/config.php
contiene il nome derl server LDAP, la porta, il nome con cui collegarsi. Se la connessione viene fatta alla porta 636 ldaps bisogna non attivare l'opzione tls, altrimenti si ottiene l'errore:
slapd[29352]: conn=40 op=0 STARTTLS slapd[29352]: conn=40 op=0 RESULT oid= err=1 text=TLS already started
Per accedere all'interfaccia web di amministrazione si punta il browser su http://ldap.mydomain.org/phpldapadmin/, usando le opportune credenziali.