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 :
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:
127.0.0.1 localhost nom.de.domaine nom
1.1.1.1 nom.de.domaine nom
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
}
dans l'ordre:
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"
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.sh | 3.42 Ko |
Cet article présente les étapes permettant la création d'un KDC secondaire.
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
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.
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...)
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.sh | 558 octets |
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.
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. |
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". |
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.
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
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.
Comment s'identifier sur un annuaire OpenLDAP a partir d'une base Kerberos ?
OpenLDAP gère le standard SASL qui va nous permettre de faire transiter nos tickets kerberos jusqu'a l'annuaire.
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 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
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
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.
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.
Il semblerait qu'une autre solution existe pour ça via le demon 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