Mise en oeuvre de Kerberos

Cette série d'article présentera l'ensemble des opérations nécessaire à la mise en oeuvre d'un serveur de ticket Kerberos (KDC) ainsi que quelques exemples d'utilisaiton, notamment pour OpenSSH, et dans un futur proche, comme base d'authentification d'un serveur NFS avec la version 4 du protocole.

Rédacteurs
Les personnes suivantes ont contribuées à la réalisation de cette série d'article :

1 - Installation du serveur de ticket KDC

Cet article présente en détails les opérations nécessaires à la mise en place d'un serveur de ticket KerberosV (krb5kdc) ainsi que le programme nécessaire à l'administration distance (kadmind), permettant aux administrateur de gérer les différentes identités (principal selon la terminologie kerberos).

Points à garder en tête avant de mettre en place une archi kerberos:

Pour prévenir ces problèmes nous avons en interne un paquet debian contenant toutes les confs et un scripts chargés d'effectuer les tests 'pré vol'. Extrait de la version pour debian/sarge:

echo "Fichier /etc/hosts"
/bin/cp /etc/hosts $BACKUPS/hosts
sed -ie 's/^127.0.0.1.*$/127.0.0.1       localhost localhost.localdomain/' /etc/hosts

echo "First some Kerberbos/DNS sanity checks ..."
HOST=${HOST:-`hostname -f`}
INA=`$DIG $HOST`
PTR=`$DIG -x $INA`

if [ "$PTR" != "$HOST." ];
   then
       echo "[ERROR] Dns isn't setup correctly. Unable to proceed:"
       echo " $HOST IN A give $INA "
       echo " $INA  PTR  give $PTR "
       exit 10
fi

echo "Verification date"
NTP_INIT=ntp
if [ -x /etc/init.d/ntp-server ]; then
   NTP_INIT=ntp-server
fi
invoke-rc.d $NTP_INIT stop

/usr/sbin/ntpdate pool.ntp.org
sed -i -e 's/#server/server/g' /etc/ntp.conf
invoke-rc.d $NTP_INIT start

Bon revenons à nos moutons, va falloir s'y mettre à se foutu KDC.

Il faut tout d'abord configurer le fichier kdc.conf (debian: /etc/krb5kdc/kdc.conf) pour ajouter notre nouveau realm, exemple:

SYSADMIN.NET = {
                database_name = /var/lib/krb5kdc/sysadmin
                admin_keytab = FILE:/etc/krb5kdc/kadm5.keytab
                acl_file = /etc/krb5kdc/kadm5.acl
                key_stash_file = /etc/krb5kdc/stash-sysadmin
                kdc_ports = 750,88
                max_life = 10h 0m 0s
                max_renewable_life = 7d 0h 0m 0s
                master_key_type = des3-hmac-sha1
                supported_enctypes = des3-hmac-sha1:normal des-cbc-crc:normal des:normal des:v4 des:norealm des:onlyrealm des:afs3
                default_principal_flags = +preauth
        }

Qu'a ton fait ici ?

dans l'ordre:

  1. On définit un emplacement de stockage de la base de mots de passes (database_name)
  2. L'emplacement de la keytab d'admin (admin_keytab, cf man kadmind) qui contient les entrées kadmin/admin et kadmin/changepw pour le domaine
  3. Une liste d'acl gérant l'accès à l'interface d'admin
  4. L'emplacement de la clef de cryptage (key_stash_file) qui protège la base (super sensible)
  5. Les ports d'écoutes
  6. La durée de vie maximum d'un ticket,
  7. La durée de vie maximum d'un ticket renouvelé
  8. le format de la master_key
  9. Une liste de format de cryptage actifs sur le domaine et des salts associés.
  10. Enfin nous rajoutons le flag preauth aux comptes kerberos, cette fonction permet de limiter les possiblitées de brute-force offline des comptes kerberos.

Maintenant il faut s'occuper de la création de la base

Executons la commande suivante, en root: kdb5_util -r SYSADMIN.NET create -s

PS: L'outil va demander un mot de passe utilisé pour sécuriser la base, ce mot de passe ne sert quasiment jamais (notez quand même que l'oublier peut-être une mauvaise idée), donc utilisez un truc très long alacon(tm)(c).

Reste à spécifier qui aura le droit d'effectuer des opérations admin sur le realm, cela se gère via le fichier d'acl dont nous avons déjà parlé.

Ex: pour autoriser les principaux de la forme nom/admin@SYSADMIN.NET à effectuer toute type d'opération: */admin@SYSADMIN.NET *

Si l'on veut que untel puisse seulement lire la base: untel@SYSADMIN.NET il

Liste des droits possibles:

Note: Chaque privilège est annulable en utilisant la majuscule associée (a <> A, etc)

Dernière chose (et pas des moindres): la création du premier compte d'admin. En l'état actuel on ne peut pas utiliser l'outil 'normal' (kadmin) car le démon n'est pas lancé et il serait difficile de s'authentifier de toute façons. Il faut donc utiliser une version spéciale de kadmin, j'ai nommé kadmin.local permettant de passer outre les acl et le serveur d'admin:
kadmin.local -q "addprinc username/admin"


Configuration client:

Reste à configurer le fichier /etc/krb5.conf pour pouvoir faire des tests en local:

[libdefaults]
# parametres par défaults:
        default_realm = SYSADMIN.NET
        kdc_timesync = 1
        ccache_type = 4
        forwardable = true
        proxiable = true
#
[realms]
# associations des serveurs / realms
SYSADMIN.NET = {
        kdc = kdc1.sysadmin.net
        #kdc = kdc2.sysadmin.net
        admin_server = kdc1.sysadmin.net
}
#
[domain_realm]
# liaison nom de domaines / realm
        sysadmin.net = SYSADMIN.NET
        asyd.net   = SYSADMIN.NET
#
[logging]
        kdc = SYSLOG:INFO:DAEMON
        admin_server = SYSLOG:INFO:DAEMON
        default = SYSLOG:INFO:DAEMON

Ca y est vous devriez pouvoir aisément vous authentifier auprès du serveur kerberos local en utilisant la commande kinit et vérifier le résultat en utilisant klist.

TODO: la dernière version de MIT Kerberos (1.6) semble pouvoir utiliser un openldap pour stocker la base de principal .. a fouiller: Configuring Kerberos with OpenLDAP back-end. Permet d'utiliser la replication ldap pour synchroniser les kdc
Fichier attachéTaille
setup-kerberos.sh3.42 Ko

2 - Installation d'un serveur de ticket esclave

Cet article présente les étapes permettant la création d'un KDC secondaire.

Installation d'un KDC secondaire

Pré-requis

Installation

A la debian's way:
aptitude install krb5-kdc

Il peut être intéressant de modifier la configuration de kerberos
pour définir la destination des messages de log du kdc. Pour cela éditez
le fichier /etc/krb5.conf, et rajoutez/modifiez la section logging:

...  ..
[logging]
        kdc = FILE:/var/log/kdc.log
        kdc = SYSLOG:INFO:DAEMON
....

Il faut ensuite ajouter une identité pour ce nouveau serveur dans notre base kerberos:
kadmin: addprinc -randkey host/kdc2.sysadmin.net
Principal "host/kdc2.sysadmin.net@SYSADMIN.NET" created.

Ce n'est pas le tout, il va falloir faire en sorte que notre serveur secondaire soit synchronisé avec le kdc primaire, sinon je vous dit pas la prise de tête...

Cela ce fait au travers d'un protocol dédié, implémenté par les outils kprop et kpropd. (Au moins pour MIT-Kerberos).

Aucune configuration automatique n'existe pour cela actuellement sous debian, il faut tout d'abord rajouter une ligne à la configuration (x)inetd pour prendre en charge le service krb5_prop.

Exemple:

krb5_prop       stream  tcp     nowait  root    /usr/sbin/kpropd krpopd

Ensuite il faut autoriser le kdc primaire à faire des mises à jours de la base. Pour cela inserez son principal dans le fichier /etc/krb5kdc/kpropd.acl sur l'esclave.
Exemple:

host/kdc1.sysadmin.net@SYSADMIN.NET

Initialisation du fichier /etc/krb5kdc/stash

Ce fichier critique contient une version cryptée du mot de passe de la base d'admin kerberos. Il permet l'échange et le decodage des bases d'identitées.

Deux méthodes sont utilisables, la première est la plus "propre", mise en place à l'époque de telnet & co, elle recrée la base en local et évite l'interception de donnée sensible, toutefois elle à l'inconvenient de vous demander la fameuse "master key" très complexe et très cachée.
L'initialisation se fait dans ce cas via kdb5_util stash -f /etc/krb5kdc/stash.

L'autre option, pour les feignasses que nous sommes est tout simplement de copier via SSH ou autre protocole sécurisé le fichier disponible sur votre kdc primaire ou un autre esclave.

Import initial

Il nous faut maintenant remplir notre base esclave avec toutes nos données disponibles sur notre KDC primaire, pour cela on executera depuis le serveur primaire les commandes suivantes:

kdb5_util dump /var/lib/krb5kdc/slave_datatrans
kprop -f /var/lib/krb5kdc/slave_datatrans kdc1.sysadmin.net

PS : Il peut arriver que cette opération ne fonctionne pas, notamment sur debian il m'est arrivé plusieurs fois de devoir copier avec SSH la base du serveur primaire pour pouvoir lancer la synchronisation (FIXME a vérifier...)

Mise en place d'une synchronisation régulière

La mise à jour des bases des kdc secondaires passe par une execution régulière des deux commandes précédentes (dump de la base puis propagation).
Une fois encore il n'existe aucun outil tout prêt pour cette opération, j'ai par exemple utilisé un script shell assez simple qui se charge de comparer l'état actuel de la base avec l'état précédent et si nécessaire de propager la nouvelle base à la liste des kdc secondaires définis.

Des améliorations sont envisageables (ex: utilisation entrées DNS SRV pour obtenir la liste des secondaires) mais ça marche:

#!/bin/sh
PATH=/usr/bin:/usr/sbin

kdclist="kdc2.sysadmin.net. kdc3.sysadmin.net."

[ -f /var/lib/krb5kdc/slave_datatrans ] && /bin/cp /var/lib/krb5kdc/slave_datatrans /var/lib/krb5kdc/slave_datatrans.old

kdb5_util dump /var/lib/krb5kdc/slave_datatrans

TMP=`/bin/mktemp`
diff --brief /var/lib/krb5kdc/slave_datatrans /var/lib/krb5kdc/slave_datatrans.old >$TMP

if [ -s $TMP ]; then
# replication uniquement si modifications
for kdc in $kdclist
do
        kprop -f /var/lib/krb5kdc/slave_datatrans $kdc
done

fi

/bin/rm $TMP

Il suffit ensuite de rajouter ce script dans une crontab root (important, pour pouvoir dumper la base
kerberos). Exemple:

5 */6 * * * root /usr/local/sbin/kdc_synch.sh &>/dev/null

Fichier attachéTaille
kdc_synch.sh558 octets

3 - Configuration DNS pour Kerberos

Présentation des diverses configuration DNS possibles pour faciliter le déploiement de kerberos.

Deux types d'enregistrement DNS sont utilisés par kerberos (MIT Kerberos 5) pour faciliter le déploiement de kerberos sur les postes clients.

Enregistrement SRV

Le premier (et le plus important) est l'enregistrement SRV, il permet de définir les différents serveurs kerberos disponibles sur une zone.

Kerberos défini plusieurs services configurables: kerberos, kpasswd, kerberos-adm et kerberos-master. Le premier étant le plus important car il permet d'obtenir la liste des contrôleurs de domaines disponibles.

Service Protocole Port Description Exemple
kerberos udp 88 Adresse d'un KDC _kerberos._udp IN SRV 0 0 88 kdc2.sysadmin.net.
kpasswd udp 464 Adresse d'un serveur d'administration kerberos, service de changement de mot de passes _kpasswd._udp IN SRV 0 0 464 kdc1.sysadmin.net.
kerberos-adm tcp 749 Adresse d'un serveur d'administration kerberos, service d'administration. _kerberos-adm._tcp IN SRV 0 0 749 kdc1.sysadmin.net.
kerberos-master udp 88 Adresse du KDC primaire, ou plus précisement le/les kdc directement impactés par un changement de mot de passe. Utilisé par les clients pour lors de la saisie d'un mot de passe incorrect pour valider que ce n'est pas un problème de propagation. _kerberos-master._udp IN SRV 0 0 88 kdc1.sysadmin.net.

Enregistrement TXT

Remplace les affectations de la section domain_realm du fichier /etc/krb5.conf.

Service Description Exemple
kerberos Associe un REALM kerberos avec le domaine dns. _kerberos.asyd.net. IN TXT "SYSADMIN.NET".

4 - Authentification HTTP par ticket Kerberos

Maintenant que nous disposons de notre serveur de tickets, il est désormais intéressant de se pencher sur les utilisations possibles - point de vue utilisateur. Cet article présente comment utiliser un ticket kerberos pour s'authentifier auprès d'un site web servi par apache.

Configuration Serveur

Pour cela nous aurons besoin du libapache2-mod-auth-kerb et d'un principal en HTTP/nom.de.machine@REALM

Configuration apache2:


AuthName "Secure Access"
AuthType Kerberos
Krb5Keytab /etc/apache2/krb5.keytab
KrbMethodK5Passwd off
KrbSaveCredentials on
require valid-user

Et stocker le principal dans un fichier spécifique accessible par le serveur web:
kadmin: ktadd -k /etc/apache2/krb5.keytab HTTP/fqdn@REALM

Configuration Client

Pour l'instant seul firefox est à même (a ma connaissance) de transférer un ticket MIT-Kerberos sous windows et sous linux via le Negotiate Auth de HTTP. Il faut toutefois le configurer pour autoriser ce comportement, via la préférence network.negotiate-auth.trusted-uris (exemple de valeur: https://,asyd.net,sysadmin.net).

Sous windows (2000 et +) il faut en plus rajouter une préférence de type booléenne network.auth.use-sspi et la configurer
à false, sinon il utilise les fonctions d'active directory et cela ne passe pas.

Note: Les dernières releases de kerberos for windows (3.2.x) s'intègrant de mieux en mieux au système de sécurité de MS(c), ce besoin disparaîtra peut-être à terme.

5 - Kerberos & OpenLDAP

Comment s'identifier sur un annuaire OpenLDAP a partir d'une base Kerberos ?

Identification par ticket Kerberos

OpenLDAP gère le standard SASL qui va nous permettre de faire transiter nos tickets kerberos jusqu'a l'annuaire.

Pré-requis

Sur le serveur de l'annuaire et sur les clients les packages suivant seront nécessaires:

libsasl2-2
libsasl2-modules
libsasl2-modules-gssapi-mit

Configuration

## Configuration SASL (kerberos)

# Nom du REALM:
sasl-realm      ASYD.NET
# Nom du serveur local:
sasl-host       ldap.asyd.net
# Conversion des user Kerberos en UID ldap
#  deux possibilitées: 1/ une configuration user 'a plat' (tout dans une branch ou=users,dc=...,dc=...)
#    il suffit de mapper les nom via la regexp
sasl-regexp "^uid=([^,]+),cn=gssapi,cn=auth" "uid=$1,ou=Users,dc=asyd,dc=net"
#   2/ une config plus eclatée
#      dans ce cas il faut utiliser la regexp pour generer une recherche:
sasl-regexp     "^uid=([^,]+),cn=asyd.net,cn=gssapi,cn=auth" ldap:///dc=asyd,dc=net??sub?(uid=$1)

## This is a bit of a hack to restrict the SASL mechanisms that the
## server advertises to just GSSAPI.  Otherwise it also advertises
## DIGEST-MD5, which the clients prefer.  Then you have to add "-Y
## GSSAPI" to all of your ldapsearch/ldapmodify/etc. command lines, which
## is annoying.  The default for this is noanonymous,noplain so the
## addition of noactive is what makes DIGEST-MD5 and the others go away.
sasl-secprops noanonymous,noplain,noactive

Keytab

Il vous faudra aussi un keytab special pour l'annuaire avec un principal de la forme ldap/ldap.asyd.net@ASYD.NET. Personnellement je l'ai stocker a part dans /etc/ldap/krb/ldap.keytab et j'ai modifier /etc/default/slapd pour y ajouter export KRB5_KTNAME=/etc/ldap/krb/ldap.keytab

Identification par les mot de passes Kerberos (bind "simple")

Il est aussi possible de s'identifier en utilisant le mot de passe kerberos si la configuration cliente ne permet pas l'obtention d'un ticket.

Deux solutions pour cela, la premiere via un module pour openldap, la seconde via une extension de la configuration SASL.

Le module OpenLDAP

Pour cela vous aurez besoin des sources d'openldap, en effet dans le dossier "contrib/slapd-modules/passwd" il existe trois modules optionnel pour gérer des mécanismes de password supplémentares : Kerberos, Radius et "Netscape MTA-MD5".

Celui qui nous intéresse étant le premier, il faut le compiler par (attention, ne pas utiliser la syntaxe fournie dans le README, le module ne se chargera pas):

gcc -shared -I../../../include -Wall -lkrb5 -g -DHAVE_KRB5 -fPIC -o pw-kerberos.so kerberos.c

puis le copier dans /usr/lib/ldap/

(debian): cp pw-kerberos.so /usr/lib/ldap/

Dernière étape, il faut veiller a ce que les UserPassword soient stockés en clair dans l'annuaire, au format {kerberos}asyd@ASYD.NET.

Via SASL

Il semblerait qu'une autre solution existe pour ça via le demon saslauthd:

OpenLDAP With saslauthd

Attention dans ce cas il est probable que la configuration sasl faite dans la premiere partie soit incompatible:

## This is a bit of a hack to restrict the SASL mechanisms that the
## server advertises to just GSSAPI.  Otherwise it also advertises
## DIGEST-MD5, which the clients prefer.  Then you have to add "-Y
## GSSAPI" to all of your ldapsearch/ldapmodify/etc. command lines, which
## is annoying.  The default for this is noanonymous,noplain so the
## addition of noactive is what makes DIGEST-MD5 and the others go away.
sasl-secprops noanonymous,noplain,noactive