jeudi, décembre 26, 2024
Nom d'utilisateur : Mot de passe :
[NEWS]
Envoyé par unreal
Le but de ce dossier est d'expliquer comment réaliser une authentification forte de type SSO 'Single Sign-On' d'une application Web hébergée en réseau local sur un serveur Linux avec Apache via un Kerberos sous Windows 2003 Server. Les clients seront des machines Windows ou Linux participant au domaine AD (Active Directory) utilisant un navigateur compatible Negotiate.

On peut résumer le fonctionnement de la manière suivante : un utilisateur ouvre une session sur le domaine et navigue vers une page http protégée du réseau Intranet. Habituellement, on affiche une boite invitant l'utilisateur à saisir son nom d'utilisateur et mot de passe alors qu'il est déjà connu de l'AD, vu qu'il a saisi les mêmes informations pour se connecter à son compte Windows. Le but du Single Sign-On est d'authentifier l'utilisateur sans qu'il soit obligé de resaisir plusieurs fois les mêmes informations.


Comment ça marche

Kerberos fonctionne avec un système de jetons, qu'on appelera des 'tickets'. L'authentification se passe en plusieurs étapes :

kerb_schema.png


1 : le poste client demande un ticket au serveur Kerberos (ici le DC Win2003)
2 : le KDC retourne un ticket, vu que le client est déjà identifié sur le réseau
3 : le poste client formule la requête au serveur Web en incluant le ticket

Plusieurs avantages de cette méthode :
  • L'utilisateur s'identifie une seule fois et peut ensuite accéder de façon transparente aux différents services
  • Le nom d'utilisateur et son mot de passe ne sont jamais transmis sur le réseau



Prérequis et nominations

Dans la suite de l'article, je vais supposer que vous avez les éléments suivants :

  • Un 2003 Server configuré en contrôleur de domaine avec le service DNS activé, et au moins un compte utilisateur (dc-1.local.domain)
  • Un serveur Linux avec Apache configuré, capable de servir des pages (lx-1.local.domain)
  • Un client XP ou 2003 enregistré sur le domaine, capable d'ouvrir une session avec un compte du domaine (pc-1.local.domain)


Kerberos étant particulièrement sensible aux noms des machines, il est important que toutes les machines apparaissent dans le serveur DNS et qu'elles aient toutes une entrée PTR (reverse DNS) égale au forward DNS (A). Pour cela, je vous conseille donc d'utiliser le service DNS du 2003 Server.

Exemple de configuration du forward DNS :

dns_setup.png


Exemple de configuration du reverse DNS :

rdns_setup.png


En plus d'être sensible à la nomination, Kerberos est sensible à un quelconque décalage temporel entre les différentes machines. Pour palier à ce problème, je vous conseille donc d'utiliser un service NTP.

Pour finir, il faut choisir un realm Kerberos, par exemple LOCAL.DOMAIN. Notez que le realm s'écrit tout en majuscules.


Configuration du 2003

Pour chaque service à Kerberosiser, les opération suivantes sont à prévoir pour générer un Service Principal :

- Création d'un compte utilisateur pour chaque service. Je vous conseille de choisir un nom qui permette d'identifier le service concerné, par exemple intranet-1. Pour ce faire, rendez-vous dans Active Directory Users and Computers, faites clic-droit, puis New -> User.

Attention : ne pas choisir un nom d'utilisateur qui existe déjà comme nom de contrôleur de domaine ou comme nom d'ordinateur.

- Génération d'un KeyTab. Ce fichier sert à authentifier le serveur Kerberosisé (ici le serveur Web) auprès du KDC. Ce fichier se génère à la ligne de commande après installation des support tools :

ktpass -princ HTTP/lx-1.local.domain@LOCAL.DOMAIN -crypto DES-CBC-MD5 -ptype KRB5_NT_PRINCIPAL -mapuser intranet-1 -pass azerty -out C:\temp\keytab.txt


En version graphique cela donne :

keytab_gen.png
Génération du keytab : vérifiez qu'il n'y a pas d'erreur !


Copiez le fichier généré via sftp/scp sur le serveur Linux dans /etc/krb5.keytab


Configuration du serveur Linux

Commencez par sécuriser le keytab copié précedemment :

# chown www-data:root /etc/krb5.keytab
# chmod 640 /etc/krb5.keytab


Configurez les DNS :

# echo -e "search local.domain\nnameserver 192.168.22.1" > /etc/resolv.conf


Dans cet exemple, j'utilise une machine en Debian Lenny, l'installation des packages se fait donc avec apt :

# apt-get install krb5-clients krb5-config krb5-user libkrb53 libapache2-mod-auth-kerb


Vérifiez que modauthkerb est activé :

# cat /etc/apache2/mods-enabled/auth_kerb.load
LoadModule auth_kerb_module /usr/lib/apache2/modules/mod_auth_kerb.so


Créez un .htaccess ou éditez apache2.conf pour sécuriser le site :

<Files "*">
        <Limit GET POST>
                AuthName "Kerberos Login"
                AuthType Kerberos
                Krb5Keytab /etc/krb5.keytab
                KrbAuthRealms LOCAL.DOMAIN
                KrbMethodNegotiate On
                KrbMethodK5Passwd Off
                KrbVerifyKDC off
                Require valid-user
        </Limit>
</Files>


Je rappelle que le realm s'écrit en majuscule. Dans cet exemple, on active le mode SSO via Negotiate et on désactive l'authentification par mot de passe ; si l'authentification automatique est impossible une page d'erreur 401 Authorization Required s'affichera.

Le dernier fichier à configurer est /etc/krb5.conf ; Lenny a du installer un fichier par défaut, je vous conseille de le renommer :

# mv /etc/krb5.conf /etc/krb5.conf.dist


Ensuite éditez krb5.conf :

[libdefaults]
        ticket_lifetime = 24000
        default_realm = LOCAL.DOMAIN
        dns_lookup_realm = true
        dns_lookup_kdc = false
        default_keytab_name = FILE:/etc/krb5.keytab

[realms]
        LOCAL.DOMAIN = {
                kdc = dc-1.local.domain
                admin_server = dc-1.local.domain
}

[domain_realm]
        .local.domain = LOCAL.DOMAIN
        local.domain = LOCAL.DOMAIN

[appdefaults]
        pam = {
                debug = false
                ticket_lifetime = 36000
                renew_lifetime = 36000
                forwardable = true
                krb4_convert = false
        }



Vérifications

A ce stage, vous avez normalement une configuration fonctionnelle. Nous allons cependant effectuer quelques vérifications parce qu'il existe beaucoup d'erreurs de configuration possibles.

- Test de connexion :

# kinit <nom d'utilisateur>@LOCAL.DOMAIN


Saisissez le mot de passe de l'utilisateur, il ne doit pas avoir d'erreur.

La commande klist permet de vérifier l'état des tickets :

# klist
Ticket cache: FILE:/tmp/krb5cc_0
Default principal: <nom d'utilisateur>@LOCAL.DOMAIN

Valid starting     Expires            Service principal
08/12/09 11:42:08 08/12/09 18:22:08 krbtgt/LOCAL.DOMAIN@LOCAL.DOMAIN


Kerberos 4 ticket cache: /tmp/tkt0
klist: You have no tickets cached


- Si tout va bien, vérifiez ensuite votre authentification de service :

# kvno HTTP/lx-1.local.domain@LOCAL.DOMAIN
HTTP/lx-1.local.domain@LOCAL.DOMAIN: kvno = 28


Il ne doit pas avoir d'erreur non plus mais voici quelques messages d'erreurs classiques et leur signification :

kvno: No credentials cache found while getting client principal name

Vous n'avez pas de ticket valide : lancez la commande kinit <nom d'utilisateur>


kvno: Server not found in Kerberos database while getting credentials for HTTP/lx-1.local.domain@LOCAL.DOMAIN

Plusieurs possibilités ici :

  • Vous avez mal généré votre keytab ; essayez de le regénérer
  • Vous avez affecté le même SPN à plusieurs utilisateurs (voir les pièges)


- Pour finir, ce test de keytab ne doit pas retourner d'erreur :

# kinit -k -t /etc/krb5.keytab HTTP/lx-1.local.domain@LOCAL.DOMAIN


Attention !
Ne passez pas à la suite tant que les trois tests précédents génèrent des erreurs !


Configuration du poste client

Nous allons configurer IE6 et Firefox 3.5 pour accéder au service Web sécurisé :

Internet Explorer 6.0

Ouvrez Internet Options et accédez à l'onglet Advanced et vérifiez que l'Authentification Windows est activée :

ie6_options.png


Ensuite ajoutez le site sécurisé dans la zone Local intranet :

ie6_intranet.png


Acceptez les changements, et naviguez sur http://lx-1.local.domain : le site s'affiche sans authentification par mot de passe.

Firefox 3.5

Lancez Firefox et tapez about:config dans la barre d'adresse, puis filtrez avec le mot auth. Modifiez network.negotiate-auth.trusted-uris et network.negotiate-auth.delegation-uris avec le domaine local.domain :

ff35_options.png



Pièges à éviter

Ce paragraphe vous permettra d'éviter ou de corriger des soucis.

Noms de machines

Il est important de bien définir les noms des machines en utilisant un FQDN avant de commencer. Les entrées DNS doivent être présentes, aussi bien en forward qu'en reverse.

Le realm

Il n'est pas obligatoirement le nom de domaine, et il peut avoir plusieurs realms sur un réseau ayant un seul domaine. Par contre, le realm s'écrit en majuscules, par exemple LOCAL.DOMAIN.

Nom de service sur plusieurs comptes

Si vous avez créé plusieurs comptes pour expérimenter, il n'est pas impossible qu'un même nom de service ou SPN se retrouve associé à plusieurs comptes, ce qui n'est pas possible. Un compte doit être unique pour chaque service Kerberosisé (intranet-1, intranet-2...) et un même nom de service (HTTP/lx-1.local.domain@LOCAL.DOMAIN) ne peut être associé à plusieurs comptes. Si vous avez utilisé ktpass pour associer le même SPN à plusieurs compte, utilisez setspn pour corriger :

C:\Program Files\Support Tools>setspn
Usage: setspn [switches data] computername
Where "computername" can be the name or domain\name

Switches:
-R = reset HOST ServicePrincipalName
    Usage: setspn -R computername
-A = add arbitrary SPN
    Usage: setspn -A SPN computername
-D = delete arbitrary SPN
    Usage: setspn -D SPN computername
-L = list registered SPNs
    Usage: setspn [-L] computername
Examples:
setspn -R daserver1
It will register SPN "HOST/daserver1" and "HOST/{DNS of daserver1}"
setspn -A http/daserver daserver1
It will register SPN "http/daserver" for computer "daserver1"
setspn -D http/daserver daserver1
It will delete SPN "http/daserver" for computer "daserver1"


Pour lister les SPN associés a un utilisateur, utilisez l'option "-L", pour supprimer, utilisez l'option "-D", par exemple :

setspn -D HTTP/lx-1.local.domain lx-1


Choix du nom d'utilisateur

Le nom d'utilisateur est libre, par contre, le nom ne doit pas déjà utilisé comme nom d'ordinateur ou comme contrôleur de domaine.

Versions
- v1.0 - 12/08/2009

Posté le 11/08/09 à 20:50 - 0 Commentaires...

[NEWS]
Envoyé par unreal
Si vous regardez vos logs SSH de temps en temps, vous avez sans doute constaté des milliers d'IP qui tentent de se logger sur le serveur. Ils auront peu de chance de se connecter pour peu que les mots de passe soient sûrs, mais si vous hébergez des clients ou des amis, comment protéger leurs comptes, et le serveur par la même occasion ?

Décidément PF offre une solution très élégante à ce problème par le bias du firewall Packet Filter qui dispose d'options de détection de fréquence de connexions.

Passons directement dans le vif du sujet avec un exemple sous FreeBSD 7.2.

On commence par activer PF dans rc.conf :

# Firewall
pf_enable="YES"                 # Enable PF (load module if required)
pf_rules="/etc/pf.conf"         # rules definition file for pf
pf_flags=""                     # additional flags for pfctl startup
pflog_enable="YES"             # start pflogd(8)
pflog_logfile="/var/log/pflog" # where pflogd should store the logfile
pflog_flags=""                 # additional flags for pflogd startup


Ensuite, on crée un fichier de configuration qui s'appelle donc /etc/pf.conf :

#################################################################
# Interface definitions
ethif0 = "em0"
ethif1 = "em1"
loopback_if = "lo0"

# Set options
set limit states 100000
set skip on lo0
#################################################################


scrub in on $ethif0 all
scrub in on $ethif1 all

# SSH bruteforce protection.
block drop in quick on { $ethif0, $ethif1 } from <ssh-bruteforce> (1)
pass in on { $ethif0, $ethif1 } proto tcp from any to any port ssh flags S/SA keep state (max-src-conn-rate 3/120, overload <ssh-bruteforce> flush global) (2)

# HTTP flood protection.
block drop in quick on $ethif0 proto tcp from <http-antiflood> to any port 80 (3)
pass in on $ethif0 proto tcp from any to any port http flags S/SA keep state (max-src-conn 100, max-src-conn-rate 50/10, overload <http-antiflood> flush global) (4)


Quelques explications s'imposent ici. La ligne 2 active la suivie d'état sur les interfaces en0 et en1 vers le service ssh. Quand une même IP source dépasse 3 nouvelles connexions dans une fenêtre de 120 secondes, PF rajoute automatiquement cette IP dans la table ssh-bruteforce. La ligne 1 sert alors de bloquer tous les paquets en provenance de cette la table ssh-bruteforce, qu'elles viennent de l'interface en0 ou en1.

On offre une protection similiaire pour le service HTTP (lignes 3 et 4) avec les paramètres suivants :

- 50 connexions par plage de 10 secondes
- 100 connexions max par IP source

Si un client dépasse ses limites, son IP sera bloquée.

Comme les tables ne sont jamais vidées (sauf redémarrage du service pf), il faut purger via un crontab :

# PF bruteforce reset
*/5 * * * *            /sbin/pfctl -t ssh-bruteforce -T expire 3600 2>/dev/null
*/5 * * * *            /sbin/pfctl -t http-antiflood -T expire 600 2>/dev/null


On débloque donc les connexions au bout d'une heure (ssh) et 10 mintes (http).

Pour démarrer pf, il suffit enfin de lancer le son script rc :

/etc/rc.d/pf start


La commande pfctl permet de surveiller les IP bloquées :

pfctl -t <nom de table> -vTshow


En pratique, on peut écrire un petit script shell pour surveiller d'un coup toutes les tables :

#!/usr/local/bin/bash


TABLES=`pfctl -s Tables 2>/dev/null`

for ONETABLE in $TABLES; do

        echo " -- $ONETABLE --"
        echo
        pfctl -t $ONETABLE -vTshow 2>/dev/null
        echo

done


Et pour finir, un exemple d'affichage du script ci-dessus :

# ./showtables.sh
-- http-antiflood --


-- ssh-bruteforce --

202.108.103.2
        Cleared:     Fri May 15 09:30:20 2009
        In/Block:    [ Packets: 8                 Bytes: 428                ]
        In/Pass:     [ Packets: 0                 Bytes: 0                 ]
        Out/Block: [ Packets: 0                 Bytes: 0                 ]
        Out/Pass:    [ Packets: 0                 Bytes: 0                 ]


Si vous avez des questions, n'hésitez pas à laisser un commentaire !

Posté le 14/05/09 à 19:53 - 0 Commentaires...

[NEWS]
Envoyé par unreal
Introduction

PF ou Packet Filter est le firewall développé par OpenBSD, puis porté vers divers systèmes d'exploitation, dont FreeBSD.
Comme OpenBSD peut souffrir de problèmes de performances en firewall à forte charge, nous allons étudier dans cet article le remplacement d'un firewall/forwarder de paquets sous OpenBSD par un système FreeBSD pour voir l'éventuel gain de performance que cela peut amener.


Configuration

Matérielle :
  • Athlon XP 1800+
  • 1Go de ram
  • 2 NIC : Realtek et 3Com

Cette configuration relativement ancienne a été choisie afin de mieux apprécier les différences de performances.

Logicielle :
  • OpenBSD 4.2
  • FreeBSD 7.0 avec scheduler ULE

Les 2 OS ont été compilés avec les optimisations d'usage (-march=athlon-xp...).


Banc de test

L'image suivante montre le plan du réseau :

banctest.png


Les tests de performances se font entre 192.168.100.2 et nas.localdomain ; la gw par défaut étant hell.localdomain, il faut donc ajouter une route sur nas pour assurer le retour des paquets :

# route add -net 192.168.100.0/24 192.168.10.81


On peut vérifier que la route est présente avec netstat :

# netstat -rn | grep 192.168.100.0
192.168.100.0/24 192.168.10.81     UGS         0        0 sis0


Ensuite, pour activer le mode routage (forwarding) sur pffw il convient de jouer avec sysctl :

# sysctl -w net.inet.ip.forwarding=1


(pour que cette configuration résiste au reboot, sous FreeBSD il faut ajouter gateway_enable="YES" dans /etc/rc.conf et sous OpenBSD, il faut décommenter la ligne net.inet.ip.forwarding=1 dans /etc/sysctl.conf.)


Test de routage

Le premier test consistera à faire un transfert FTP de nas à la machine 192.168.100.2 avec pffw configuré en routeur pur. Pendant le transfert, on contrôle plusieurs chose :

  • La vitesse de transfert (9700ko/s dans les 2 cas)
  • La charge CPU de pffw à l'aide de top

Comme la charge est quelque peu variable, j'ai configuré un refresh de top toutes les cinq secondes et fait une moyenne sur 30 mesures consécutives.

Résultats :

  • FreeBSD : 72,3% CPU idle
  • OpenBSD : 65,9% CPU idle

Naturellement, la charge CPU est presque totalement du I/O wait au niveau des interfaces réseau.


Test de firewall + routage

Voici les règles de filtrage :

#################################################################
# Interface definitions

in_if = "xl0"
out_if = "rl0"
loopback_if = "lo0"
table <me> const { $in_if , $out_if, $loopback_if }
set limit states 100000

#################################################################

scrub in on $in_if all
scrub in on $out_if all


# Block all by default
block all

# ICMP.
pass in proto icmp all keep state
pass out proto icmp all keep state

## Host rules ##
pass on $loopback_if all
# FTP.
pass in on $out_if proto tcp from any port 20 to $out_if keep state
pass out on $out_if proto tcp from $out_if to any port > 10000 keep state
# SSH from out_if.
pass in on $out_if proto tcp to $out_if port 22 keep state
# DNS.
pass out on $out_if proto udp from $out_if to any port 53 keep state
# DHCP.
pass out on $out_if proto udp from 0.0.0.0 port 68 to 255.255.255.255 port 67 keep state
# Connexions sortantes.
pass out on $out_if proto tcp from $out_if to any port {21,22,80,443,5999} keep state
## End host rules ##

## Routing rules ##
# in -> out
pass in on $in_if proto tcp from any to ! <me> port {21,22,80,5001} keep state
pass out on $out_if proto tcp from ! <me> to any port {21,22,80,5001} keep state
# out -> in
pass in on $out_if from any to ! <me> keep state
pass out on $in_if proto tcp from ! <me> to any keep state
## End routing rules ##


Il s'agit d'un ruleset assez simple par soucis de lisibilité, cependant, comme vous allez pouvoir le constater, l'ajout du firewall a une influence non négligeable sur les performances.

Transfert FTP avec FW

On reprend donc le test précédent et on ajoute les règles de filtrage.

Résultats :

  • FreeBSD : 65,8% CPU idle
  • OpenBSD : 64,2% CPU idle


Benchmark avec iPerf

Iperf est un outil permettant de mesurer le throughput d'un réseau, il s'agit donc d'un bon test pour contrôler les performances de notre firewall.

  • FreeBSD : 48,9% CPU idle et 90,5Mbit/s de vitesse de transfert
  • OpenBSD : 46,1% CPU idle et 90,2Mbit/s de vitesse de transfert



Conclusion

  • FreeBSD l'emporte niveau I/O et certainement aussi niveau stack IP
  • OpenBSD réduit l'écart quand on active les fonctionnalités de filtrage dans la mesure où FreeBSD 7.0 est livré avec le PF d'OpenBSD 4.1, qui a largement été amélioré pour la 4.2


Il sera certainement intéressant de refaire ces tests quand le dernier PF sera porté sous FreeBSD, mais en attendant la différence de performance est telle qu'on peut prendre l'un ou l'autre selon ses préférences.


Posté le 25/03/08 à 10:30 - 0 Commentaires...

2 pages... [1-5][6-8]