world

CentOS 6 – Varnish & MaxMind GeoIP

Posted on 06/03/2012 · Posted in Linux

centosNous allons voir comment déporter le système de géo-localisation IP sur Varnish.
L’objectif final est de permettre à vos backends de récupérer le Pays de l’utilisateur au sein de la requête HTTP.

Par défault, Varnish n’intègre pas de système de géo-localisation par IP, en revanche il existe quelques plugins qui permettent l’utilisation de GeoIP de MaxMind.

Voici les parties de l’article :

  • Installation de Varnish
  • Installation de GeoIP pour Varnish
  • Configuration du Varnish Module
  • Configuration de SELinux

A noter que nous avons opter pour le VMOD Geoip-vmod par leed25d. Contrairement aux autres plugins, celui-ci ne travail pas le header HTTP de manière autonome. Ce sera à vous de le faire, et grâce à cela vous allez pouvoir choisir comment…

Varnish

Pour compiler le VMOD, il vous faudra récupérer les sources de Varnish et les compiler même si vous choisissez l’installation par YUM.
De mon coté, je n’utilise pas en production la version que je compile mais la version provenant du dépot varnish-cache.org. A vous de voir.

Commençons par l’installation de Varnish via YUM (cf. Doc officielle):

1
2
rpm --nosignature -i http://repo.varnish-cache.org/redhat/varnish-3.0/el5/noarch/varnish-release-3.0-1.noarch.rpm
yum install varnish

Pour compiler Varnish nous allons avoir besoin de quelques outils et des sources.

1
2
3
yum install pcre-devel make
cd && curl -o varnish-source.tar.gz http://repo.varnish-cache.org/source/varnish-3.0.2.tar.gz
tar -xvzf varnish-source.tar.gz

On lance la compilation de Varnish.

1
2
3
cd varnish-3.0.2/
./configure
make

Normalement, Varnish a été compilé dans votre repertoire $HOME/varnish-3.0.2/.

GeoIP VMOD

On récupère les sources sur github.

Après l’installation de quelques outils dont GeoIP, on lance la compilation du VMOD.
Attention, pour les version 32Bits utiliser VMODDIR=/usr/lib/varnish/vmods/.

1
2
3
4
5
6
7
yum install unzip automake autoinstall libtool geoip geoip-devel
unzip leed25d-geoip-vmod-[REVISION].zip
cd leed25d-geoip-vmod-[REVISION]
./autogen.sh
./configure VARNISHSRC=$HOME/varnish-3.0.2/ VMODDIR=/usr/lib64/varnish/vmods/
make
make install

Suite à l’installation Varnish, penser à ouvrir votre firewall.

1
2
#/etc/sysconfig/iptables
-A INPUT -m tcp -p tcp --dport 80 -j ACCEPT
1
service iptables restart

De même, il faut configurer Varnish pour écouter sur le port 80 à la place du 6081.

1
2
#/etc/sysconfig/varnish</strong>
VARNISH_LISTEN_PORT=80

Ensuite, on va vérifier que l’on peut lancer Varnish en chargeant le plugin GeoIP.

1
2
3
#/etc/varnish/default.vcl
#Top of file.
import geoip;

On va lancer le processus en debug pour voir si tout se passe bien :

1
2
varnishd -d -f /etc/varnish/default.vcl
start

Si vous n’avez pas d’erreur, c’est une bonne chose. Sinon, vérifier les étapes ci-dessus.

On va donc pouvoir inclure le pays de l’utilisateur dans le Header HTTP en suivant l’exemple de l’auteur du VMOD

1
2
3
4
5
6
7
#/etc/varnish/default.vcl
import geoip;

sub vcl_recv {
    set req.http.X-Forwarded-For = client.ip;
    set req.http.X-GeoIP = geoip.country(req.http.X-Forwarded-For)
}

Maintenant on va pouvoir mettre Varnish en démarrage automatique.

1
2
chkconfig varnish on
service varnish start

Attention:
Sachant que vous êtes sous CentOS, SELinux est surement activé et bloquera l’access au fichier de données /usr/share/GeoIP/GeoIP.dat. Vous pouvez le désactiver ou aller voir à la fin de l’article comment le configurer aux petits oignons.

1
setenforce 0

Et pour finir, un peu de ménage.

1
2
cd && rm -Rf varnish-* && rm -Rf leed25d-*
yum remove pcre-devel make unzip automake autoinstall geoip-devel

Pour aller plus loin

Avec la configuration ci-dessus,
Si un client de France se connecte directement à Varnish, lorsqu’une requête sera générée pour atteindre vos backends elle contiendra : X-GeoIP: FR

Vous pourrez donc récupérer le pays de l’utilisateur en analysant le contenu de la requête HTTP.
Il est à noter que GeoIP retourne le code pays “AA” lorsqu’il ne parvient pas à faire la détection.

Voici comment vous pouvez exploiter le contenu du header en PHP :

1
2
3
4
5
6
7
8
9
10
11
12
$headers = apache_request_headers();
$code = null;

if ($headers && is_array($headers) && array_key_exists("X-GeoIP", $headers)) {
    $code = $headers["X-GeoIP"];
}

if ((null == $code) || ("AA" == $code)) {
    $code = $this->getDefaultCountry();
}

$code = strtoupper($code);

Retournons du coté de Varnish.
Comment les choses vont se passer si vous ajoutez un Proxy en amont de Varnish. Par exemple, Pound pour gérer le protocole HTTPS.

La detection du pays ne fonctionnera plus normalement car la valeur contenu dans le script VCL ‘client.ip‘ correspondra à l’IP de votre serveur Pound.

Nous allons donc devoir travailler avec un autre Header HTTP: X-Forwarded-For. Celui-ci permet de conserver l’historique des différents point de passage d’une requête HTTP et contient l’IP du client qui a initié la connection HTTP.

Lorsque les différents Proxy implementent correctement ce standard, le champs X-Forwarded-For contient l’IP du client, le proxy A, le proxy B, etc.. le tout séparé avec des virgules.

Voici comment en tenir compte au sein de votre configuration VCL :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
sub vcl_recv {
    //...

    if (req.restarts == 0) {
        if (req.http.x-forwarded-for) {
            set req.http.X-Forwarded-For =
            req.http.X-Forwarded-For + ", " + client.ip;
        } else {
            set req.http.X-Forwarded-For = client.ip;
        }
    }

    set req.http.X-GeoIP = geoip.country(regsub (req.http.X-Forwarded-For, "(,.*)", ""));

    //...
}

Maintenant parlons un peu du système de cache de Varnish.
Si vous avez besoin de connaitre le pays de l’utilisateur, il y a donc fort à parier que le contenu retourné à l’utilisateur sera different en fonction de son Pays.

En résumé, pour une URL : /mon-url, en fonction du Pays utilisateur le contenu sera different.
Si on conserve la spécification par défaut de Varnish qui consiste à mettre en cache les données provenant d’une même URL, vous allez avoir quelques mauvaises surprises.

Voici comment tenir compte du pays de l’utilisateur pour gérer les données qui sont mises en cache.

1
2
3
4
5
6
7
8
9
10
sub vcl_hash {
    //...

    hash_data(req.url);
    hash_data(req.http.X-GeoIP);
   
    //...

    return (hash);
}

SELinux

Sous Centos, il y a SELinux.
Si vous n’êtes pas un expert en sécurité Linux. Voici comment faire fonctionner Varnish & GeoIP sans désactiver SELinux.
Le processus Varnish fait parti d’un contexte SELinux different du fichier GetIP.dat qui est installé avec GeoIP.
Du coup, nous allons faire un module pour SELinux afin d’autoriser varnish_t à lire les contextes de type usr_t.

1
2
3
4
mkdir ~/myvarnish; cd ~/myvarnish;
echo "policy_module(myvarnish, 1.0.0) optional_policy(` gen_require(` type varnishd_t; ') files_read_usr_files(varnishd_t) ')" > myvarnish.te
make -f /usr/share/selinux/devel/Makefile myvarnish.pp
semodule -i myvarnish.pp

Pour le coup, cette partie provient d’une discussion avec une personne sur #SELinux on freenode.