Squid on OpenBSD (fr)

Les serveurs de proxy sont devenues monnaie courante, pour ne pas dire obligatoires en entreprise (notamment pour la collecte de logs). Le service le plus répandu est Squid, que ce soit en version 2.7 ou 3.1, les versions les plus fréquentes à l’heure actuelle (statistiques du 1er janvier 2013)

Pour ce tutoriel, nous allons utiliser OpenBSD 5.2 et Squid 3.3.4 ainsi que SquidGuard 1.4p3. La configuration de Squid ne sera pas détaillée en terme de sécurité, seuls les éléments d’interaction avec le système et entre Squid et SquidGuard seront rapidement évoqués. Nous n’utiliserons pas l’authentification.

Nous allons optimiser squid en mettant l’ensemble des données qui utilisent des accès disques en ramdisk, et régler les problématiques associées à ce type d’optimisation. Le serveur qui est utilisé dispose de 16Go de RAM afin d’emmagasiner l’ensemble du cache en RAM

Prérequis: configuration de Packet Filter

Vous devez configurer le firewall d’OpenBSD pour autoriser le port 3128 (port par défaut de squid) et autoriser le serveur à faire des requêtes HTTP/HTTPS. Une règle de redirection de ports à été ajoutée afin de faire du proxy transparent sur HTTP. Voici une configuration simple et fonctionnelle (Attention cela ne concerne que Squid):

#
# Macros & Tables
#
out_if="em0"
int_if="em1"
proxy_ip="10.1.1.1"
outgoing_proxy_ip="195.25.36.159"
table <clients> { 10.50.0.0/16 192.168.0.0/16 172.16.0.0/18 }

#
# Default rules
#

block in log all
pass out all

#
# NAT
#

pass in quick on $int_if to any port http rdr-to $proxy_ip port 3128

#
# Filtering
#

pass in quick on $int_if proto tcp from <clients> to $proxy_ip port 3128
pass on $out_if quick proto tcp from $outgoing_proxy_ip to port { http https }

Prérequis: configuration des limites OpenBSD

Afin de pouvoir supporter la charge en terme d’entrées sortes parallèles, nous devons augmenter les limites systèmes en terme de descripteurs de fichiers. Ouvrez le fichier /etc/login.conf et éditez la classe daemon en augmentant le nombre de descripteurs de fichiers à 4096:

daemon:\
        :ignorenologin:\
        :datasize=infinity:\
        :maxproc=infinity:\
        :openfiles-cur=<span style="color: #ff0000;">4096</span>:\
        :stacksize-cur=8M:\
        :localcipher=blowfish,8:\
        :tc=default:

Installation

Installez tout d’abord un OpenBSD tout frais, dans l’idéal en 5.2.

Ensuite on va installer les quelques prérequis, notamment squidGuard et squid2.7, qui serviront de support (notamment si vous souhaitez avoir les helper d’authentification):

export PKG_PATH="http://ftp.fr.openbsd.org/pub/OpenBSD/5.2/packages/amd64/"
pkg_add -i squid
pkg_add -i squidGuard
pkg_add -i wget

Maintenant on va prendre la version de Squid 3.3.4 sur le site de squid-cache.org et la compiler:

cd /root/
wget http://www.squid-cache.org/Versions/v3/3.3/squid-3.3.4.tar.gz
tar xvzf squid-3.3.4.tar.gz
cd squid-3.3.4
./configure  '--enable-pf-transparent' '--enable-follow-x-forwarded-for' '--with-large-files' '--enable-ssl' '--disable-ipv6' '--enable-esi' '--enable-kill-parent-hack' '--disable-snmp' '--with-pthreads'
make -j8
make install

Au niveau des options,

  • si vous n’utiliserez pas le proxy transparent (redirection port 80 -> 3128), retirez ‘–enable-pf-transparent’
  • si vous utilisez IPv6, retirez ‘–disable-ipv6’

L’option -j8 définit l’utilisation de 8 coeurs de processeurs pour la compilation, accélérant nettement le traitement.

Maintenant on va changer le chemin du service squid. Editez le fichier /etc/rc.d/squid et changez la ligne daemon par

daemon="/usr/local/squid/sbin/squid"

Changez maintenant les flags afin de charger le fichier de configuration de squid et activer le service dans /etc/rc.conf.local (s’il n’existe pas, crééez le)

squid=YES
squid_flags="-f /etc/squid/squid.conf"

Copiez maintenant le fichier squid.conf dans un répertoire plus approprié par rapport à OpenBSD

mkdir /etc/squid/
cp /usr/local/squid/etc/squid.conf.documented /etc/squid/squid.conf

Créez maintenant les répertoires de squidGuard dont nous aurons besoin:

mkdir /etc/squidguard/mount/

Configuration

Configuration de Squid

Nous allons maintenant configurer Squid afin d’utiliser Squidguard. Attention depuis la version 3.2, cela ne se configure pas comme en 3.1 et 2.7:

url_rewrite_program /usr/local/bin/squidGuard -c /etc/squidguard/squidguard.conf
url_rewrite_children 192 startup=150 idle=10 concurrency=0

Nous lançons par défaut 150 processus squidGuard, avec un maximum de 192, et 10 en spare.

Si vous souhaitez utiliser le proxy transparent, il faut absoluement rajouter un second port d’écoute en mode intercept

http_port 3128
http_port 3129 intercept

On configure maintenant l’espace mémoire à réserver à squid, ainsi que d’autres paramètres associés:

# Real squid memory cache
cache_mem 2800 MB
maximum_object_size_in_memory 8 MB

# Squid disk cache
cache_dir ufs /var/squid/cache 2800 16 64
minimum_object_size 3 KB
maximum_object_size 6 MB

# IP & DNS names memory cache
ipcache_size 10240
fqdncache_size 10240

# File descriptor number
max_filedescriptors 4096

Vous pouvez tuner ces paramètres en fonction de votre configuration, par exemple divisez par 2 la taille de chaque cache si vous n’avez que 8Go de mémoire. Changez la taille maximale des fichiers en cache suivant le type de pages et de documents qui transitent en HTTP, tout en étant raisonnable, ne mettez pas des ISO en mémoire, le cache sera très vite rempli ! (A moins que vous ayez 64Go de ram, minimum).

Configurez ensuite les autres options, ACL, etc… à votre guise.

Configuration de SquidGuard

Ouvrez le fichier /etc/squidguard/squidguard.conf (s’il n’existe pas créez le et peuplez le). Nous allons simplement modifier la ligne correspondant au répertoire de blacklists:

dbhome /etc/squidguard/mount/blacklists

Configuration du système

Nous allons maintenant nous occuper du tuning du système, de la configuration du boot, de la mise à jour des blacklists.

Dans un premier temps, on va créer 2 ramdisk pour stocker le cache “disque” de squid et les blacklists de squidGuard. Ouvrez le fichier /etc/fstab et ajoutez les 2 lignes suivantes:

swap            /etc/squidguard/mount   mfs rw,nodev,nosuid,noatime,-s=2096900 0 0
swap            /var/squid/cache        mfs rw,nodev,nosuid,noatime,-s=9236000 0 0

Les options intéressantes sont ici le noatime, et -s.

  • noatime: on n’écrit pas les heures d’accès dans le système de fichier, il est temporaire, c’est donc inutile
  • -s : correspond au nombre de blocs sur le FS. Généralement ce sont des blocs de 512k. Les deux valeurs correspondent ici respectivement à 991M et 4.3G

Montez maintenant les deux systèmes de fichiers:

mount /var/squid/cache
mount /etc/squidguard/blacklists

On va maintenant créer l’arborescence du cache squid et modifier les droits afin d’utiliser le pf transparent:

/usr/local/squid/sbin/squid -f /etc/squid/squid.conf -z
chown root:_squid /dev/pf
chmod 0640 /dev/pf

On va maintenant générer les blacklists de squidGuard. On se base sur celles de l’université de Toulouse:

cd /etc/squidguard/
/usr/local/bin/wget ftp://ftp.univ-tlse1.fr/pub/reseau/cache/squidguard_contrib/blacklists.tar.gz
cd /etc/squidguard/mount/
tar xzf /etc/squidguard/blacklists.tar.gz
chown -R _squid:_squid /etc/squidguard/mount/
/usr/local/bin/squidGuard -b -c /etc/squidguard/squidguard.conf -C all
chown -R _squid:_squid /etc/squidguard/mount/

Après ce procédé, si vous tapez df -h vous devriez voir que vos ramdisk se sont remplis

mfs:185        4.3G    1.0M   4.3G    1%    /var/squid/cache
mfs:754       991M   78.8M    862M     8%    /etc/squidguard/mount

La solution est prête ! Il reste néanmoins une étape subsidiaire, que faire en cas de reboot (tout est perdu) et comment mettre à jour tout cela proprement ?

Je vous propose ce script utilisé depuis un moment en production dans mon laboratoire du CNRS sur notre double gateway Squid:

#! /bin/sh

#
# Functions
#

gen_blacklists() {
        # extraction
        cd /etc/squidguard/mount/
        tar xzf /etc/squidguard/blacklists.tar.gz

        # droits
        chown -R _squid:_squid /etc/squidguard/mount/

        # Generation
        /usr/local/bin/squidGuard -b -c /etc/squidguard/squidguard.conf -C all

        # on reapplique les droits
        chown -R _squid:_squid /etc/squidguard/mount/

        # backup en cas de reboot
        cp -Rp /etc/squidguard/mount/blacklists /etc/squidguard

        /etc/rc.d/squid start
}

# On eteint squid
/etc/rc.d/squid stop

# suppression des données en RAM
rm -R /etc/squidguard/mount/*
/sbin/umount /etc/squidguard/mount
# On attend que les volumes soient démontés
while [ $(df -h|grep /etc/squidguard/mount|wc -l|awk '{print $1}') -gt 1 ];
do
        sleep 1;
        /sbin/umount /etc/squidguard/mount
done

# On remonte le volume
mount /etc/squidguard/mount

# Au boot on ne fait que reprendre le backup
if [ "$1" == "boot" ];
then
        if [ -d /etc/squidguard/blacklists ];
        then
                cp -Rp /etc/squidguard/blacklists /etc/squidguard/mount/
                /etc/rc.d/squid start
        else
                # S'il n'y a pas de backup des blacklists, on va reprendre le tar.gz et les reconstruire
                if [ -f /etc/squidguard/blacklists.tar.gz ];
                then
                        gen_blacklists
                else
                        echo "/!\ Squid cannot be started because no blacklists found"
                fi
        fi
else
        # suppression de l'ancienne backup des blacklists
        if [ -d /etc/squidguard/blacklists ];
        then
                rm -R /etc/squidguard/blacklists
        fi

        # suppression de l'ancienne archive (au cas ou il y aura des doublon on supprime tout)
        rm /etc/squidguard/blacklists.tar.gz*

        # telechargement des BL
        cd /etc/squidguard/
        /usr/local/bin/wget ftp://ftp.univ-tlse1.fr/pub/reseau/cache/squidguard_contrib/blacklists.tar.gz

        gen_blacklists
fi

Ce script exécute 2 tâches, il gère la création complète des blacklists squidGuard et leur mise à jour, mais il fait également un backup de ces blacklists.

Il peut arriver que dans un PRA/PCA votre proxy et vos routeurs matériels tombent. Généralement OpenBSD redémarera plus vite que les routeurs, et il ne pourra pas télécharger les blacklists sur le net, et donc les générer, et squid ne démarrera pas.

Le script réalise un backup des listes générées et les restaure au boot. Si elles n’existent pas il reprend le dernier .tar.gz et refait le processus de génération. Si jamais il n’y a rien, eh bien il ne peut pas démarrer squid. L’utilisation de ce procédé se fait en passant l’argument boot au script

Maintenant on applique le script au démarrage, éditez le fichier /etc/rc.local et ajoutez lignes suivantes:

echo 'Started Squid Proxy Cache Service'
if [ -x /usr/local/squid/sbin/squid ]; then
        umount /var/squid/cache
        mount /var/squid/cache
        /usr/local/squid/sbin/squid -f /etc/squid/squid.conf -z
        chown root:_squid /dev/pf
        chmod 0640 /dev/pf
        /etc/squidguard/squidguard-update.sh boot
fi
echo ''

Editez également le fichier /etc/rc.shutdown afin de rajouter l’extinction propre de squid

echo 'Stopping Squid Proxy Cache Service'
if [ -x /usr/local/sbin/squid ]; then
        /etc/rc.d/squid stop
fi
echo ''

Pour terminer, on rajoute la planification de la mise à jour des blacklists, par exemple le dimanche matin à 5h:

crontab -e
00      5       *     *     6       /etc/squidguard/squidguard-update.sh > /dev/null

Votre proxy-cache est désormais prêt et optimisé !

Note: ces actions sont également réalisables sous FreeBSD et Linux, il faut simplement changer de technologie de ramdisk (mfs), et les chemins des fichiers. OpenBSD reste néanmoins le plus sécurité et performant pour ce type de processus.