====== Autenticazione Kerberos per NFSv4 ======
La versione 4 del protocollo NFS si distingue dalla precedente versione 3 soprattutto per l'uso obbligatorio di una sicurezza forte (basata su //Kerberos versione 5//) e di un migliore meccanismo di locking (//mandatory locking// invece di //advisory locking//). L'uso del protocollo TCP su una sola porta facilita il passaggio attraverso i firewall.
In questo esempio semplificato il **Kerberos Distribution Center** (KDC) dove gira il demone è lo stesso host su cui gira il servizio NFS. Non esistono KDC slave, solo il master.
La distribuzione di riferimento è una GNU/Linux **Debian Lenny**.
**Web references**
* [[http://aput.net/~jheiss/krbldap/|Replacing NIS with Kerberos and LDAP HOWTO]]
* [[http://www-theorie.physik.unizh.ch/~dpotter/howto/kerberos|Kerberos/LDAP/NFSv4 HOWTO]]
* [[http://www.freesoftwaremagazine.com/blogs/securing_nfs]]
* [[http://mailman.mit.edu/pipermail/kerberos/2007-May/011581.html]]
* [[http://gentoo-wiki.com/HOWTO_NFSv4|HOWTO NFSv4]]
* [[http://www.citi.umich.edu/projects/nfsv4/linux/faq/|Linux NFSv4 FAQ]]
===== Verifiche preliminari =====
* NTP installato e ora sincronizzata tra server e client.
* Il comando **''%%hostname --fqdn%%''** deve restituire un nome completo di dominio sul server e sul client.
===== Installazione server =====
Questi i pacchetti Debian da installare sul server:
* **krb5-kdc**: Kerberos key server
* **krb5-admin-server**: Kerberos admin daemon e altri comandi di amministrazione
Si deve creare il //realm// (dominio a cui apparterranno i server e i client) e alcuni //principal// (credenziali di utenti e servizi). L'installazione del pacchetto **krb5-config** richiede il nome del //realm// il nome dei //Kerberos servers// e dell'//Administrative server//, queste informazioni vengono scritte in due file di configurazione:
* **''/etc/krb5.conf''** file di configurazione per tutte le utility (client) Kerberos
* **''/etc/krb5kdc/kdc.conf''** file di configurazione del demone KDC
In Debian abbiamo il comodo script **krb5_newrealm** che crea il database con gli account **/var/lib/krb5kdc/principal**, lo stash (un file che contiene la master key) **/etc/krb5kdc/stash** ed avvia i demoni eseguendo nell'ordine:
* kdb5_util create -s
* /etc/init.d/krb5-kdc start
* /etc/init.d/krb5-admin-server start
Ecco in dettaglio la creazione del realm con la richiesta della master key:
# kdb5_util create -s
Loading random data
Initializing database '/var/lib/krb5kdc/principal' for realm 'MYREALM.ORG',
master key name 'K/M@MYREALM.ORG'
You will be prompted for the database Master Password.
It is important that you NOT FORGET this password.
Enter KDC database master key:
Lo script crea anche un file con le ACL **''/etc/krb5kdc/kadm5.acl''**, è consuetudine scommentare l'ultima riga per dare diritto di accesso a tutti i //principal// (account) il cui nome sia del tipo **%%nome/admin%%**:
# This file Is the access control list for krb5 administration.
# When this file is edited run /etc/init.d/krb5-admin-server restart to activate
# One common way to set up Kerberos administration is to allow any principal
# ending in /admin is given full administrative rights.
# To enable this, uncomment the following line:
*/admin *
Quindi si deve creare anche un account a cui dare questi privilegi, ad esempio **root/admin@MYREALM.ORG**. Si utilizza l'utilty **''kadmin.local''**, come mostrato nel paragrafo successivo.
A questo punto sul server abbiamo tre demoni in esecuzione:
* **/usr/sbin/krb5kdc** in ascolto sulle porte **88 UDP** (Kerberos v5) e **750 UDP** (Kerberos v4)
* **/usr/sbin/kadmind** in ascolto sulla porta **749 TCP**
* **/usr/sbin/krb524d** in ascolto sulla porta **4444 UDP** (demone per la conversione delle credenziali da v.5 a v.4, non esiste più in Debian Squeeze, **krb5-kdc** versione 1.8.3)
==== Dump e restore del database Kerberos ====
Per salvare tutti i principals in un file ASCII:
kdb5_util dump -verbose kerberos_principals.dump
Per effettuare il restore su una macchina appena installata, senza aver creato il database in precedenza:
kdb5_util load -verbose kerberos_principals.dump
Per completare il restore bisogna recuperare anche il file con lo stash (gli eventuali messaggi di errore indicano la mancanza della //master key//) e le ACL, si tratta dei file:
* **''/etc/krb5kdc/stash''**
* **''/etc/krb5kdc/kadm5.acl''**
==== Modificare il lifetime dei ticket ====
La durata predefinita di un ticket è di **10 ore** (installazione Debian). Per modificarla sono necessarie diverse operazioni.
Editare il file **''/etc/krb5kdc/kdc.conf''** e modificare il **max_life** del realm predefinito. Questo parametro viene usato per creare i nuovi principal (non serve riavviare alcun servizio):
[realms]
RIGACCI.ORG = {
max_life = 16h 0m 0s
Modificare il **''maxlife''** del principal **''krbtgt/REALM@REALM''**, ad esempio con **''kdamin.local''**:
getprinc krbtgt/RIGACCI.ORG@RIGACCI.ORG
Maximum ticket life: 0 days 10:00:00
...
modprinc -maxlife "0 days 16 hours" krbtgt/RIGACCI.ORG@RIGACCI.ORG
Modificare il **''maxlife'' di tutti i principal creati in precedenza**.
===== Creazione account utente =====
L'utility **kadmin.local** consente di creare nuovi account (nella terminologia Kerberos sono chiamati **//principal//**). Si esegue con i **privlegi di root** sul server che ospita il KDC e non richiede alcuna ulteriore autenticazione.
kadmin.local: addprinc niccolo@MYREALM.ORG
WARNING: no policy specified for niccolo@MYREALM.ORG; defaulting to no policy
Enter password for principal "niccolo@MYREALM.ORG":
Re-enter password for principal "niccolo@MYREALM.ORG":
Principal "niccolo@MYREALM.ORG" created.
kadmin.local: addprinc root@MYREALM.ORG
...
kadmin.local: addprinc root/admin@MYREALM.ORG
...
kadmin.local: listprincs
K/M@MYREALM.ORG
kadmin/admin@MYREALM.ORG
kadmin/changepw@MYREALM.ORG
kadmin/history@MYREALM.ORG
krbtgt/TEXNET.ORG@MYREALM.ORG
niccolo@MYREALM.ORG
root/admin@MYREALM.ORG
root@MYREALM.ORG
Come si vede esistono altri principal di servizio, oltre a quelli esplicitamente creati da noi.
Dopo aver aggiunto dei principal è possibile delegare le funzioni di amministratore ad altri utenti aggiungendo le opportune ACL in ''/etc/krb5kdc/kadm5.acl''. L'utente delegato userà l'utility **kadmin**. È convenzione diffusa dare privilegi di amministratore a tutti gli utenti del tipo **name/admin@REALM**.
Per gestire i ticket Kerberos si usano le utility **kinit**, **klist** e **kdestroy**.
==== Policy di default ====
Conviene definire una **policy di default**, da cui tutti i nuovi account ereditano alcune caratteristiche, ad esempio la lunghezza minima della password. Per gli account già creati bisogna esplicitamente settare la nuova policy:
add_policy -minlength 5 -minclasses 2 default
get_policy default
modify_principal -policy default niccolo@MYREALM.ORG
===== Installazione client =====
Questi i pacchetti Debian da installare sul client:
* **krb5-user** programmi per l'autenticazione Kerberos, gestione dei ticket, cambio della password.
* **krb5-config** prepara la configurazione per le utility Kerberos.
L'installazione scrive in **''/etc/krb5.conf''** il realm e il server KDC predefinito.
===== Creazione account per server e client NFS =====
Sul server KDC si creano due account, uno per il server NFS e uno per il client (nella terminologia Kerberos un account viene detto //principal//), il nome dell'account è del tipo **%%service_name/hostname@REALM%%**. Sul server e sul client NFS bisogna invece creare le rispettive chiavi, che verranno salvate nei rispettivi file **''/etc/krb5.keytab''**.
Giusto per fare un esempio, una parte la eseguiamo sul server KDC (che nel nostro esempio è anche **server NFS**) da utente **root** con **''kadmin.local''**:
# kadmin.local
addprinc -randkey nfs/inside.mydomain.org@MYREALM.ORG
WARNING: no policy specified for nfs/inside.mydomain.org@MYREALM.ORG; defaulting to no policy
Principal "nfs/inside.mydomain.org@MYREALM.ORG" created.
kadmin.local: listprincs
kadmin.local: ktadd -e des nfs/inside.mydomain.org@MYREALM.ORG
Entry for principal nfs/inside.mydomain.org@MYREALM.ORG with kvno 3,
encryption type DES cbc mode with RSA-MD5 added to keytab WRFILE:/etc/krb5.keytab.
kadmin.local: exit
Il comando **ktadd** aggiunge una chiave nel file locale **''/etc/krb5.keytab''**. Questa chiave deve stare sul **server NFS**, non confondiamoci col fatto che KDC e server NFS sono sullo stesso host in questo esempio.
:!: **ATTENZIONE** al bug **[[http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=413838|413838]]**:
Notare l'uso del comando **''ktadd''** con l'opzione **%%-e des%%** . Il risultato è la creazione di **una sola entry** nella keytab, associata alla crittografia DES; l'impostazione predefinita sarebbe quella di creare due entry, una delle quali con crittografia triplo DES. Il server NFS supporta solo il DES: un bug nella procedura di negoziazione Kerberos causa il fallimento del mount se è presente anche la chiave triplo DES.
La seconda parte la eseguiamo sul client NFS, con il comando **''kadmin''** (ovviamente richiede la password di amministratore Kerberos). È necessario usare l'utente **root** perché si deve aggiungere una chiave al file locale **''/etc/krb5.keytab''**:
# kadmin -p root/admin@MYREALM.ORG
Authenticating as principal root/admin@MYREALM.ORG with password.
Password for root/admin@MYREALM.ORG:
kadmin: addprinc -randkey nfs/ulisse.mydomain.org@MYREALM.ORG
WARNING: no policy specified for nfs/ulisse.mydomain.org@MYREALM.ORG; defaulting to no policy
Principal "nfs/ulisse.mydomain.org@MYREALM.ORG" created.
kadmin: ktadd nfs/ulisse.mydomain.org@MYREALM.ORG
Entry for principal nfs/ulisse.mydomain.org@MYREALM.ORG with kvno 5,
encryption type Triple DES cbc mode with HMAC/sha1 added to keytab WRFILE:/etc/krb5.keytab.
Entry for principal nfs/ulisse.mydomain.org@MYREALM.ORG with kvno 5,
encryption type DES cbc mode with CRC-32 added to keytab WRFILE:/etc/krb5.keytab.
Il comando **addprinc** genera un nuovo account sul **server KDC remoto**, il comando **ktadd** invece aggiunge una chiave nel **file ''/etc/krb5.keytab'' locale**.
Verificare che funzioni la risoluzione del nome DNS //ulisse.mydomain.org//, sia diretta che inversa.
Per vedere chiavi memorizzate localmente in **''/etc/krb5.keytab''**:
k5srvutil list
Keytab name: FILE:/etc/krb5.keytab
KVNO Principal
---- --------------------------------------------------------------------------
3 nfs/ulisse.mydomain.org@MYREALM.ORG
3 nfs/ulisse.mydomain.org@MYREALM.ORG
Per eliminare delle chiavi si usa il comando **''k5srvutil delete''**.
===== Configurazione server NFS =====
Si configura il server NFS in modo che sappia trovare il server KDC (dovrebbe già essere così in seguito all'installazione), nel file **''/etc/krb5.conf''**:
[libdefaults]
default_realm = MYREALM.ORG
[realms]
MYREALM.ORG = {
kdc = inside.mydomain.org
admin_server = inside.mydomain.org
}
[login]
krb4_convert = false
krb4_get_tickets = false
Infine il file **''/etc/exports''** deve richiedere l'autenticazione Kerberos e usare le opzioni specifiche di NFSv4:
/home gss/krb5(fsid=0,rw,sync,no_root_squash,no_subtree_check)
Notare che dal kernel 2.6.23 la sintassi **gss/krb5** è deprecata, si deve usare l'opzione **sec=** come suggerito da man exports(5).
Per vedere quali directory risultano esportate:
showmount -e 127.0.0.1
Export list for 127.0.0.1:
/home gss/krb5
**ATTENZIONE**: Non esportare sottodirectory di directory già esportate, specialmente mescolando tipi di accesso diverso (host e gss/krb5, NFSv3 e NFSv4). Si potrebbe incappare nell'errore che la sottodirectory non risulta esportata come ci si aspetta. In questo esempio si pensava di esportare **''/home''** e invece NFS cerca di esportare **''/''**:
mountd[2937]: refused mount request from 192.168.1.2 for /home (/): not exported
Altro possibile errore: se sul server non è attivo **rpc.gssd** oppure **rpc.svcgssd** il client non viene riconosciuto:
mountd[1116]: mount request from unknown host 192.168.1.2 for /home (/home)
Ricordarsi di attivare anche **rpc.idmapd**, altrimenti tutti i file esportati risulteranno appartenere a nobody:nogroup.
In Debian questo significa impostare **NEED_SVCGSSD=yes** in **''/etc/default/nfs-kernel-server''** e **NEED_IDMAPD=yes** e **NEED_GSSD=yes** in **''/etc/default/nfs-common''**.
===== Configurazione client NFS =====
È indispensabile attivare il demone **rpc.idmapd**, impostando **NEED_IDMAPD=yes** in **''/etc/default/nfs-common''**. Altrimenti user e group degli oggetti nel filesystem montato non sono corretti.
Bisogna attivare anche il demone **rpc.gssd**, con Debian è sufficiente impostare **NEED_GSSD=yes** in **''/etc/default/nfs-common''**. Altrimenti si incappa nel seguente errore:
# mount -v -t nfs4 inside.mydomain.org:/ /nfs/inside/home -o rw,sec=krb5
mount.nfs4: Connection timed out
**ATTENZIONE**: Con NFSv4 la directory esportata con l'opzione **fsid=0** diventa la radice NFSv4, pertanto va montata come tale, senza specificare il percorso. Altrimenti questo è il messaggio di errore:
mount -t nfs4 inside.mydomain.org:/home /nfs/inside/home -o rw,sec=krb5
mount.nfs4: mounting inside.mydomain.org:/home failed, reason given by server:
No such file or directory
Quindi per montare //una tantum// la directory:
mount -v -t nfs4 inside.mydomain.org:/ /net/inside -o rw,sec=krb5
mount.nfs4: pinging: prog 100003 vers 4 prot tcp port 2049
inside.mydomain.org:/ on /nfs/inside type nfs4 (rw,sec=krb5)
oppure per montarla ad ogni boot si mette in **''/etc/fstab''**:
inside.mydomain.org:/ /net/inside nfs4 rw,sec=krb5 0 0
===== Troubleshooting =====
Se si sospettano problemi di permessi conviene controllare cosa dice il demone **rpc.gssd** sul client. Avviare il demone con l'opzione **-vvv** (Debian: impostando **RPCGSSDOPTS="-vvv"** in ''/etc/default/nfs-common'').
Ad esempio il seguente errore si risolve rinnovando il ticket Kerberos con il comando **''kinit(1)''**:
rpc.gssd[13175]: ERROR: GSS-API: error in gss_acquire_cred(): The referenced credential has expired - No error
Qui abbiamo un problema con la **risoluzione dei nomi**; un nome risolve in un dirizzo IP il cui reverse lookup non risolve nel nome stesso:
# host cheope.rigacci.org
cheope.rigacci.org has address 192.168.200.245
# host 192.168.200.245
245.200.168.192.in-addr.arpa domain name pointer ldap.rigacci.org.
risultano i seguenti errori nel **''/var/log/auth.log''** del server:
krb5kdc[27119]: TGS_REQ (7 etypes {18 17 16 23 1 3 2}) 172.16.6.2: UNKNOWN_SERVER: authtime 1200091396,
nfs/bari.rigacci.org@RIGACCI.ORG for nfs/ldap.rigacci.org@RIGACCI.ORG,
Server not found in Kerberos database
krb5kdc[27119]: TGS_REQ (1 etypes {1}) 172.16.6.2: UNKNOWN_SERVER: authtime 1200091396,
nfs/bari.rigacci.org@RIGACCI.ORG for nfs/ldap.rigacci.org@RIGACCI.ORG,
Server not found in Kerberos database
e i seguenti sul client:
rpc.gssd[7053]: rpcsec_gss: gss_init_sec_context: (major) Unspecified GSS failure.
Minor code may provide more information - (minor) Server not found in Kerberos database
Altro errore legato al bug **[[http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=413838|413838]]**: la negoziazione della crittografia DES (l'unica supportata dal server NFS) fallisce se sul server NFS esiste anche una chiave triple DES.
rpc.gssd[7053]: WARNING: Failed to create krb5 context for user with uid 0 with any credentials cache
for server cheope.rigacci.org
sul server si legge
rpc.svcgssd[9833]: leaving poll
rpc.svcgssd[9833]: handling null request
rpc.svcgssd[9833]: WARNING: gss_accept_sec_context failed
rpc.svcgssd[9833]: ERROR: GSS-API: error in handle_nullreq: gss_accept_sec_context(): Unspecified GSS failure.
Minor code may provide more information - Key version number for principal in key table is incorrect
rpc.svcgssd[9833]: sending null reply