Cluster Amavis

Posté par | content

 

Afin de garantir la continuité, la fiabilité et la performance de nos services, nous allons créer un cluster Amavis à partir d’une distribution Debian Squeeze.

 

2 systèmes Linux (qui assurent le filtrage anti-spam et anti-virus) fournissent le même service en parallèle en permettant la répartition des charges et la redondance en cas de panne.

Article écrit par Michael Britton, responsable exploitation

 Dans un modèle d’architecture « normalisé », il faudrait en toute logique au minimum 4 serveurs :

  • 2 loadbalancers en failover
  • 2 serveurs amavis

Oui mais voilà, mon boss a dit  » 4 serveurs? Trop cher !!! Alors tiens, en voilà 2 ! »

 

Donc nous allons faire cela avec 2 serveurs uniquement (ou plus) ou comment faire 1+1+1+1=2 !

 

Amavis

        • La première étape va être d’installer d’Amavis sur chaque serveur.

Installation : Ici, l’installation des paquets Debian sera nécessaire au bon fonctionnement de Amavis.

aptitude install amavisd-new spamassassin clamav clamav-daemon razor pyzor zoo unzip unarj bzip2 unrar-free p7zip-full arj cabextract ripole nomarch

 

        • Pour faire fonctionner correctement certains plugins, il sera nécessaire d’ouvrir les ports suivant, en sortie :

 

          – 2703 tcp(razor)

 

          – 6277 tcp(dcc)

 

        – 24441 udp(pyzor)

 

        • Pour que Amavis écrive dans un fichier log spécifique (/var/log/amavisd.log par exemple), nous allons modifier rsyslog :

 

vi /etc/rsyslog.conf

 

        • On ajoutera en fin de fichier :

#Local
local0.*                                -/var/log/amavisd.log

 

        • Ensuite, nous crérons la rotation des logs :

 

vi /etc/logrotate.d/rsyslog

 

        • On ajoutera en fin de fichier :

 

/var/log/amavisd.log
{
        rotate 30
        daily
        missingok
        notifempty
}

 

        • Pour valider le tout, nous relancerons rsyslog :

 

/etc/init.d/rsyslog restart

 

        • Il ne reste plus qu’à dire à Amavis d’utiliser les lignes de code suivantes :

 

vi /etc/amavis/conf.d/50-user

 

#LOG
$syslog_ident = ‘amavis';    # syslog ident tag, prepended to all messages
$syslog_facility = ‘local0′;
$syslog_priority = ‘debug';  # switch to info to drop debug output, etc

ClamAV :

        • ClamAV est chargé de détecter les virus.

 

adduser clamav amavis
/etc/init.d/amavis restart
/etc/init.d/clamav-daemon restart

SpamAssassin : SpamAssassin va avoir l’énorme tache de détecter les spams parmi les mails entrants.

        • On activera l’utilisation des modules suivants :

 

vi /etc/spamassassin/local.cf

 

# dcc
use_dcc 1
dcc_path /usr/bin/dccproc #pyzor
use_pyzor 1
pyzor_path /usr/bin/pyzor
pyzor_add_header 1 #razor
use_razor2 1
razor_config /etc/razor/razor-agent.conf #bayes
use_bayes 1
use_bayes_rules 1
bayes_auto_learn 1

DCC :

        • Installation du plugin DCC :

 

cd /tmp
wget http://www.dcc-servers.net/dcc/source/dcc-dccproc.tar.Z
tar xzvf dcc-dccproc.tar.Z
cd dcc-dccproc-1.3.144
./configure –with-uid=amavis
make
make install
chown -R amavis:amavis /var/dcc
ln -s /var/dcc/libexec/dccifd /usr/local/bin/dccifd

Pyzor :

        • Afin d’éviter certains warning, éditons le fichier /usr/bin/pyzor :

#!/usr/bin/python -Wignore::DeprecationWarning import os
# set umask
os.umask(0077) import pyzor.client
pyzor.client.run()

 

        • Le fait de lancer ensuite la commande :

 

pyzor ping

 

        • Va générer les fichiers suivants :

/root/.pyzor/config
/root/.pyzor/servers

 

        • Nous éditons la config :

 

vi /root/.pyzor/config

 

[client]
ServersFile = servers
AccountsFile = accounts
DiscoverServersURL = http://pyzor.sourceforge.net/cgi-bin/inform-servers-0-3-

Razor2 :

        • On endosse l’identité Amavis pour procéder à l’initialisation de Razor :

 

# su amavis
$ razor-admin -create

 

Cette commande a pour effet de créer les fichiers de configuration dans /etc/razor/ et de découvrir la liste des serveurs Razor.
On procède ensuite à l’inscription auprès du réseau Razor.

 

        • L’identité attribuée par les serveurs Razor sera alors stockée dans le fichier /var/lib/amavis/.razor/identity :

 

$ razor-admin -register
$ exit

        • Ensuite, vérifier dans le fichier de configuration de SpamAssassin /etc/spamassassin/v310.pre que le module Razor a bien été chargé :

 

# Razor2 – perform Razor2 message checks.
#
loadplugin Mail::SpamAssassin::Plugin::Razor2

        • Puis, activez les tests distants dans la configuration de Amavis (50-user) :

 

$sa_local_tests_only = 0;

Enfin, modifier au besoin la configuration de Razor /etc/razor/razor-agent.conf

 

        • Nous relancerons Amavis, et nous vérifirons dans les logs la bonne intégration de Razor :

 

Module Razor2::Client::Version xxxx

 

Normalement vos Amavis sont prêts en configuration très basique.
Nous allons passer maintenant au tour de magie !
Pour cela nous allons installer Keepalived.

 

Keepalived

Keepalived va nous permettre d’avoir la redondance des services MAIS AUSSI la répartition de charge.
Il utilise pour cela vrrp et ipvs.

Installation :

        • Installons les paquets nécessaires :

 

aptitude install libssl-dev libpopt-dev libnl1 ipvsadm

 

        • Installons ensuite la dernière version de keepalived :

 

wget http://www.keepalived.org/software/keepalived-1.2.7.tar.gz
tar xzf keepalived-1.2.7.tar.gz
cd keepalived-1.2.7
./configure
make
make install

 

Configuration :

        • Créons maintenant le fichier de configuration :

vi /etc/keepalived/keepalived.conf

 

global_defs {
    # Adresses mail des destinataires.
    notification_email {
        superviseur@platine.com
        monitoring@platine.com
    }
    # Adresse de l’émetteur.
    notification_email_from amavis01@platine.com
    # Adresse IP du serveur mail à utiliser pour l’envoi.
    smtp_server 127.0.0.1
    smtp_connect_timeout 30
    # Nom identifiant la machine (pas forcement son hostname).
    router_id CLUSTER-AMAVIS
}  # Configuration d’une instance VRRP pour l’interface du coté externe,
# connectée au réseau IP Internet.
# Nous utilisons une seule instance dans cet exemple, mais selon vos
# besoins vous pouvez utiliser une autre instance VRRP pour l’interface
# du coté interne, sur le réseau IP coté LAN privé.
vrrp_instance INCOMING {
    # Déclaration de cette machine comme MASTER.
    state MASTER
    # Nom de l’interface qui portera l’ip virtuelle pour cette instance.
    interface eth0
    # Numéro de l’identifiant VRRP (n° arbitraire, commun aux membres de
    # cette instance).
    virtual_router_id 10
    # Priorité pour l’élection entre le MASTER et les autres machines en
# attente (BACKUP).
    priority 100
    # Intervalle de vérification (secondes) de la santé des membres VRRP.
    advert_int 1
    # Permet d’indiquer sur quelle interface effectuer le broadcast vrrp
# Si non spécifié, c’est la même interface que celle portant ip virtuelle (recommandé)

    lvs_sync_daemon_interface eth0
    # Authentification entre les membres de cette instance, doit être le
# même sur tous les membres.

    authentication {
        auth_type PASS
        auth_pass myvrrpdpassword
    }
# Permet d’alerter en cas de changement de de status
smtp_alert

# Actions à effectuer en plus lors du changement d’état de l’instance
    notify_master « /etc/keepalived/rules master »
    notify_backup « /etc/keepalived/rules backup »
    notify_fault « /etc/keepalived/rules fault »
    # Adresses IP virtuelles qui seront activées ou désactivées selon le
    # passage de l’état MASTER à BACKUP. On en utilise qu’une seule ici.
    virtual_ipaddress {
        123.45.67.1/24 brd 123.45.67.255 dev eth0
    }
    # Vous pouvez ajouter ou supprimer des routes selon le changement
# d’état (MASTER/BACKUP)
.
#virtual_routes {

    #    0.0.0.0/0 via 123.45.67.14
    #}
}  # Déclaration d’un serveur virtuel avec l’IP 123.45.67.1 écoutant sur le
# port de Amavis (10024).

virtual_server 123.45.67.1 10024 {
# Intervalle entre chaque vérification de la santé des serveurs
# réels.

    delay_loop 5
    # Algorithme de répartition des requêtes vers les serveurs réels.
    # Voir man ipvsadm (rr|wrr|lc|wlc|lblc|sh|dh).
    lb_algo wlc
    # Techniques de répartition de charge IP (NAT|DR|TUN).
    lb_kind DR
    # Délai de persistance de l’association d’une requête vers un
    # serveur réel.
    # Une valeur (secondes) à zéro, permet d’ignorer cette association.
    # Mettez à zéro pour faire vos tests.
    #persistence_timeout 5
    # Seul le protocole TCP est implémenté.
    protocol TCP
    # Si l’adresse IP de ce serveur virtuel n’a pas pu être activée, le
    # contrôle des serveurs réels est suspendu.
    ha_suspend
    # Vous pouvez définir l’adresse d’un serveur vers qui rediriger les
    # requêtes si tous les serveurs réels sont injoignables.
    #sorry_server 123.45.67.12 10024
    # Définition des serveurs réels écoutant sur le port 10024.
    # node1 :
    real_server 192.168.1.3 10024 {
        # Pondération associée à ce serveur réel. Si vous avez un serveur
        # plus puissant que les autres par exemple, vous pouvez lui
        # mettre une plus grande valeur pour qu’il soit plus souvent
        # utilisé.
        weight 1
        # Si une vérification de la santé de ce serveur réel échoue, la
        # pondération passera à zéro => il ne sera plus utilisé.
        inhibit_on_failure
        # Méthode utilisée pour contrôler la santé de ce serveur réel(HTTP_CHECK, TCP_CHECK, MISC_CHECK).
        TCP_GET {
            #adresse ip à utiliser comme source du test
            bindto 192.168.1.3
            connect_port 10024
            connect_timeout 1
            nb_get_retry 2
            delay_before_retry 1
        }
    }
    # node2 :
    real_server 192.168.1.4 10024 {
        weight 1
        inhibit_on_failure
        TCP_GET {
            bindto 192.168.1.3
            connect_port 10024
            connect_timeout 1
            nb_get_retry 2
            delay_before_retry 1
        }
    }
}

 

Il est aussi possible d’utiliser MISC_CHECK qui permettra par exemple de modifier le poids de chaque serveur à la volée suivant leur charge.

        • On fait de même sur l’autre serveur en le mettant en état de backup :

global_defs {
    notification_email {
        superviseur@platine.com
        monitoring@platine.com
    }
    notification_email_from amavis01@platine.com
    smtp_server 127.0.0.1
    smtp_connect_timeout 30
    router_id CLUSTER-AMAVIS
}  vrrp_instance INCOMING {
    state BACKUP
    interface eth0
    virtual_router_id 10
    priority 99
    advert_int 1
    lvs_sync_daemon_interface eth0
    authentication {
        auth_type PASS
        auth_pass myvrrpdpassword
    }
    smtp_alert
    notify_master « /etc/keepalived/rules master »
    notify_backup « /etc/keepalived/rules backup »
    notify_fault « /etc/keepalived/rules fault »
    virtual_ipaddress {
        123.45.67.1/24 brd 123.45.67.255 dev eth0
    }
}  virtual_server 123.45.67.1 10024 {
    delay_loop 5
    lb_algo wlc
    lb_kind DR
    protocol TCP
    ha_suspend
    # node1 :
    real_server 192.168.1.3 10024 {
        weight 1
        inhibit_on_failure
        TCP_GET {
            bindto 192.168.1.4
            connect_port 10024
            connect_timeout 1
            nb_get_retry 2
            delay_before_retry 1
        }
    }
    # node2 :
    real_server 192.168.1.4 10024 {
        weight 1
        inhibit_on_failure
        TCP_GET {
            bindto 192.168.1.4
            connect_port 10024
            connect_timeout 1
            nb_get_retry 2
            delay_before_retry 1
        }
    }
}

 

      • Voilà, notre keepalived est configuré, nous avons bien notre ip virtuel de disponible sur l’interface eth0 et celle-ci bascule d’un serveur vers l’autre en cas de panne et les connexions sont réparties entre les 2 serveurs… ou presque! En effet, keepalived va transmettre les paquets mais l’ip de destination de ces paquets est l’ip virtuelle, qui n’est que sur le serveur « maître »! Et il faut aussi que le serveur ayant traité la demande réponde avec l’ip virtuelle.

 

      • Pour s’en sortir, il existe 2 manières de faire proprement :

 

        • Ajouter l’adresse ip virtuelle sur l’interface loopback.
        • Ajouter une règle de PREROUTING dans la table de nat.

 
Ip virtuelle sur lo : Pour une raison qui m’échappe encore, j’ai rencontré un problème de boucle lors de la mise en place de cette solution.
Je ne vais donc pas m’attarder sur celle-ci trop longtemps.

          • Sachez tout de même 2 ou 3 choses :
            Elle est nécessaire lorsqu’un des serveurs est sous Windows (oui car il n’y a pas iptables). Il faut utiliser une « carte de bouclage Microsoft ».

     

          • Il est nécessaire d’ajouter ceci dans le sysctl.conf :

    net.ipv4.conf.lo.arp_ignore=1
    net.ipv4.conf.lo.arp_announce=2

    et il faut déclarer l’ip virtuelle comme ceci :

    ip addr add 123.45.67.1/32 brd 123.45.67.1 dev lo
    ip route add 123.45.67.1 dev lo

      Règle de PREROUTING :

              • Cette méthode est très simple, il faut ajouter une règle de préroutage dans la table de nat afin de rediriger l’ensemble du trafic à destination de l’ip virtuelle vers la machine :

        /sbin/iptables -t nat -A PREROUTING -d 123.45.67.1 -p tcp –dport 10024 -j REDIRECT

         

        Ok, sauf que si l’on fait cela sur le « maître » (celui qui va dispatcher le trafic) et bien nous redirigerons donc tout le trafic seulement vers lui. De ce fait, on bypass le loadbalancing. C’est à ce moment là que la fonctionnalité de « notify » de keepalived entre en scène !

         

              •  En effet, grâce à elle, nous allons pouvoir activer/désactiver la règle sur les serveurs suivant leur état master/backup/fault :

         

        vi /etc/keepalived/rules

         

        #!/bin/bash
        case $1 in
          ‘master’)
            /sbin/iptables -t nat -D PREROUTING -d 123.45.67.1 -p tcp –dport 10024 -j REDIRECT
          ;;
          ‘backup’)
            /sbin/iptables -t nat -A PREROUTING -d 123.45.67.1 -p tcp –dport 10024 -j REDIRECT
          ;;
          ‘fault’)
            /sbin/iptables -t nat -D PREROUTING -d 123.45.67.1 -p tcp –dport 10024 -j REDIRECT
          ;;
        esac
        exit

        Maintenant vous pouvez criez « It works!!!! »… Ou presque !

         

        Amavis en cluster

              • Le principal problème à régler va être de faire en sorte que Amavis écoute sur la bonne interface et qu’il retourne le mail scanné au bon serveur émetteur! Ecoute : Ici, cela va être très simple. En effet Amavis ne peut écouter que sur une ou toutes les interfaces/ip.
                Nous avons besoin qu’il écoute sur 127.0.0.1 (en cas de maître) mais aussi sur l’ip de eth0 (en cas de backup) sur chaque serveur.

        Nous n’avons pas le choix, il faut mettre la ligne de code ci-dessous dans la configuration de Amavis (50-user) :

         

        $inet_socket_bind = undef;

         

        Il écoutera donc partout.

        Retour des mails :

        Pour une meilleure gestion, il est primordial que Amavis retourne le mail au serveur qui lui a envoyé (mx, pop, smtp relais…)

         

              • Pour cela, nous allons spécifier les notify et forward method dans le fichier de configuration 50-user :

        $notify_method = ‘smtp:*:10025′;

         

        Et ensuite

            1. Tout est fin prêt pour recevoir les premiers mails ! Vous pouvez tester votre cluster par de simples telnet vers l’ip virtuelle sur le port 10024.

              ipvsadm -l

               

              Cette commande exécutée sur le serveur maître vous permettra de voir l’état des serveurs du clusters avec leurs connexions.
              Il ne vous reste plus qu’à personnaliser votre configuration de Amavis et libre à vous d’ajouter à tout moment, d’autres serveurs à votre cluster ! Souplesse, redondance et performance… tout y est !

        Relier des serveurs en cluster est la technique imparable pour assurer la disponibilité maximum d'un service web

        Photo © Platine

        Schéma graphique © Platine

        © Platine 09/04/2013