Service web : Un mode maintenance pour bricoler

2ème version de ce « truc », avec support SSL, à découvrir par là : Un mode maintenance avec SSL

By RRZEicons (Cc-sa)
By RRZEicons (Cc-sa)

Afin de réaliser des maintenances sur mon service web (ou les services attenant tel que Mysql) j’ai mis en place un petit mot d’excuse qui dit en substance : « maintenance en cours, merci de repasser plus tard ». C’est mieux que « La connexion a échoué » ou « Can’t Connect to MySQL Server on nian nian nian » non ?

La configuration de prod  :

  • Apache sur le port 80

La configuration de maintenance :

  • Apache sur le port 80 (le même)
  • Lighttpd sur le port 81
  • Iptables redirige le trafic arrivant sur le port 80 vers le port 81 en PREROUTING sauf pour mon IP (ça permet donc de bricoler)

Installation de lighttpd

Apeuté, et ayé :

aptitude -y install lighttpd
update-rc.d lighttpd remove
mkdir /var/www/maintenance
echo "Serveur en maintenance" > /var/www/maintenance/index.html # Vous pouvez faire une belle page html c'est mieux !

Configuration de lighttpd

Éditer le fichier /etc/lighttpd/lighttpd.conf

server.modules = (
	"mod_access",
)

server.document-root        = "/var/www/maintenance"
server.upload-dirs          = ( "/var/cache/lighttpd/uploads" )
server.errorlog             = "/var/log/lighttpd/error.log"
server.pid-file             = "/var/run/lighttpd.pid"
server.username             = "www-data"
server.groupname            = "www-data"
server.port                 = 81
server.error-handler-404    = "/index.html"

index-file.names            = ( "index.html", "index.lighttpd.html" )

include_shell "/usr/share/lighttpd/create-mime.assign.pl"

Il est certainement possible de faire plus propre sur ce point. Actuellement je gère le message dans le index.html que je met dans le error404. Des redirection 302 quelque soit l’URL serait à envisager.

Maintenance On/Off

Pour se mettre en mode maintenance :

# Démarrage du serveur d'excuse
service lighttpd start
# Redirection du port 80 vers 81 sauf pour mon IP
iptables -A INPUT -p tcp --dport 81 -j ACCEPT
iptables -t nat -A PREROUTING \! -s ${IPMAISONDEMOI} -p tcp --dport 80 -j DNAT --to-destination ${IPDUSERVEUR}:81
iptables -t nat -A POSTROUTING -j MASQUERADE

Et pour désactiver le mode maintenance :

# Si vous n'avez pas d'autres règles (c'est mal) :
iptables -F
iptables -t nat -F
# Sinon redémarrer votre service iptables 
# Lighttpd n'est plus utile
service lighttpd stop

Si vous avez des suggestions…

[ispconfig] Managesieve (dovecot) & Horde

sieve.infoDes dires de Wikipedia : « Sieve est un langage de filtrage du courrier électronique. Il est normalisé dans le RFC 5228. Sieve permet de filtrer sur les en-têtes d’un message qui suit le format du RFC 5322, c’est-à-dire un message Internet typique.  »

Sieve c’est très pratique car le filtrage du courrier est effectué au niveau du serveur dès la réception de l’email. Ce qui est presque indispensable quand on utilise plusieurs clients de messagerie (web &/ou desktop). Je vais donc utiliser Managesieve (qui est la partie serveur du protocole) pour Dovecot (projet Pigeonhole).

Actuellement le panel ISPconfig me permet d’éditer les filtres Sieve mais n’utilise pas Managesieve. ISPconfig stock en base (table mail_user_filter) et écrase le fichier à chaque modification.

Je ne souhaite plus passer par ISPconfig pour modifier mes filtres, mais directement par Horde (via Ingo) ou Roundcube (plugin) ou encore par thunderbird (plugin) selon mes besoins.

Installation de Managesieve

Rien de plus simple :

aptitude install dovecot-managesieved

Modifier le fichier /etc/dovecot/dovecot.conf :

< protocols = imap
> protocols = imap sieve

Puis redémarrer le service, le port 4190 doit ensuite être à l’écoute :

$ service dovecot restart
$ netstat -pnat | grep 4190
tcp        0      0 0.0.0.0:4190            0.0.0.0:*               LISTEN      11111/dovecot

Horde (ingo) & Sieve

Il vous suffit de modifier le fichier ingo/config/backends.php de votre instance horde de la façon suivante :

[...]
/* IMAP Example */
$backends['imap'] = array(
    // ENABLED by default
<    'disabled' => false,
>    'disabled' => true,
    'transport' => array(
        Ingo::RULE_ALL => array(
            'driver' => 'null',
            'params' => array(),
        ),
    ),
[...]
$backends['sieve'] = array(
    // Disabled by default
<    'disabled' => true,
>    'disabled' => false,
    'transport' => array(
        Ingo::RULE_ALL => array(
            'driver' => 'timsieved',
            'params' => array(
                // Hostname of the timsieved server
                'hostspec' => 'localhost',
                // Login type of the server
                'logintype' => 'PLAIN',
                // Enable/disable TLS encryption
                'usetls' => false,
                // Port number of the timsieved server
                'port' => 4190,
                // Name of the sieve script
<                'scriptname' => 'ingo',
>                'scriptname' => 'filtres',
                // Enable debugging. The sieve protocol communication is logged
[...]

Ne faites (peut être) pas ça chez vous

En effet ça ne s’avère pas être forcément la meilleure des solutions :

  • Il n’est apparemment pas possible d’importer des scripts existants.
  • Plus embêtant il s’avère que Horde fonctionne presque de la même façon qu’ISPconfig. A savoir qu’il stock en base les filtres et écrase le script sieve (via managesieve quand même) Ce qui me condamne à n’utilise qu’une interface (horde) pour modifier mes filtres :’-(

Bon je m’en contente, il est toujours plus agréable de modifier ses filtres via son webmail (horde) que via le panel ISPconfig.

Ghostery : Si c’est gratuit, c’est vous le produit ?

« Si c’est gratuit, c’est vous le produit ! » c’est le titre d’une émission très intéressante de « là-bas si j’y suis » (ré-écouter) qui nous rappel à quel point nos données personnels sont une source de revenu phénoménale pour quelques grosses entreprises de marketing… Ma position personnelle est claire (d’autant plus avec le plugin wordpress d’incitation à l’anti-pub) : je refuse, tant que faire se peut, qu’on collecte des informations sur ma personne à l’insu de mon plein gré. (dédicace Richard V.)

J’avais rédigé un article pour venter les mérites de Ghostery qui, venant s’ajouter à un anti-pub classique, me satisfaisait amplement. Il bloquait réseau sociaux, statistique (type Analytics)… c’était parfait ! Mais au détour d’un surf sur la toile du web (comme disent les jeunes) je suis tombé sur un article de surfezcouvert.net qui dit ceci :

« Ghostery” […] serait détenu par Evidon une entreprise qui… vend nos données personnelles aux publicitaires. »

By moneyblognewz
By moneyblognewz

je contacte l’auteur aussitôt pour essayer de connaître la source de cette information, mais je n’obtiens pas de réponse. J’ai donc fouiné… et voici quelques sources plus ou moins intéressantes sur le sujet:

Donc oui Ghostery appartient à la société Evidon dont l’activité est de faire du  « Online marketing intelligence, web analytics privacy »… un dessin ?

Le développement de Ghostery et sa base d’utilisateurs dévoués nous permettent de révéler la technologie marketing invisible sur le Web de façon plus exhaustive et unique que jamais auparavant, » a déclaré Scott Meyer, PDG d’Evidon. « Un panel de recherche quantitative courant peur comprendre 50 000 utilisateurs. Cependant, notre panel GhostRank compte plus de 7,8 millions d’utilisateurs qui nous permettent d’indexer l’activité de plus de 26 millions de domaines chaque jour, dans le monde entier. Les données anonymes issues de notre panel révèlent un éclairage précieux qui permet aux publicitaires et aux éditeurs d’affiner leur prise de décisions de partenariats dans l’écosystème numérique. » [Sources bfmtv.com]

Toutefois il semblerait* que seul la fonction GhostRank (qui n’est pas -encore- activé par défaut) envoie des données chez Exidon.

* « il semblerait » car je n’ai pas fait la démarché de décompresser et d’analyser le code de Ghostery. Ceci dit si quelqu’un le fait qu’il n’hésite pas à en faire part !

Ghostery serait donc acceptable. Mais plus pour moi, car en plus de ne pas être libre, un doute plane… sans compter qu’on ne sait pas ce qu’ils feront dans la prochaine mise à jour. Il faut trouver une autre solution.

Plan B : Protection par DNS

Il y a un paradoxe à protéger sa vie privée en fessant mentir le DNS non ? En tout cas pour un groupe de machine ça reste une solution remarquable. C’est suite à un commentaire que j’ai découvert adsuck. Adsuck est un petit service DNS qui bloque les méchants…)

Sourceforge avec Adsuck
Sourceforge avec Adsuck

Mais Adsuck, en plus d’être pénible à installer et à faire fonctionner sous linux, ne s’avère pas optimisé donc fait grandement ralentir mon surf. A ajouter à cela le fait que le projet ne semble pas très actif.

Mais en fouillant pour comprendre le fonctionnement d’Adsuck j’ai découvert un « service » qui fournis des fichiers hosts de nom de domaine méchant. Il y a plein de service existant de ce type, celui qu’utilise Adsuck s’appelle winhelp2002.mvps.org, il semble actif, je teste !

Plan C : winhelp2002.mvps.org

On télécharge le fichier hosts fourni et le met à la place du notre. Cette manipulation peut être facilement automatisée tous les jours (cron.daily) avec un petit script :

#!/bin/bash
# Source : http://www.putorius.net/2012/01/block-unwanted-advertisements-on.html
cd /tmp
wget http://winhelp2002.mvps.org/hosts.txt
rm /etc/hosts
mv hosts.txt /etc/hosts

Ce qui me plaisait dans Adsuck c’était l’aspect intégration avec le service DNS et donc la possibilité de le mutualiser… Du coup j’ai scripté pour transformer le fichier hosts de winhelp2002.mvps.org en zone DNS bind9 :

#!/bin/bash

set -eu

HOSTSURL="http://winhelp2002.mvps.org/hosts.txt"
NAMEDCONFADS="/etc/bind/named.conf.ads"
BLOCKEDZONE="/etc/bind/blockeddomain.hosts"
FICTMP=`tempfile`
ERRORLOG=`tempfile`
# Email pour les erreurs (0 pour désactiver
EMAIL=0
# Log d'erreur
exec 2> ${ERRORLOG}

ionice -c3 -p$$ &>/dev/null
renice -n 19 -p $$ &>/dev/null

function cleanup {
    if [ "`stat --format %s ${ERRORLOG}`" -ne "0" ] && [ "$EMAIL" != "0" ] ; then
        cat ${ERRORLOG} | mail -s "$0 - Log error" ${EMAIL}
    else 
        cat ${ERRORLOG} 
    fi
    rm ${ERRORLOG}
}
trap cleanup EXIT

# téléchargement du fichier hosts
wget "${HOSTSURL}" -O ${FICTMP} &>/dev/null

# Suppression des commentaires
grep -v '^#' ${FICTMP} | 
	# Suppression des 6 premières lignes inutiles
	tail -n +6 | 
	# On retir les sauts de ligne mac
	sed 's/\x0D$//' | 
	# La syntaxe bind
	awk  -v blockzone=${BLOCKEDZONE} ' { printf "zone \"%s\"  {type master; file \"%s\";};\n" ,$2,blockzone }' > ${NAMEDCONFADS}

/usr/sbin/named-checkconf ${NAMEDCONFADS}
/usr/sbin/service bind9 reload 

rm ${FICTMP}

Il ne reste plus qu’à inclure le fichier /etc/bind/named.conf.ads dans le named.conf :

>    include "/etc/bind/named.conf.ads";

Après quelques jours d’utilisation ça ne s’avère pas très probant, car ça bloque finalement moins que les machin’block en extension navigateur (Trueblock, Adblock Edge, *block)

Plan D : retour au plan A

Finalement, je suis resté avec mon machin’block et j’ai suivi le conseil de John77800 en ajoutant les listes Antisocial.txt (ajout direct) & Fanboy’s Social (ajout direct)

– Qui dit mieux ?

– Mieux

Backup chiffré avec duplicity sur HubiC

EDIT 24/02/2015 : ‘Il n’est plus nécessaire d’utiliser cloudfiles comme backend pour duplicity. À la place, il faut utiliser un backend spécial hubic intégré à duplicity récemment » voir le commentaire de blankoworld

EDIT 02/2015 : suppression du « DeprecationWarning » dans le log.

EDIT 17/02/2014 : suite à des changements sur Hubic.com, Gu1 à mis à jour python-cloudfiles-hubic. J’ai donc mis à jour mon script en conséquence

Hubic GUI avec duplicityMon ADSL est depuis peut chez OVH. De ce fait je bénéficie d’un compte hubiC avec un espace de stockage d’1To. Quelle aubaine pour des sauvegardes ! Mais bon donner mes mails, mes sites, mes documents administratifs à un tiers… bof bof. Il faudrait un minimum de chiffrage !

Et bien comme disait les autres nuls : « Hassan Cehef c’est possible » avec duplicity et python-cloudfiles-hubic !

python-cloudfiles-hubic est nécessaire car duplicity n’intègre pas nativement le service cloud « HubiC » pour une sombre histoire de protocole d’authentification non standard de la part d’OVH (détail par l’auteur)

Installation

On commence par le plus simple (duplicity) :

aptitude install duplicity

Maintenant python-cloudfiles-hubic :

aptitude install python-setuptools git
cd /usr/src
git clone https://github.com/Gu1/python-cloudfiles-hubic.git
cd python-cloudfiles-hubic
python setup.py  install

Utilisation

Dans vos paramètre sur hubic.com dans votre menu « Vos application » il va falloir ajouter une application :

  • Nom : cequevousvoulez
  • Domaine de redirection : http://localhost/

Quand l’application est créer récupérer le « client id » ainsi que le « client secret » dans l’interface

screenshot.62

Quelques petits tests pour la prise en main :

# Désactiver le bash_history (c'est pénible avec les mots de passes)
unset HISTFILE
# Les variables 
export CLOUDFILES_USERNAME=toto@toujours.lui
export CLOUDFILES_APIKEY=je.vais.pas.vous.donner.le.mot.de.passe.de.toto
# CLOUDFILES_AUTHURL="hubic|client id|client secret|http://localhost/"
export CLOUDFILES_AUTHURL="hubic|api_hubic_XXXX|YYYYY|http://localhost/"
# Sauvegarde
duplicity /root cf+http://default
# Observer l'état
duplicity collection-status cf+http://default
# Liste les fichiers distants 
duplicity list-current-files cf+http://default
# Test la restauration d'un fichier 
duplicity  --file-to-restore .bash_alias cf+http://default /tmp/bash_alias_recup

Rendez-vous ensuite dans votre interface hubiC. Et là normalement il y a plein de fichier duplicity-BLABLA-blabla.bla ! On supprime tout ! (c’était juste pour les tests)

Il ne semble pas possible d’écrire dans un sous répertoire. Mais, comme je l’ai signalé dans mon commentaire, il semble possible d’écrire dans un autre « container » sur hubiC (autre que default). Il ne sera visible qu’après modification de l’URL. Exemple si vous avez écrit dans le conteneur backup rendez vous sur l’URL : https://hubic.com/home/browser/#backup

Le script

Voici mon script :

#!/bin/bash

###################################
## Backup sur HubiC avec duplicity
# Script sous licence BEERWARE
# Version 0.4.1 02/2015
###################################

set -eu

##### Paramètres

# Utilisateur Hubic
HUBICUSER="leuserdevotrehubic"
# Mot de passe HubiC
HUBICPASSWORD="lemotdepassedevotrehubic"
# Application client id Hubic
HUBICAPPID="api_hubic_XXXXX"
# Application client secret Hubic
HUBICAPPSECRET="YYYYYY"
# Application domaine de redirection Hubic
HUBICAPPURLREDIRECT="http://localhost/"
# Liste à sauvegarder (voir le man duplicity avec le filelist)
DUPLICITYFILELIST="/etc/backup-`hostname`.filelist"
# Passphrase pour le chiffrement
PASSPHRASE="VotrePassPhraseDeOufQueYaQueVousEtVousSeulQuiSavez:-p"
# Fréquence des sauvegardes complètes
FULLIFOLDERTHAN="1W"
# Rétention des sauvegardes
RETENTION="2M"
# Log d'erreur
LOGERROR="/var/tmp/backup-hubic-error.log"
# Bin de duplicity
DUPLICITY_BIN="/usr/bin/duplicity"
# Email pour les erreurs (0 pour désactiver)
EMAIL="toto@mondomaine.com"
# Envoyer un rapport par email sur l'état des backup
RAPPORT=1
# Log d'erreur
exec 2> ${LOGERROR}

##### Début du script

function cleanup {
	echo "exit..."
	unset CLOUDFILES_USERNAME
	unset CLOUDFILES_APIKEY
	unset PASSPHRASE
        grep -v "has been deprecated" ${LOGERROR} > ${LOGERROR}.tmp
        mv ${LOGERROR}.tmp ${LOGERROR}
	if [ "`stat --format %s ${LOGERROR}`" != "0" ] && [ "$EMAIL" != "0" ] ; then
		cat ${LOGERROR} | mail -s "$0 - Error" ${EMAIL}
	fi
}
trap cleanup EXIT

# Gentil avec le système
ionice -c3 -p$$ &>/dev/null
renice -n 19 -p $$ &>/dev/null

if ! [ -f ${DUPLICITYFILELIST} ] ; then
	echo "Aucun fichier filelist : ${DUPLICITYFILELIST}"
	exit 1
fi

export CLOUDFILES_USERNAME=${HUBICUSER}
export CLOUDFILES_APIKEY=${HUBICPASSWORD}
export CLOUDFILES_AUTHURL="hubic|${HUBICAPPID}|${HUBICAPPSECRET}|${HUBICAPPURLREDIRECT}"
export PASSPHRASE

# Backup 
${DUPLICITY_BIN} --full-if-older-than ${FULLIFOLDERTHAN} / cf+http://default --include-globbing-filelist ${DUPLICITYFILELIST} --exclude '**'

# Suppression des vieux backups
${DUPLICITY_BIN} remove-older-than ${RETENTION} cf+http://default --force

# Rapport sur le backup
if [ "$RAPPORT" != "0" ] && [ "$EMAIL" != "0" ] ; then
        ${DUPLICITY_BIN} collection-status cf+http://default | mail -s "$0 - collection-status" ${EMAIL}
fi

unset CLOUDFILES_USERNAME
unset CLOUDFILES_APIKEY
unset PASSPHRASE

exit 0

A noter que mes bases de données sont dumpées à plat de façon indépendante du script de backup distant (par mysql_dump.sh)

Exemple de fichier filelist :

/etc
/var/backups/mysql
/var/chroot/bind9/etc/bind
/var/lib/mysql
/var/lib/awstats
/var/lib/mailman
/var/spool/cron
/var/vmail
- /var/www/mercereau.info/wp-content/cache/
- /var/www/default
/var/www
/home
- /root/.cpan
- /root/.cache
- /root/.npm
/root
/opt

Attention : les fichiers et répertoires à exclure doivent apparaître avant l’inclusion d’un répertoire parent. En effet, duplicity s’arrête à la première règle qui matche un chemin donné pour déterminer s’il doit l’inclure ou l’exclure. (sources)

Il n’y a plus qu’a le lancer en tâche cron :

44 4 * * *  /usr/local/bin/backup-to-hubic.sh

Ressources

WordPress & fail2ban : stopper la brute-force « POST /wp-login.php »

Edit : azerttyu, dans son commentaire signale une solution plus propre (bien que celle-ci fonctionne)

WordPress étant très populaire il est (malheureusement) de fait très attaqué.. La principale (hors SPAM sur les commentaires) est faite par brute-force sur la page wp-login.php. Je l’avais déjà remarqué, mais j’ai récement eu des problèmes d’indisponibilités suite à plusieurs attaques venant de multiple adresse IP (l’attaque passant donc de brute-force à DDOS) J’ai donc dû réagir et pour ce faire j’ai configuré fail2ban pour bloquer les IP’s faisant plus de 6 tentatives de connexions sur tous les sites wordpress du serveur.

Configuration de fail2ban

Note : mon installation de fail2ban est existante et fonctionne déjà pour le FTP & le SSH

Créer le fichier /etc/fail2ban/jail.d/apache-wp-login.conf  :

> [apache-wp-login]
> 
> enabled = true
> port    = http,https
> filter  = apache-wp-login
> logpath = /var/log/apache2/un.autre.blog.wordrepp/access.log
>         /var/log/apache2/mercereau.info/access.log
> maxretry = 6

Puis créer la définition de la regex « apache-wp-login » dans le fichier /etc/fail2ban/filter.d/apache-wp-login.conf

[Definition]
failregex = ^<HOST> -.*POST .*wp-login.php HTTP.*
ignoreregex =

Pour finir : un restart du service fail2ban & vous n’avez plus qu’à tester en faisant plus de 6 tentatives de mot de passe sur la page votreblog/wp-admin/

$ service fail2ban restart
$ tail -f /var/log/fail2ban.log
2013-09-05 16:33:39,559 fail2ban.actions: WARNING [apache-wp-login] Ban XX.XX.XX.XX

Pour information, le lendemain 47 IP ont été bloquées grâce à ce système…

$ fail2ban-client status apache-wp-login
Status for the jail: apache-wp-login
|- Filter
| |- Currently failed: 7
| |- Total failed: 59966
| `- File list: /var/log/apache2/mercereau.info/access.log
`- Actions
|- Currently banned: 0
|- Total banned: 4128
`- Banned IP list:

Si comme moi vous gérez un hébergement mutualiser vous pouvez ajouter un script qui toutes les nuits scan votre /var/www à la recherche de wp-login.php et ajout le log dans fail2ban. Ce script est adapté à l’architecture d’ISPconfig :

#!/bin/bash

# Détection des wordpress sur le serveur
# Ajout des logs du site en question dans fail2ban
# Fonctionne avec l'arbo du panel ISPconfig3
# A mettre en tâche planifié

fail2banConf='/etc/fail2ban/jail.d/apache-wp-login.conf'

echo -n "[apache-wp-login]
enabled = true
port    = http,https
filter  = apache-wp-login
maxretry = 8
logpath = " > $fail2banConf

find /var/www/clients -name wp-login.php | while IFS=$'\n' read f ; do
    clientId=`echo $f | cut -d"/" -f5`
    siteId=`echo $f | cut -d"/" -f6`
    # Test si le lien symbolique n'est pas mort
    readlink=`readlink /var/www/clients/$clientId/$siteId/log/access.log`
    ls /var/www/clients/$clientId/$siteId/log/${readlink} &>/dev/null
    if ! (($?)) ; then
		echo "	/var/www/clients/$clientId/$siteId/log/access.log " >> $fail2banConf
    fi
done

/etc/init.d/fail2ban restart >/dev/null

Vous pouvez aussi faire la même chose pour bloquer wp-xmlrpc (qui est très sollicitée en brute force. Dans le script d’automatisation je télécharge les IP utilisé par JetPack (non pas que j’aime ce plugin mais certain de mes utilisateurs l’utilise et c’est bloquant pour xmlrpc…

#!/bin/bash

# Détection des wordpress sur le serveur
# Ajout des logs du site en question dans fail2ban
# Fonctionne avec l'arbo du panel ISPconfig3
# A mettre en tâche planifié

# https://wpchannel.com/wordpress/tutoriels-wordpress/lutter-attaques-ddos-xml-rpc-php-fail2ban/

cd /tmp
wget https://jetpack.com/ips-v4.txt
if ! (($?)) ; then
	ips=`sed ':a;N;$!ba;s/\n/ /g' /tmp/ips-v4.txt`
else 
	ips=''
fi

fail2banConf='/etc/fail2ban/jail.d/apache-wp-xmlrpc.conf'

echo -n "[apache-wp-xmlrpc]
enabled = true
filter = apache-wp-xmlrpc
bantime = 86400
maxretry = 1
port    = http,https
ignoreip = 127.0.0.1/8 ns1.wordpress.com ns2.wordpress.com ns3.wordpress.com ns4.wordpress.com jetpack.wordpress.com $ips 
logpath = " > $fail2banConf

find /var/www/clients -name wp-login.php | while IFS=$'\n' read f ; do
    clientId=`echo $f | cut -d"/" -f5`
    siteId=`echo $f | cut -d"/" -f6`
    # Test si le lien symbolique n'est pas mort
    readlink=`readlink /var/www/clients/$clientId/$siteId/log/access.log`
    ls /var/www/clients/$clientId/$siteId/log/${readlink} &>/dev/null
    if ! (($?)) ; then
		echo "	/var/www/clients/$clientId/$siteId/log/access.log " >> $fail2banConf
    fi
done

/etc/init.d/fail2ban restart >/dev/null

Et le fichier : /etc/fail2ban/filter.d/apache-wp-xmlrpc.conf

[Definition]
failregex = ^ .(GET|POST) /xmlrpc.php .
ignoreregex =

OpenDKIM & Postfix sur debian squeeze

Edit : suite au commentaire de Gaël & mon problème de double signature, sa solution est la bonne, je modifie l’article en conséquence.

Après mettre passé de Amavis/SpamAssasin à Dspam j’ai voulu ré-implémenter DKIM (que j’avais implémenté avec Amavis) cette fois-ci avec OpenDKIM :

Installation :

$ aptitude install opendkim
$ mkdir -p /etc/dkim

Modification du fichier de config postfix (/etc/postfix/master.cf)

smtp      inet  n       -       -       -       -       smtpd
<   -o content_filter=dspam:
>   -o content_filter=dspam: -o smtpd_milters=inet:127.0.0.1:8891

Modification de la configuration d’OpenDKIM (/etc/opendkim.conf) :

Socket          inet:8891@localhost
LogWhy yes
MilterDebug     1

# Log to syslog
Syslog                  yes
# Required to use local socket with MTAs that access the socket as a non-
# privileged user (e.g. Postfix)
UMask                   002

KeyTable           /etc/dkim/KeyTable
SigningTable       /etc/dkim/SigningTable
ExternalIgnoreList /etc/dkim/TrustedHosts
InternalHosts      /etc/dkim/TrustedHosts

Il faut maintenant générer les clefs & ce script va nous y aider :

#!/bin/bash

# Script sous licence BEERWARE

SELECTOR="mail"
REPERTOIRE="/etc/dkim"
DOMAINE=$1
USERDKIM="opendkim"
GROUPDKIM="opendkim"

if ! [ -d "${REPERTOIRE}" ] ; then
    echo "Le répertoire ${REPERTOIRE} n'existe pas."
    exit 1
fi

if [ -z ${DOMAINE} ] ; then
    echo "Vous devez avoir renseigner le domaine en argument du script."
    exit 2
fi

if [ -d "${REPERTOIRE}/keys/${DOMAINE}" ] ; then
    echo "Le répertoire ${REPERTOIRE}/keys/${DOMAINE} existe déjà... vous devez déjà avoir dû lancé le script."
    exit 3
else 
    mkdir -p ${REPERTOIRE}/keys/${DOMAINE}
fi

opendkim-genkey -D ${REPERTOIRE}/keys/${DOMAINE} -r -d ${DOMAINE} -s ${SELECTOR}
chown ${USERDKIM}:${GROUPDKIM} ${REPERTOIRE}/keys/${DOMAINE}/${SELECTOR}.private
echo "${SELECTOR}._domainkey.${DOMAINE} ${DOMAINE}:${SELECTOR}:${REPERTOIRE}/keys/${DOMAINE}/${SELECTOR}.private" >> ${REPERTOIRE}/KeyTable
echo "${DOMAINE} ${SELECTOR}._domainkey.${DOMAINE}" >> ${REPERTOIRE}/SigningTable
echo "${DOMAINE}" >> ${REPERTOIRE}/TrustedHosts

if [ -f ${REPERTOIRE}/keys/${DOMAINE}/${SELECTOR}.txt ]; then 
    cat ${REPERTOIRE}/keys/${DOMAINE}/${SELECTOR}.txt
else 
    echo "Une erreur s'est produite !"
fi

Exemple d’utilisation du script :

$ ./addDkimKey.sh mercereau.info
mail._domainkey IN TXT "v=DKIM1; g=*; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDEOxRe2sVbsmDYbnB1pRWdx5U6FgZiwUKRl0gPFmsgPNA035P7gBLmhXrmALeJLZv0n7ARkStoIvl/ZNAbUep/YUgMynW5q2fsh4Pa/q82ocPKRKGLBYTxFDa+tyhG0oi5pzI6d37Ji9M40c5DgD/2QqTfyY5ywLqKG47+HuivJQIDAQAB" ; ----- DKIM mail for mercereau.info

Le script vous sort l’enregistrement DNS a ajouter pour terminer la configuration

On redémarre les services :

$ service opendkim restart
$ service postfix restart

Et pour finir on test ici ou .

Ce tuto à été très fortement inspiré par le tuto de isalo.org

[ispconfig] Remplacer Amavis/Spamassassin par Dspam

dspam-logo-textAjouter des services décentralisés « à la maison » c’est le bien mais à force d’empiler des briques… ça déborde. Et là j’étais à un stade ou la SWAP était un chouilla trop utilisée.

J’avais déjà désactivé ClamAv (anti-virus) pour économiser de la mémoire vive mais ça ne suffisait pas. Mon autre plus gros poste de dépense en RAM était Amavis/Spamassasin. Je me suis donc mis à chercher une alternative ; La plus légère et efficace semble être DSPAM.

Attention : Le fait de remplacer Amavis/Spamassasin va, de fait vous amputer de fonctionnalité administrable par le panel ISPconfig « Stratégie anti-spam », « liste blanche » car Ispconfig ne support pas (encore !?) DSPAM

Préparation

Étant donné que le serveur est déjà en prod j’ai modifié mon script de firewall (iptables) en spécifiant seulement mon adresse IP pour l’accès au SMTP (pour les tests) ça aura pour effet de faire patienter vos emails en file d’attente sur le serveur émetteur quoi que vous fassiez comme bêtise…

< iptables -A INPUT -p tcp --dport smtp -j ACCEPT
> iptables -A INPUT -p tcp --dport smtp -s VOTRE.IP.DE.MAISON -j ACCEPT

5 jours, c’est par défaut le temps d’attente maximal de la plupart des MTA. Vous pouvez donc théoriquement bricoler pendant 5 jours sans perdre d’email dans cet état…

Installation

Je suis sous Debian squeeze, les paquets Dsapm existe pour squeeze mais dans le backport (non activé pour ma part)

Installation des dépendances :

$ aptitude install libgd-gd2-perl libgd-graph-perl libgd-graph3d-perl libgd-text-perl dbconfig-common postfix-pcre

Ensuite on récupère les paquets sur le site de debian et ont les installent

$ dpkg -i libdspam7_3.10.1+dfsg-3~bpo60+1_amd64.deb
$ dpkg -i libdspam7-drv-mysql_3.10.1+dfsg-3~bpo60+1_amd64.deb
$ dpkg -i dspam_3.10.1+dfsg-3~bpo60+1_amd64.deb
$ dpkg -i dspam-webfrontend_3.10.1+dfsg-3~bpo60+1_all.deb

Note : dbconfig-common va vous demander ce qu’il faut pour créer la base de données.. »suivez le guide. »

Configuration

Postfix

Nous allons, dans postfix désactiver la partie Amavis et activer la partie Dspam /etc/postfix/main.cf :

58c58
< smtpd_client_restrictions = check_client_access mysql:/etc/postfix/mysql-virtual_client.cf
---
> smtpd_client_restrictions = check_client_access mysql:/etc/postfix/mysql-virtual_client.cf, check_client_access pcre:/etc/postfix/dspam_filter_access
71,72d70
< content_filter = amavis:[127.0.0.1]:10024
< receive_override_options = no_address_mappings
74a73,76
>
> dspam_destination_recipient_limit = 1

Même chose dans le fichier /etc/postfix/master.cf :

smtp      inet  n       -       -       -       -       smtpd
11a12
>    -o content_filter=dspam:
116,129c117,118
< 127.0.0.1:10025 inet n - - - - smtpd
<         -o content_filter=
<         -o local_recipient_maps=
<         -o relay_recipient_maps=
<         -o smtpd_restriction_classes=
<         -o smtpd_client_restrictions=
<         -o smtpd_helo_restrictions=
<         -o smtpd_sender_restrictions=
<         -o smtpd_recipient_restrictions=permit_mynetworks,reject
<         -o mynetworks=127.0.0.0/8
<         -o strict_rfc821_envelopes=yes
<         -o receive_override_options=no_unknown_recipient_checks,no_header_body_checks
<         -o smtpd_bind_address=127.0.0.1
< 
---
> dspam   unix    -       n       n       -       10      pipe
>         flags=Rhqu user=dspam argv=/usr/bin/dspam --deliver=innocent --user $user -i -f $sender -- $recipient

Dspam

Dans mon cas j’ai choisi de tout le temps délivrer les SPAM et de tagger le sujet. L’apprentissage se fera via l’interface web (dont nous verrons la configuration plus tard)

Activer le démarrage de Dspam /etc/default/dspam

< start=NO
---
> start=YES

La configuration de Dspam à largement été inspiré du howto d’UNIX garden :

29c29
< StorageDriver /usr/lib/dspam/libhash_drv.so
---
> StorageDriver /usr/lib/dspam/libmysql_drv.so
48c48
< TrustedDeliveryAgent "/usr/bin/procmail"
---
> TrustedDeliveryAgent "/usr/sbin/sendmail"
144c144
< Trust root
---
> #Trust root
146,149c146,149
< Trust www-data
< Trust mail
< Trust daemon
< Trust amavis
---
> #Trust www-data
> #Trust mail
> #Trust daemon
> #Trust amavis
151a152
> Trust postfix
297c298
< Preference "signatureLocation=message"	# { message | headers } -> default:message
---
> Preference "signatureLocation=headers"	# { message | headers } -> default:message
371a373,380
> MySQLServer     	127.0.0.1
> #MySQLPort
> MySQLUser               dspam
> MySQLPass               MOTDEPASSEDEMALADE
> MySQLDb                 dspam
> MySQLCompress           true
> MySQLUIDInSignature    on
> 
471c480
< LocalMX 127.0.0.1
---
> #LocalMX 127.0.0.1

Pour finir sur les tags j’ai dû faire la chose suivante :

$ mkdir /var/spool/dspam/txt/
$ echo ‘Scanned and tagged as SPAM by DSPAM’ > /var/spool/dspam/txt/msgtag.spam

Premier test

Redémarrage des services pour appliquer tous ces changements :

$ service amavis stop
$ service postfix restart
$ service dspam start

Pour tester vous pouvez en envoyer un message avec la commande telnet. Voici un petit script pratique pour automatiser le test :

#!/bin/bash
from="nimportequi@domain.fr"
to="david@domain.fr"
smtp="smtp.domain.fr"
(
    sleep 1
    echo "ehlo x"
    sleep 1
    echo "mail from:${from}"
    sleep 1
    echo "rcpt to:${to}"
    sleep 1
    echo "data"
    sleep 1
    echo "subject:Test message"
    sleep 1
    echo "from:${from}"
    sleep 1
    echo "to:${to}"
    sleep 1
    echo " "
    echo "Coucou."
    sleep 1
    echo "."
    sleep 1
    echo "QUIT"
) | telnet ${smtp} 25

Dans les entêtes du message vous devriez avoir du X-DSPAM comme ceci :

X-DSPAM-Result: Innocent
X-DSPAM-Processed: Thu Jul 1 00:03:19 2050
X-DSPAM-Confidence: 0.9751
X-DSPAM-Probability: 0.0000
X-DSPAM-Signature: 1,51e7a147199049585619662

Si tout fonctionne on dégage amavis (dit « le gros amavis ») du démarrage :

update-rc.d dspam defaults
update-rc.d amavis remove

Sinon fouiller vos logs (/var/log/mail.log /var/log/syslog…)

Interface web

L’interface web est en CGI et nous allons utiliser apache & suexec (qui est déjà embarqué avec ISPconfig) pour le faire tourner

Voici la configuration du virtualhost (sites-available/dspam)

<IfModule mod_suexec.c>
    <VirtualHost *:80>
        DocumentRoot /var/www/dspam

        # Problème css, image : 
        Alias /usr/share/dspam /usr/share/dspam

        ServerName dspam.domain.fr
        ServerAdmin dspam@domain.fr

        SuexecUserGroup dspam dspam

        <Directory /var/www/dspam>
            Options ExecCGI
            Options -Indexes
            Addhandler cgi-script .cgi
            DirectoryIndex dspam.cgi
        </Directory>

        <Directory />
            Options FollowSymLinks
            AllowOverride None
            Order allow,deny
            allow from all
            AuthType Basic
            AuthName "Restricted DSPAM user"
            Auth_MYSQLhost localhost
            Auth_MYSQLusername ispconfig
            Auth_MYSQLpassword MOTDEPASSESUPERCHAUD
            Auth_MYSQLdatabase dbispconfig
            Auth_MYSQLpwd_table mail_user
            Auth_MYSQLuid_field login
            Auth_MYSQLpwd_field password
        </Directory>
    </VirtualHost>
</IfModule>

On active le virtualhost :

$ a2ensite dspam
$ service apache2 graceful

On ajoute le compte admin de l’interface :

$ echo "david" > /etc/dspam/admins

Vous devriez maintenant pouvoir vous rendre sur l’interface :

  • http://dspam.domain.fr/ (interface utilisateur)
  • http://dspam.domain.fr/admin.cgi (interface d’administration)

Conclusion

L’objectif premier était d’économiser de la mémoire vive, c’est chose faite ! la preuve en image :

memory-day

Je suis aussi très satisfait de l’apprentissage de DSPAM. Au début ça peut faire peur parce qu’il laisse vraiment tout passer, mais l’apprentissage est rapide et significatif :

Les premiers jours d'utilisation de DSPAM
Les premiers jours d’utilisation de DSPAM

Ressources

Les sites ressources que j’ai utilisées :

En continuant à utiliser le site, vous acceptez l’utilisation des cookies (au chocolat) Plus d’informations

Les cookies sont utilisés à des fin de statistique de visite du blog sur une plateforme indépendante que j'héberge moi même. Les statistiques sot faites avec un logiciel libre. Aucune information n'est redistribué à google ou autre. Je suis seul autorisé à lire ces informations

Fermer