J’utilise uniquement mit-krb5 (je n’utilise pas l’implémentation Heimdal). Ici je ne détaillerai que le cas d’une architecture non répliquée.
Le poste client et sous Archlinux, le serveur sous Gentoo. Le but de cette installation est de sécuriser un partage NFSv4 (serveur NFS sous Gentoo et client Archlinux, ce sont les deux même machines).
Vérifier les informations trouvées sur le net (y compris ce wiki) sur la documentation officiel correspondant à votre version de krb5.
Notes générales
Qu’est ce que Kerberos
Outre le fait que ce soit le chien des enfers, Kerberos est un système d’authentification SSO (single-sign-on).
Quelle meilleur description que celle de ceux qui l’on inventé et implémenté :
Kerberos V5 is an authentication system developed at MIT. Kerberos is named for the three-headed watchdog from Greek mythology, who guarded the entrance to the underworld.
[…] Since Kerberos negotiates authenticated, and optionally encrypted, communications between two points anywhere on the internet, it provides a layer of security that is not dependent on which side of a firewall either client is on. Since studies have shown that half of the computer security breaches in industry happen from inside firewalls, MIT’s Kerberos V5 plays a vital role in maintaining your network security.
[…] Kerberos V5 is a single-sign-on system, which means that you have to type your password only once per session, and Kerberos does the authenticating and encrypting transparently.
Fonctionnement général
Le fonctionnement général de kerberos est assez bien décrit sur Wikipedia et dans la documentation officiel.
Under Kerberos, a client (generally either a user or a service) sends a request for a ticket to the Key Distribution Center (KDC). The KDC creates a ticket-granting ticket (TGT) for the client, encrypts it using the client’s password as the key, and sends the encrypted TGT back to the client. The client then attempts to decrypt the TGT, using its password. If the client successfully decrypts the TGT (i.e., if the client gave the correct password), it keeps the decrypted TGT, which indicates proof of the client’s identity.
The TGT, which expires at a specified time, permits the client to obtain additional tickets, which give permission for specific services. The requesting and granting of these additional tickets is user-transparent.
Ticket
Un ticket est un « passe » (fichier ou élément en mémoire) permettant d’authentifier un principal sur un réseau (et donc au final de lui permettre d’accéder à certain services).
La notion de ticket est assez bien décrite dans la documentation officiel mais reste très théorique.
D’après ce que j’ai pu lire jusqu’à présent et ce que j’en ai compris un ticket contient :
Le tout chiffré avec la clé du principal auquel il est destiné.
TGT
C’est premier le ticket ticket qu’un principal obtient. Il permet au client d’obtenir d’autre ticket permettant d’accéder à des services.
Un exemple ; je dispose d’un serveur NFSv4 qui requière une authentification via Kerberos.
Sur le client, montage de la partition NFSv4 sécurisée
max@laptop % mount /mnt/ddext
max@laptop % ls /mnt/ddext
ls: impossible d'ouvrir le répertoire /mnt/ddext: Permission non accordée
max@laptop % klist
klist: Credentials cache file '/tmp/krb5cc_1000' not found
Pour l’instant je (utilisateur max soit principal max@LAN) ne suis pas authentifié sur le serveur Kerberos.
Je ne peut donc pas accéder au partage même si celui-ci est monté.
max@laptop % kinit
Password for max@LAN:
max@laptop % klist
Ticket cache: FILE:/tmp/krb5cc_1000
Default principal: max@LAN
Valid starting Expires Service principal
16/11/2014 18:24:19 17/11/2014 18:24:19 krbtgt/LAN@LAN
Je me suis authentifié et ai donc obtenu un TGT (krbtgt/LAN@LAN).
max@laptop % ls /mnt/ddext
bd/ Bouquins/ Images/ …
max@laptop % klist
Ticket cache: FILE:/tmp/krb5cc_1000
Default principal: max@LAN
Valid starting Expires Service principal
16/11/2014 18:24:19 17/11/2014 18:24:19 krbtgt/LAN@LAN
16/11/2014 18:24:32 17/11/2014 18:24:19 nfs/server.lan@LAN
Je peux maintenant accédé au partage.
La commande ls a aussi déclenché la requête d’un ticket spécifique au service NFS.
Le système a automatiquement utilisé le TGT pour obtenir le ticket nfs/server.lan@LAN.
La machine cliente a eu besoin de s’authentifier pour faire le mount (principal nfs/laptop.lan@LAN) mais ça n’est pas important dans cette exemple.
principal
La meilleur description que j’ai pu trouvé est celle de la documentation officiel.
A Kerberos principal is a unique identity to which Kerberos can assign tickets. Principals can have an arbitrary number of components. Each component is separated by a component separator, generally ‘/’. The last component is the realm, separated from the rest of the principal by the realm separator, generally ‘@’. If there is no realm component in the principal, then it will be assumed that the principal is in the default realm for the context in which it is being used.
Traditionally, a principal is divided into three parts: the primary, the instance, and the realm. The format of a typical Kerberos V5 principal is primary/instance@REALM.
- The primary is the first part of the principal. In the case of a user, it’s the same as your username. For a host, the primary is the word host.
- The instance is an optional string that qualifies the primary. The instance is separated from the primary by a slash (/). In the case of a user, the instance is usually null, but a user might also have an additional principal, with an instance called admin, which he/she uses to administrate a database. The principal jennifer@ATHENA.MIT.EDU is completely separate from the principal jennifer/admin@ATHENA.MIT.EDU, with a separate password, and separate permissions. In the case of a host, the instance is the fully qualified hostname, e.g., daffodil.mit.edu.
- The realm is your Kerberos realm. In most cases, your Kerberos realm is your domain name, in upper-case letters. For example, the machine daffodil.example.com would be in the realm EXAMPLE.COM.
En résumé, un principal un utilisateur, une machine… un élément unique auquel Kerberos peux assigné un ticket. Il possède une clé secrète. Dans l’exemple de Wikipedia, le client et le serveur d’impression sont des principals.
Realm
Littéralement le « royaume », c’est une parti du principal.
On peut le voir comme un nom de domaine.
Dans le principal le realm est positionné après le @ et est généralement en lettres capitales.
KDC
Key Distribution Center distribue les clés et les tickets. Englobe le serveur d’authentification et le TGS.
TGS
Ticket-Granting Server distribue les tickets.
keytab
C’est un fichier où sont stocké les clés de certains principals. Cela permet à ces principals d’obtenir leur tickets sans avoir a rentrer un mot de passe (encore faut-il qu’il ait accès au keytab).
Par défaut le fichier keytab est /etc/krb5.keytab.
Implémentation
mit-krb5 se compose de plusieurs démons et d’outils clients. Les principaux sont :
- krb5kdc : démon principal
- krb5kadmind : démon d’administration, permet d’ajouter des principal, d’écrire dans le keytab…
- klist : liste les tickets et les clés du keytab
- kadmin : permet d’administrer la bdd du KDC
- kinit : permet de demandé un ticket
Installation
Pas de version client, un seul paquet pour les outils clients et les serveurs.
Archlinux :
root@laptop # pacman -S krb5
Gentoo :
root@server # emerge krb5
Configuration
- serveur Gentoo :
- hostname : server
- domain : lan
- ip : 192.168.1.102
- client Archlinux :
- hostname : laptop
- domain : lan
- ip : 192.168.1.100
- Realms : LAN
Synchronisation ntp
Il faut que l’horloge du serveur et du client soit synchronisée.
Je passe les détails mais en gros, sur le serveur Gentoo (si celui-ci utilise openntpd) :
max@laptop % cat /etc/ntpd.conf
listen on *
servers 0.gentoo.pool.ntp.org
servers 1.gentoo.pool.ntp.org
servers 2.gentoo.pool.ntp.org
servers 3.gentoo.pool.ntp.org
Sur le client Archlinux, /etc/systemd/timesyncd.conf :
[Time]
NTP=server.lan
FallbackNTP=0.arch.pool.ntp.org 1.arch.pool.ntp.org 2.arch.pool.ntp.org 3.arch.pool.ntp.org
Sinon on peut mettre n’importe quelle source du moment que c’est la même.
Client (Archlinux)
/etc/krb5.conf
[libdefaults]
default_realm = LAN
[realms]
LAN = {
admin_server = server.lan
default_domain = lan
kdc = server.lan
}
[domain_realm]
.lan = LAN
lan = LAN
Sources :
Serveur (Gentoo)
Général
Le serveur et le client doivent utiliser le même fichier de configuration général krb5.conf.
KDC
Le programmes relatif au KDC (uniquement utilisé sur le serveur) parse les fichier krb5.conf et kdc.conf.
Il est donc possible, mais non recommandé de placer des section du kdc.conf dans le krb5.conf.
/etc/kdc.conf
[kdcdefaults]
[realms]
LAN = {
database_name = /var/lib/krb5kdc/principal
acl_file = /var/lib/krb5kdc/kadm5.acl
key_stash_file = /var/lib/krb5kdc/.k5.LAN
kdc_ports = 88
max_life = 10h 0m 0s
max_renewable_life = 7d 0h 0m 0s
}
[logging]
kdc = SYSLOG
admin_server = SYSLOG
default = SYSLOG
Sources :
Base de données
Création de la base de données utilisé par le KDC :
root@server # kdb5_util create -s
-s permet de stocker la clé du KDC (le mot de passe) dans un fichier (stash file, .k5.LAN).
Ça évite d’avoir a entrer la clé (le mot de passe) à chaque démarrage du KDC.
La base sera créé dans le dossier /var/lib/krb5kdc/.
Source : documentations officiel d’installation (version 1.12)
Principal d’administration
Création du principal d’administration root/admin@LAN qui va nous servir à configurer les autres.
root@server # kadmin.local
Authenticating as principal root/admin@LAN with password.
kadmin.local: addprinc root/admin@LAN
WARNING: no policy specified for root/admin@LAN; defaulting to no policy
Enter password for principal "root/admin@LAN":
Re-enter password for principal "root/admin@LAN":
Principal "root/admin@LAN" created.
kadmin.local: quit
On pourrait penser que cette partie n’est pas obligatoire, vu qu’il est possible de d’administrer la base via kadmin.local.
C’est effectivement le cas si on utilise pas le fichier keytab sur les client.
Si on veut utiliser le keytab sur un poste client (c’est le cas dans une conf NFSv4), on va devoir utiliser l’outil kadmin sur le poste client (seul outil, à ma connaissance, capable d’écrire dans le keytab) et donc on va avoir besoins d’un principal d’administration (cf. section keytab dans « Création de principals »).
Sources :
ACL
On donne tous les droits à ce principal. C’est pas très safe mais j’en ai rien à foutre.
root@server # cat /var/lib/krb5kdc/kadm5.acl
root/admin@LAN *
root@server # chmod 600 /var/lib/krb5kdc/kadm5.acl
Sources :
Démarrage des démons
systemd
Pour ceux qui ont fait le choix d’utiliser systemd. Au 30/01/2015, sous Gentoo les fichiers d’intégration de mit-krb5 à systemd sont manquant.
J’ai donc utilisé et adapté ceux utilisé sous ArchLinux.
root@server # pwd
/etc/systemd/system
root@server # tail -n +1 krb5-k*
==> krb5-kadmind.service <==
[Unit]
Description=Kerberos 5 administration server
[Service]
ExecStart=/usr/sbin/kadmind -nofork
[Install]
WantedBy=multi-user.target
==> krb5-kdc.service <==
[Unit]
Description=Kerberos 5 KDC
[Service]
ExecStart=/usr/sbin/krb5kdc -n
Restart=always
[Install]
WantedBy=multi-user.target
==> krb5-kpropd.service <==
[Unit]
Description=Kerberos 5 propagation server
[Service]
ExecStart=/usr/sbin/kpropd -S
[Install]
WantedBy=multi-user.target
==> krb5-kpropd@.service <==
[Unit]
Description=Kerberos 5 propagation server
Conflicts=krb5-kpropd.service
[Service]
ExecStart=/usr/sbin/kpropd
StandardInput=socket
StandardError=syslog
==> krb5-kpropd.socket <==
[Unit]
Description=Kerberos 5 propagation server
[Socket]
ListenStream=754
Accept=yes
[Install]
WantedBy=sockets.target
root@server # systemctl daemon-reload
root@server # systemctl start krb5-kdc.service
root@server # systemctl enable krb5-kdc.service
root@server # systemctl start krb5-kadmind.service
Il n’est pas nécessaire de faire en sorte que mit-krb5kadmind tourne tous le temps.
Il doit seulement être démarré quand on utilise kadmin.
OpenRC
Si vous utilisez OpenRC et non systemd.
root@server # /etc/init.d/mit-krb5kadmind start
root@server # rc-update add mit-krb5kdc
mit-krb5kadmind dépend de mit-krb5kdc donc la première commande va démarrer les deux démon.
Il n’est pas nécessaire de faire en sorte que mit-krb5kadmind tourne tous le temps.
Il doit seulement être démarré quand on utilise kadmin.
Vérifications
Vérifié que vos logs contiennent bien les lignes :
krb5kdc[…]: krb5kdc: starting...
kadmind[…]: kadmind: starting...
Ces ligne indique que le KDC et kadmind on bien terminé leurs phase d’initialisation et qu’il sont prêt à gérer les requêtes.
Attention, kadmind génère la ligne de log kadmind[…]: starting.
Ce n’est pas celle qu’on cherche.
J’ai eu quelques soucis avec kadmind.
Celui-ci n’émettait aucune erreur dans les logs mais ne répondait pas.
Après quelques investigations je me suis aperçus qu’il été bloqué sur la lecture de /dev/random.
Mon serveur n’est soumis qu’a peut d’activité et celui-ci ne généré pas assez d’entropie.
kadmind mettait plusieurs minutes à démarrer.
J’ai résolue le problème en utilisant haveged.
Création de principals
Le but de cette installation de Kerberos de mettre en place un serveur NFSv4 avec authentification.
Pour cette exemple je vais donc créer deux principals max@LAN et nfs/laptop.lan@LAN qui me serviront dans la mise en place du NFS.
max@LANpossède une clé connunfs/laptop.lan@LANpossède une clé aléatoire, pour l’utiliser nous devrons stocker sa clé dans le keytab (du client).
Soit :
root@server # kadmin
Authenticating as principal root/admin@LAN with password.
Password for root/admin@LAN:
kadmin: addprinc max
WARNING: no policy specified for max@LAN; defaulting to no policy
Enter password for principal "max@LAN":
Re-enter password for principal "max@LAN":
Principal "max@LAN" created.
kadmin: addprinc -randkey nfs/laptop.lan
WARNING: no policy specified for nfs/laptop.lan@LAN; defaulting to no policy
Principal "nfs/laptop.lan@LAN" created.
kadmin: quit
keytab
Pour pouvoir récupérer la clé de principal nfs/laptop.lan@LAN et la stocker dans le fichier keytab du client nous devons nous connecter à la console d’administration à partir du poste client.
root@laptop # kadmin
Authenticating as principal root/admin@LAN with password.
Password for root/admin@LAN:
kadmin: ktadd nfs/laptop.lan
Entry for principal nfs/laptop.lan with kvno 3, encryption type aes256-cts-hmac-sha1-96 added to keytab FILE:/etc/krb5.keytab.
Entry for principal nfs/laptop.lan with kvno 3, encryption type aes128-cts-hmac-sha1-96 added to keytab FILE:/etc/krb5.keytab.
Entry for principal nfs/laptop.lan with kvno 3, encryption type des3-cbc-sha1 added to keytab FILE:/etc/krb5.keytab.
Entry for principal nfs/laptop.lan with kvno 3, encryption type arcfour-hmac added to keytab FILE:/etc/krb5.keytab.
kadmin: quit
Vérifications
root@laptop # klist -k
Keytab name: FILE:/etc/krb5.keytab
KVNO Principal
---- --------------------------------------------------------------------------
3 nfs/laptop.lan@LAN
3 nfs/laptop.lan@LAN
3 nfs/laptop.lan@LAN
3 nfs/laptop.lan@LAN
Le keytab contient bien la clé du principal nfs/laptop.lan@LAN.
Le fait qu’elle soit présente plusieurs fois est normal. Elle est chiffrée avec plusieurs algorithmes :
root@laptop # klist -k -e
Keytab name: FILE:/etc/krb5.keytab
KVNO Principal
---- --------------------------------------------------------------------------
3 nfs/laptop.lan@LAN (aes256-cts-hmac-sha1-96)
3 nfs/laptop.lan@LAN (aes128-cts-hmac-sha1-96)
3 nfs/laptop.lan@LAN (des3-cbc-sha1)
3 nfs/laptop.lan@LAN (arcfour-hmac)
obtention de tickets
Pour vérifier que tout à bien fonctionné nous allons faire des demandes de tickets.
max@LAN
Je suis loggé en temps que max, par défaut kinit demande donc un ticket pour max@LAN.
Je n’ai pas besoins de lui spécifier d’option.
max@laptop % klist
klist: Credentials cache file '/tmp/krb5cc_1000' not found
max@laptop % kinit
Password for max@LAN:
max@laptop % klist
Ticket cache: FILE:/tmp/krb5cc_1000
Default principal: max@LAN
Valid starting Expires Service principal
16/11/2014 15:25:59 17/11/2014 15:25:59 krbtgt/LAN@LAN
nfs/laptop.lan@LAN
Ici je doit spécifier à kinit d’utiliser le principal nfs/laptop.lan@LAN mais aussi de chercher la clé dans le keytab.
Je suis loggé en root car le fichier keytab n’est accessible qu’à cette utilisateur.
root@laptop # klist
klist: Credentials cache file '/tmp/krb5cc_0' not found
root@laptop # kinit -k -p nfs/laptop.lan
root@laptop # klist
Ticket cache: FILE:/tmp/krb5cc_0
Default principal: nfs/laptop.lan@LAN
Valid starting Expires Service principal
16/11/2014 15:58:15 17/11/2014 15:58:15 krbtgt/LAN@LAN
Firewall
Sur le serveur, j’accepte les requêtes au KDC (kerberos : 88), les connexion à kadmind (kerberos-adm : 749) et les requêtes de changement de mot de passe (kpasswd : 464). Les port kerberos-adm et kpasswd sont écouté par le démon kadmind.
-A INPUT -s 192.168.1.0/24 -p tcp --dport kerberos -j ACCEPT
-A INPUT -s 192.168.1.0/24 -p udp --dport kerberos -j ACCEPT
-A INPUT -s 192.168.1.0/24 -p tcp --dport kerberos-adm -j ACCEPT
-A INPUT -s 192.168.1.0/24 -p udp --dport kerberos-adm -j ACCEPT
-A INPUT -s 192.168.1.0/24 -p tcp --dport kpasswd -j ACCEPT
-A INPUT -s 192.168.1.0/24 -p udp --dport kpasswd -j ACCEPT
Sources :
- Expérience personnel
- documentation officiel, section firewall
Réinitialisation
Si vous avez merdé quelque part et que vous voulez repartir sur un truc propre.
Sur le serveur :
root@server # kdestroy
root@server # /etc/init.d/mit-krb5kdc stop
root@server # kdb5_util destroy
root@server # rm /var/lib/krb5kdc/.k5.LAN
root@server # rm /etc/krb5.keytab
Dans l’ordre j’ai :
- supprimé les tickets en cache
- stoppé tous les démons
- supprimé la base de donnée du KDC
- supprimé le fichier stash contenant la clé de la base
- supprimé le fichier keytab
- j’aurai aussi pu supprimer les clés qu’il contient via
kadminmais avecrmje suis sûr de mon coup ;-)
- j’aurai aussi pu supprimer les clés qu’il contient via
Sur le client :
root@laptop # kdestroy
root@laptop # rm /etc/krb5.keytab
Commandes
kadminpermet d’administrer le KDC-pspécifie un principal d’administration?une fois dans l’interface, permet d’obtenir la liste des commandes
kinitdemande un TGT-pspécifie un principal-kne demande pas de clé (mot passe) à l’utilisateur mais va directement la chercher dans le keytab
klistpermet de lister les tickets de l’utilisateur courant-kpermet de lister les clé du keytab de la machine-eaffiche l’algorithme de chiffrement à coté que chaque ticket et clé-cpermet de spécifié le fichier de cache contenant les tickets
kdestroysupprime les tickets du cache (ou supprime le cache… le résultat est le même)-A??-cpermet de spécifié le fichier de cache contenant les tickets
Résumé :
max@laptop % ls /tmp/krb5cc*
max@laptop % mount /mnt/server
max@laptop % ls /tmp/krb5cc*
/tmp/krb5ccmachine_LAN
max@laptop % sudo klist -c /tmp/krb5ccmachine_LAN
Ticket cache: FILE:/tmp/krb5ccmachine_LAN
Default principal: nfs/laptop.lan@LAN
Valid starting Expires Service principal
31/01/2016 19:01:13 01/02/2016 19:01:13 krbtgt/LAN@LAN
31/01/2016 19:01:13 01/02/2016 19:01:13 nfs/server.lan@LAN
max@laptop % ls /mnt/server
… FAIL …
max@laptop % kinit
Password for max@LAN:
max@laptop % ls /tmp/krb5cc*
/tmp/krb5cc_1000 /tmp/krb5ccmachine_LAN
max@laptop % klist
Ticket cache: FILE:/tmp/krb5cc_1000
Default principal: max@LAN
Valid starting Expires Service principal
31/01/2016 20:13:55 01/02/2016 20:13:55 krbtgt/LAN@LAN
max@laptop % ls /mnt/server
… OK …
TODO
Normalement les client kerberos font des résolutions DNS forward & inverse (pour avoir le nom canonique CNAME de la machine). Pourtant, après avoir supprimé les entrées correspondant au DNS inverse de mon serveur DNS, kerberos fonctionne toujours parfaitement.
Je suppose que la résolution DNS inverse n’est effectué que si le forward DNS trouve un CNAME. Dans mon installation interne je n’utilise pas de CNAME.
Il faudrait que je vérifie ça dans le code source.