Tag - internet

Entries feed

Sunday, December 20 2015

Let's Encrypt et le load-balancer Pound

Pound est un reverse-proxy et un load-balancer libre fort performant. Il est très pratique en frontal d'un ensemble de services web et peut notamment se charger d'effectuer la compression TLS des flux. Il est bien sûr possible de l'utiliser avec Let's Encrypt tel que décrit ici.

Pour ce faire, imaginons que nous venons de lancer la commande suivante :

certbot certonly -a webroot --webroot-path /var/www/mon-site/ -d mondomaine.tld

Un nouveau dossier a été créé : /etc/letsencrypt/live/mondomaine.tld/. Il contient le certificat et également la clé privée utilisée pour ce certificat. Afin que Pound fonctionne, il faut regrouper le certificat et la clé privée dans un même fichier :

cat /etc/letsencrypt/live/mondomaine.tld/fullchain.pem /etc/letsencrypt/live/mondomaine.tld/privkey.pem > /etc/letsencrypt/live/mondomaine.tld/total.pem

et il faut alors référencer le fichier total.pem dans la configuration de Pound :

ListenHTTPS
	Address 2001:2002:2003:2004::
        Port    443
	Cert	    "/etc/letsencrypt/live/mondomaine.tld/total.pem"

et il ne reste plus qu'à redémarrer Pound par :

service pound restart

Saturday, December 19 2015

Utiliser Let’s Encrypt avec ownCloud/Nextcloud, Piwik, Dotclear, Drupal, Wordpress, des applications Rails et des sites statiques !

Depuis le début du mois, il est possible d'utiliser "Let's Encrypt" pour obtenir des certificats TLS/SSL pour sécuriser ses sites et services en ligne (bien que le système soit toujours annoncé en bêta). Ce matin, je décidais donc de m'y mettre et de remplacer mes certificats StartSSL.

Depuis Mai 2016, le service Let's Encrypt n'est plus en bêta et les limitations de la bêta évoquées ici ne sont plus mordantes !

Depuis Mai 2016, le client letsencrypt est devenu certbot (https://certbot.eff.org/) ! les commandes évoquées plus bas sont sans doute valables en remplaçant letsencrypt-auto par certbot !

Première étape : comprendre le fonctionnement

Le principe est assez simple et n'est pas très différent de celui déjà rencontré pour l'obtention de certificats auprès des opérateurs "classiques" (les StartSSL et consors). Classiquement, (i) on démontre la possession réelle du nom de domaine, (ii) on génère une clé privée et une clé publique et on transmet la clé publique à l'opérateur de certification qui (iii) fournit en retour un certificat attestant le lien entre le nom de domaine et la paire de clés crypto utilisées pour l'établissement de communications sécurisées. Avec Letsencrypt, ces étapes ont lieu mais automatiquement. Dans l'utilisation commune, Letsencrypt vient avec un script Python (letsencrypt-auto) qui va faire tout le travail :

  • le script va créer un fichier mondomaine.tld/.well-known/acme-challenge/chaîne-choisie-au-hasard et le serveur distant cherchera à accéder à ce fichier pour authentifier la possession/maîtrise du domaine mondomaine.tld
  • puis le script génère et échange les clés cryptographiques avec l'autorité de certification Letsencrypt
  • et le certificat est rapatrié
  • enfin, dans certains cas, le script se charge même de l'installer !

Par rapport à ce qui est fourni habituellement par les acteurs privés :

  • la chaîne de bout en bout est plus transparente et libre
  • le certificat est gratuit
  • le certificat n'a une validité que de 90 jours (mais le renouvellement est gratuit et peut être géré automatiquement par le script tous les 2 mois par exemple)
  • les certificats n'autorisent pas les wildcards (e.g. *.mondomaine.tld) ce qui a déjà été fort amplement débattu partout sur le web mais ne semble pas devoir changer.

Deuxième étape : installer Let’s Encrypt

Nous allons commencer par le cas simple d'un site statique. Le script letsencrypt se télécharge sur la machine d'hébergement à l'aide de git :

git clone https://github.com/letsencrypt/letsencrypt
cd letsencrypt

puis on peut lancer le script (qui va effectuer les installations supplémentaires nécessaires) par :

./letsencrypt-auto

Cela fonctionne très bien sur Debian Jessie et sans doute les autres systèmes récents (c'est la version de Python qui semble être un des facteurs limitants pour les "vieilles" distributions). On reviendra sur ce point plus loin.

Troisième étape : utiliser Let’s Encrypt pour un site statique

Commençons par le cas simple d'un site statique hébergé dans /var/www/mon-site/ et servi par Apache.

./letsencrypt-auto certonly -a webroot --webroot-path /var/www/mon-site/ -d mondomaine.tld

certonly car nous demandons à Let’s Encrypt de générer le certificat et de s'arrêter là (donc de ne pas l'installer lui-même). -a webroot car nous indiquons à Let’s Encrypt où se trouve la racine du site afin qu'il puisse y placer le fichier de "challenge" (.well-known/acme-challenge/chaîne-choisie-au-hasard). Et -d mondomaine.tld pour indiquer le domaine. Il est possible d'indiquer plusieurs domaines s'ils partagent le même webroot par exemple :

./letsencrypt-auto certonly -a webroot --webroot-path /var/www/mon-site/ -d mondomaine.tld -d www.mondomaine.tld

Dans ce cas le certificat contiendra les 2 domaines en SAN (Subject Alternative Names).

Au premier lancement, le script demande de saisir l'adresse courriel qui sera rattachée au compte (et qui recevra les éventuelles notifications de péremption des domaines non renouvelés).

Et hop, le script travaille et un certificat tout neuf (et valide !) est déposé dans /etc/letsencrypt/live/mondomaine.tld/fullchain.pem. La clé privée correspondante se trouve dans /etc/letsencrypt/live/mondomaine.tld/privkey.pem. Ce certificat peut alors être utilisé comme il l'a toujours été (par ex. appelé dans la configuration d'Apache ou de votre load balancer) - je détaille ici comment l'utiliser avec le load balancer Pound.

Let’s Encrypt et un blog dotclear

Aucune surprise ni difficulté avec dotclear :

./letsencrypt-auto certonly -a webroot --webroot-path /chemin/vers/blog/dotclear -d blog.bandinelli.net

et hop, /etc/letsencrypt/live/blog.bandinelli.net/fullchain.pem est créé ! Une commande pour un certificat, c'est classe et pratique !

Let’s Encrypt et Piwik

Aucune surprise ni difficulté avec Piwik :

./letsencrypt-auto certonly -a webroot --webroot-path /chemin/vers/racine/piwik -d piwik.mondomaine.tld

et hop, /etc/letsencrypt/live/piwik.mondomaine.tld/fullchain.pem est créé !

Let’s Encrypt et Wordpress

Aucune surprise ni difficulté avec Wordpress :

./letsencrypt-auto certonly -a webroot --webroot-path /chemin/vers/racine/wordpress -d mondomaine.tld

et hop, /etc/letsencrypt/live/mondomaine.tld/fullchain.pem est créé !

Let’s Encrypt et Drupal 7

Une petite astuce est nécessaire ici : par défaut le moteur de Drupal demande au serveur web de réécrire toutes les adresses et empêche l'accès à certaines adresses. Ainsi, le fichier .htaccess se trouvant à la racine d'un site Drupal contient la ligne suivante :

RewriteRule "(^|/)\." - [F]

Cette ligne ordonne à Apache de renvoyer vers la page "Accès interdit" toute requête qui débuterait par ".". Il faut bien évidemment désactiver cette sécurité pour Letsencrypt :

RewriteCond %{REQUEST_URI} !^/.well-known/acme-challenge/.*
RewriteRule "(^|/)\." - [F]

La condition RewriteCond désactive la redirection qui suit pour le challenge de letsencrypt seulement.

Une fois cela effectué, on peut utiliser la commande classique pour obtenir le certificat valide dans /etc/letsencrypt/live/mondomaine.tld/fullchain.pem :

./letsencrypt-auto certonly -a webroot --webroot-path /chemin/vers/site/drupal/ -d mondomaine.tld

Let’s Encrypt et ownCloud/Nextcloud

Une petite astuce est nécessaire ici : par défaut le moteur d'ownCloud demande au serveur web de réécrire toutes les adresses et empêche l'accès à certaines adresses. Ainsi, le fichier .htaccess se trouvant à la racine d'une instance ownCloud/Nextcloud contient la ligne suivante :

RewriteRule ^(\.|autotest|occ|issue|indie|db_|console).* - [R=404,L]

elle renvoie vers 404 tous les appels à un chemin démarrant par ".". Il est bien sûr nécessaire de désactiver cette ligne conditionnellement :

RewriteCond %{REQUEST_URI} !^/.well-known/acme-challenge/.*
RewriteRule ^(\.|autotest|occ|issue|indie|db_|console).* - [R=404,L]

Ensuite, sans surprise, pour obtenir le certificat valide dans /etc/letsencrypt/live/mondomainecloud.tld/fullchain.pem :

./letsencrypt-auto certonly -a webroot --webroot-path /chemin/vers/owncloud/ -d mondomainecloud.tld

Let’s Encrypt et une application Ruby on Rails

Aucune surprise ni difficulté avec une application Ruby on Rails servie en production par Unicorn, à condition de bien choisir le dossier public comme webroot :

./letsencrypt-auto certonly -a webroot --webroot-path /chemin/vers/application/public -d domaine.tld

et hop, /etc/letsencrypt/live/domaine.tld/fullchain.pem est créé !

Let’s Encrypt sur une vieille distribution ?

Si Let's Encrypt ne peut être lancé sur votre machine de production car elle dispose de versions trop anciennes des fichiers, rien n'est perdu ! Il est en effet possible de fournir au script un webroot qui serait par exemple partagé via SSH ! Par exemple :

apt install sshfs
mkdir /mnt/webroot-distant
sshfs user@machine:/path/to/webroot /mnt/webroot-distant
./letsencrypt-auto certonly -a webroot --webroot-path /mnt/webroot-distant -d mondomaine.tld

Conclusion

Très efficace et rapide, comment ne pas tomber sous le charme de Letsencrypt ? Il reste à valider : la procédure de renouvellement et la pérennité dans le temps de la structure. Pour y aider, on peut toujours faire un petit don sur la page d'accueil de Let’s Encrypt !

Friday, July 10 2015

Routeur avec Tomato, Fibre Orange, VLAN 835

Comme déjà exposé ici, il est possible de se passer de la Livebox d'Orange et d'avantageusement la remplacer par un routeur "évolué" muni du micrologiciel Tomato.

Dans le précédent article, je détaillais le mode opératoire avec le routeur Asus RT-N16. J'ai eu l'occasion dernièrement de répéter l'opération avec l'Asus RT-N18U. Le nouveau mode opératoire est très similaire sauf qu'il ne faut pas utiliser de VID offset pour que cela fonctionne :

Paramétrage PPPoE pour le WAN

Dans l'onglet principal de Tomato, on choisit une connexion PPPoE pour le WAN et on saisit le nom d'utilisateur 'fti/xxxxx' et le mot de passe pour la connexion.

Puis on bascule le WAN dans le VLAN 835

Il faut alors se rendre dans les options avancées, catégorie VLAN.

  • On sélectionne la ligne correspondant au VLAN du WAN et on on saisit 835 comme VID.
  • Il ne faut pas oublier également de cocher la case 'Tagged' pour demander au retour de bien prendre en compte le trafic 'marqué' comme appartenant au VLAN 835.

vlan835-asus-rt-n18u.png

Et voilà le tour est joué. On sauvegarde, le routeur inscrit ces paramètres dans sa nvram et redémarre. On voit que le WAN PPPoE parvient à se connecter à internet et le routeur distribue internet à tous les postes du réseau qui le référencent comme passerelle.

Firmware Tomato (by Shibby) sur Asus RT-N18U

J'ai déjà parlé à plusieurs reprises dans ces pages du micrologiciel Tomato pour les routeurs. J'ai récemment acquis un routeur Asus RT-N18U et me suis empressé d'installer Tomato dessus.

Pour ce faire,

  • on télécharge d'abord la version ARM du firmware ici : http://tomato.groov.pl/download/K26ARM/
  • on extrait le fichier .trx de l'archive
  • on allume le routeur Asus RT-N18U (encore équipé de son micrologiciel natif) et on se rend dans "Administration", "Mise à jour du firmware". On sélectionne alors le fichier .trx de Tomato et on laisse le processus de mise à jour se faire
  • une fois le routeur redémarré, on effectue un "factory reset" avec le bouton dédié pour vider la mémoire des paramètres non adéquats (liés au micrologiciel natif)
  • et hop le tour est joué, on peut alors se connecter au micrologiciel Tomato et enfin profiter de toute la puissance du routeur

Tomato semble fonctionner sans difficulté sur ce matériel - qui, dans mes tests initiaux, a été très performant. A recommander donc !

Monday, November 10 2014

Obtenir une bonne note chez SSLLabs avec Pound

J'utilise Pound dans mon infrastructure, notamment pour sa capacité d'assurer tout le chiffrement en SSL/TLS entre mes serveurs et les clients.

Cependant, la version stable de Pound dans Debian Wheezy n'est pas patchée pour écarter les récentes "attaques" sur SSL/TLS à commencer par la corruption de SSLv3 (faille baptisée Poodle).

Si la version 2.7, la prochaine stable, disposera de tous les derniers raffinements, seule une branche non officielle pourra satisfaire le plus scrupuleux adminsys. Cette branche non officielle est maintenue par Joe Gooch (qu'il soit permis ici de le remercier !) et est disponible ici : https://github.com/goochjj/pound/tree/pcidss/v2.6.

Voici comment Joe décrit cette branche :

The other is called pcidss/v2.6, which is Pound 2.6, plus cipher and protocol patches necessary (initially) to pass PCI compliance, and as part of that is the directive to disable SSL3.

Compiler Pound 2.6-pcidss

  • Télécharger la dernière version ici : https://github.com/goochjj/pound/archive/pcidss/v2.6.zip
  • Dé-zipper l'archive et se rendre dans le dossier
  • Réaliser ensuite la compilation (le système devra bien sûr comporter tout le nécessaire à cela : gcc, build-essentials, libssl-dev...) :
./configure
make
make install
  • dans Debian, il semble que pound 2.6-pcidss s'installe dans /usr/local/sbin/pound alors que le paquet original l'installe dans /usr/sbin/pound. On peut donc remplacer l'ancienne version par la nouvelle et vérifier que l'utilitaire par défaut correspond bien à la nouvelle version :
pound -V

qui doit retourner 2.6-pcidss.

  • on peut alors modifier la configuration de Pound avec ces paramètres :
	DisableSSLv2
	DisableSSLv3

	Ciphers "EECDH+ECDSA+AESGCM:EECDH+aRSA+AESGCM:EECDH+ECDSA+SHA384:EECDH+ECDSA+SHA256:EECDH+aRSA+SHA384:EECDH+aRSA+SHA256:EECDH:EDH+aRSA:-RC4:EECDH+aRSA+RC4:EECDH+RC4:EDH+aRSA+RC4:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS:RC4+SHA"
    	SSLHonorCipherOrder 1
	SSLAllowClientRenegotiation     0
  • et redémarrer Pound

Normalement, vous devriez désormais disposer d'un chiffrement SSL de qualité susceptible de vous faire obtenir un A (yes!) sur https://www.ssllabs.com/ssltest/ (si votre certificat est de bonne qualité - SSLLabs disqualifie tout de suite tout certificat auto-signé !).

StartSSL pour des certificats SSL "wildcard" à petit prix

Disposant de plusieurs domaines pour mes activités personnelles et professionnelles, j'utilisais jusqu'ici des certificats auto-signés pour sécuriser mes connexions avec SSL/TLS. Cependant, habituer l'utilisateur à "ajouter une exception de sécurité" sans réfléchir me déplaisait au plus haut point. J'ai donc finalement, poussé aussi par mon beau-frère, mis en place de jolis certificats validés par StartCom Ltd. (StartSSL).

Les tarifs pratiqués par StartCom Ltd./StartSSL sont beaucoup plus doux que ceux pratiqués par d'autres acteurs du domaine. Chez eux, on paye en effet le processus de validation d'identité mais ensuite l'émission des certificats est gratuite. Voilà qui est tout à fait intéressant et économique pour couvrir plusieurs domaines !

Ouvrir un compte chez StartSSL

La première étape consiste à se connecter sur http://startssl.com et à choisir "Sign-up" pour ouvrir un nouveau compte. On saisit ses informations personnelles (il faut qu'elles soient exactes si l'on prévoit de faire valider son identité !) puis le site installe automatiquement dans le navigateur un certificat/clé qui autorise ce seul navigateur à se connecter au site. Une bonne pratique consistera à sauvegarder de manière sûre ce certificat pour conserver l'accès au site StartSSL !

Profiter des certificats de niveau 1

Sans rien payer, il est alors possible de faire valider un domaine via le 'Validations Wizard' (la validation d'un domaine consiste à recevoir un courriel envoyé par exemple à postmaster@le-domaine-en-question.fr et à saisir le code de validation reçu) puis de créer des certificats de niveau 1.

Les certificats de niveau 1 sont une bonne base pour débuter mais il n'est notamment pas possible avec ce niveau de disposer de certificats "wildcard" (i.e. pour tous les sous-domaines d'un domaine). Pour bénéficier de cette fonctionnalité, il faut disposer d'un niveau 2.

Obtenir le niveau 2

Pour passer niveau 2, il faut d'une part :

  • soumettre des documents pour prouver son identité (photocopies de 2 pièces d'identité, éventuellement justificatif de domicile, éventuellement recevoir un appel de StartSSL sur son numéro de téléphone)
  • s'acquitter de la somme de 59,90$ (environ 48 euros)

Tout le processus s'effectue en ligne via le 'Validations Wizard', catégorie 'Personal identity validation'. Les gens de StartCom StartSSL sont extrêmement réactifs.

Dans mon cas, après quelques heures et quelques échanges par courriel et téléphone, mon identité a été vérifiée et mon niveau 2 validé.

Créer un certificat 'wildcard'

Une fois niveau 2, voici la marche à suivre :

  • sur le serveur que l'on souhaite protéger, nous allons générer une clé privée et un Certificate Sining Request (CSR) par la commande
openssl req -nodes -newkey rsa:4096 -sha256 -keyout cle-privee.key -out serveur.csr

Il est à noter que ce processus génère une clé privée sans mot de passe. Il est tout à fait possible de générer une clé avec mot de passe mais il faudra alors préciser le mot de passe correspondant aux logiciels serveurs qui utiliseront la clé pour crypter les échanges.

Au cours du processus, OpenSSL va demander quelques informations d'identité. Il est important de préciser dans le champ 'Common Name' le nom d'hôte à protéger : en l'occurrence *.le-domaine-en-question.fr si l'on souhaite bénéficier d'un certificat 'wildcard' pour le-domaine-en-question.fr.

Country Name (2 letter code) [AU]: FR
State or Province Name (full name) [Some-State]: Ile-de-France
Locality Name (eg, city) []: Mary-sur-Marne
Organization Name (eg, company) [Internet Widgits Pty Ltd]: MaSociété
Organizational Unit Name (eg, section) []: 
Common Name (eg, YOUR name) []: *.le-domaine-en-question.fr
Email Address []: postmaster@le-domaine-en-question.fr
A challenge password []: 
An optional company name []:
  • on peut alors afficher le contenu du CSR par
cat serveur.csr

et le conserver précieusement

  • de retour sur le site de StartSSL, se rendre dans le 'Certificates wizard'
  • choisir 'Webserver SSL/TLS certificate'
  • passer (bouton SKIP) l'étape de génération d'une clé privée puisque nous avons créé nous-même notre clé privée sur le serveur
  • copier alors le contenu du CSR dans le champ texte
  • sélectionner le domaine à protéger : seuls les domaines déjà validés peuvent être utilisés. On pourra par exemple saisir *.le-domaine-en-question.fr.
  • et voilà le certificat qui apparaît à l'écran. Il convient de copier ce certificat précieusement, par exemple dans un fichier wildcard.le-domaine-en-question.fr.crt.

Utiliser son tout nouveau certificat

Cette étape dépend ensuite du serveur utilisé (Apache, Pound, Nginx, ...). La plupart du temps, on regroupera le certificat obtenu de la part de l'autorité de certification et la clé privée dans un même fichier .pem. On pourra également inclure les certificats intermédiaires de l'autorité : https://www.startssl.com/certs/ca.pem et https://www.startssl.com/certs/sub.class2.server.ca.pem.

cat wildcard.le-domaine-en-question.fr.crt cle-privee.key ca.pem sub.class2.server.ca.pem > wildcard.le-domaine-en-question.pem

On pourra alors utiliser ce .pem sur son serveur, en s'assurant toutefois de bien le garder secret, car il contient notre clé privée !

Bon courage pour votre génération de certificats !

Sunday, March 23 2014

L'importance du paramètre TimeOut dans Pound

Pound est un reverse-proxy et un load-balancer libre fort perfomant. Il faut toutefois savoir que par défaut Pound n'attend pas plus de 15 secondes la réponse du serveur sous-jacent avant de retourner une erreur : "An internal server error occurred. Please try again later". Un 'timeout' de 15 secondes est suffisant pour de nombreux cas - cependant certaines requêtes sont parfois plus longues par exemple quand il s'agit de déclencher des requêtes importantes sur des bases de données, de lancer le téléchargement d'une grosse archive dans ownCloud ou de toute autre opération susceptible de prendre plus de 15 secondes à un serveur (notamment quand celui-ci est fortement sollicité par ailleurs).

Il est dès lors possible d'augmenter la durée du 'TimeOut' en ajoutant cette ligne :

  • soit dans la configuration globale de pound
  • soit dans la définitiond d'un 'backend' spécifique
TimeOut 150

Si 150 secondes n'est pas adapté, on modifie bien sûr la valeur.

Voilà qui devrait faire disparaître la plupart des erreurs "An internal server error occurred. Please try again later" !

Friday, October 18 2013

Votre service est-il en ligne ou hors ligne ? Le savoir sans délai avec Monit.

La grande frousse pour de nombreux administrateurs (enfin j'imagine), c'est la panne d'un système critique (généralement un samedi matin) qui passe inaperçue... Je vais vous présenter ici le petit utilitaire 'monit' qui, tout simplement, vous permettra de recevoir des notifications en cas de panne d'un de vos services. Et d'effectuer un ensemble de réactions ! C'est très certainement l'allié indispensable aux côtés de Munin que je présentais dernièrement !

Monit (à ne pas confondre avec M/Monit qui est son grand-frère non libre) est un ingénieux petit logiciel auquel on donne des missions de surveillance et des actions à effectuer lorsque certains comportements sont constatés. Je ne résiste pas à la tentation de recopier ici la bannière trouvée sur le site de monit : Monit, barking at daemons!

Un cas typique d'utilisation est le suivant : vous avez un processus P qui doit tourner sur votre machine mais que vous craignez voir s'arrêter... Vous pouvez demander à monit de vérifier toutes les X minutes que ce processus tourne toujours et le redémarrer si monit le trouve éteint. Dans ce cas, vous exécuterez monit sur le serveur qui propulse le processus à surveiller.

Autre scénario : votre serveur HTTP tourne sur l'adresse 2000:aaaa:bbbb:: et le port 80 et vous voulez vous assurer qu'il est toujours joignable. Monit peut se connecter à cette IP (ping) et dialoguer avec le service (voire même effectuer des requêtes HTTP complètes et évaluer la réponse) pour déterminer s'il est vivant. Et cela peut également fonctionner pour surveiller un FTP, un IMAP, un serveur OpenVPN... Dans ce cas, on hébergera monit sur le serveur local ou bien à distance si l'on souhaite également détecter une perte de connectivité (attention toutefois au cas de la coupure du serveur chargé de la surveillance !).

Et Monit permet bien plus encore : vérifier la présence d'un fichier, vérifier les droits sur un dossier, vérifier que la charge CPU ou la mémoire vive n'ont pas éteint des niveaux trop élevés et agir si nécessaire... Monit voit et agit !

L'installation de monit s'effectue (sous Debian) par un classique :

aptitude install monit

Pour le paramétrage, on parcourra d'abord /etc/monit/monitrc :

# Vérifier l'état des services toutes les 2 minutes
set daemon 120
# Raconter le quotidien dans un fichier
set logfile /var/log/monit.log
# Communiquer avec l'ami SMTP pour envoyer des courriels d'alerte
set mailserver monsmtp.domain.tld username "Moi" password "MonMDP" using tlsv1
# Choisir l'expéditeur de son choix quand Monit nous parle
set mail-format { from: monit@monserveur.domain.tld }
# Choisir à qui les alertes sont envoyées
set alert mon@courriel.fr
# Inclure les éléments de configuration compris dans /etc/monit/conf.d/
include /etc/monit/conf.d/*

On pourra s'occuper du ménage concernant le fichier de log (/var/log/monit.log) à l'aide de logrotate comme expliqué ici (section 'envie de rotation?').

Entrons alors dans le vif du paramétrage...

check host monsite.domain.tld with address a.b.c.d
 if failed icmp type echo count 3 with timeout 3 seconds then alert
 if failed port 80 protocol http with timeout 15 seconds then alert
 if failed port 1194 type udp with timeout 15 seconds then alert

La routine ci-dessous ne fait qu'envoyer des alertes : (i) si le serveur ne répond plus au ping, (ii) si un serveur web ne répond plus sur le port 80 et (iii) si un service ne répond pas en UDP sur le port 1194 (OpenVPN par exemple). Monit exécute chaque test les uns après les autres. Lorsqu'un test échoue au sein d'un groupe alors les tests suivants ne sont pas effectués. Monit envoie automatiquement un message lorsque le service est perdu et prévient également (c'est bien aimable de sa part) quand le service est rétabli.

Plus ardu :

check process apache with pidfile /usr/local/apache/logs/httpd.pid
  start program = "/etc/init.d/httpd start" with timeout 60 seconds
  stop program  = "/etc/init.d/httpd stop"
  if cpu > 60% for 2 cycles then alert
  if cpu > 80% for 5 cycles then restart
  if totalmem > 200.0 MB for 5 cycles then restart
  if children > 250 then restart
  if loadavg(5min) greater than 10 for 8 cycles then stop
  if failed host www.tildeslash.com port 80 protocol http
      and request "/somefile.html"
      then restart
  if failed port 443 type tcpssl protocol http
     with timeout 15 seconds
     then restart
  if 3 restarts within 5 cycles then timeout
  depends on apache_bin
  group server

Le script ci-dessous adopte le comportement suivant :

  • une alerte est émise sur la charge CPU est supérieure à 60% au cours de 2 vérifications successives
  • le serveur Apache est redémarré si la charge CPU est supérieure à 80% au cours de 5 vérifications successives
  • le serveur Apache est redémarré si la mémoire consommée est supérieure à 200 MB au cours de 5 vérifications successives
  • le serveur Apache est redémarré si plus de 250 processus fils sont détectés
  • le serveur Apache est stoppé (pas redémarré) si la charge est supérieure à 10 pendant 8 vérifications
  • le serveur Apache est redémarré si l'hôte www.tildeslash.com ou l'appel du fichier somefile.html échouent
  • le serveur Apache est redémarré si l'accès en HTTPS n'est pas disponible
  • et enfin si 3 redémarrages sont constatés en 5 cycles alors on passe à une alerte de niveau supérieur (timeout)

Je ne couvre ici qu'une faible part des possibles et je vous invite à explorer ! Un superbe outil à mettre dans toutes les mains !

Friday, October 11 2013

Reverse IPv6 avec DNSMasq, chez Online.net

Comme raconté ici, le postmaster de Google a adopté une position très stricte de rejet de tout courriel provenant d'un serveur SMTP se connectant en IPv6 mais ne disposant pas de champ 'reverse' concordant.

On peut déplorer cette très grande rigidité et s'en étonner, surtout dans une période d'adoption progressive de l'IPv6. Pour ceux dont le fournisseur d'accès (plus précisément le fournisseur de votre bloc d'adresses IPv6) ne donne aucun moyen d'avoir un 'reverse', une solution temporaire est proposée ici : connexion en IPv4 à Google.

Dans le cas d'Online.net, la possibilité d'une délégation DNS est apparue récemment en production. Elle permet d'indiquer à quel serveur DNS se raccrocher pour effectuer la translation de nom inverse (i.e. d'adresse IP vers nom de domaine) pour les adresses du bloc.

Etape 1 : disposer d'un serveur DNS capable de répondre aux requêtes "reverse"

La grande référence du DNS est bind, mais on peut également monter ce petit service en moins de 10 lignes de configuration avec DNSMasq (dont je parlais déjà ici).

On installe dnsmasq par

aptitude install dnsmasq

et voici un exemple de configuration complète :

log-facility=/var/log/dnsmasq.log
log-queries
no-resolv
no-hosts
ptr-record=0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.0.h.g.f.e.d.c.b.a.1.0.0.2.ip6.arpa,monreverse1.domain.tld
ptr-record=1.0.1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.0.h.g.f.e.d.c.b.a.1.0.0.2.ip6.arpa,monreverse2.domain.tld

Les paramètres log-facility et log-queries indiquent que l'on souhaite garder une trace de toutes les requêtes DNS dans /var/log/dnsmasq.log

no-resolv et no-host ainsi que l'absence de paramètre server indiquent que l'on ne souhaite répondre positivement qu'aux requêtes correspondant à l'un des enregistrements mentionnés dans le fichier de configuration.

Et enfin, sont indiqués les 2 enregistrements PTR qui correspondent à 2 adresse IPv6 pour lesquelles on souhaite avoir un reverse IPv6.

La première adresse est 2001:abcd:efgh:100:: et la seconde est 2001:abcd:efgh:100::101. On voit que l'adresse est mentionnée dans l'enregistrement PTR en l'écrivant "à l'envers" et en séparant chaque caractère (y compris les 0 que la convention nous permet de ne pas faire apparaître dans les adresses IPv6) par un point.

Etape 2 :

On rend ce serveur DNS très simple (et capable de ne répondre qu'à ces 2 requêtes reverse IPv6) accessible à l'adresse dns.domain.tld. Si on est placé derrière un firewall, on n'oubliera pas d'ouvrir le port 53 en TCP et en UDP.

Etape 3 : paramétrer la délégation DNS chez le fournisseur du bloc IPv6

Cette étape diffère selon le fournisseur du bloc IPv6. Chez Online, il faut se rendre dans la console, onglet "Serveur" puis "Paramétrage du réseau". On choisit le bloc IPv6 de son choix et on clique sur l'option "Paramétrer la délégation DNS". On saisit alors l'adresse du serveur DNS capable de répondre aux éventuelles requêtes reverse IPv6.

Délégation DNS chez Online

Etape 4 : on peut à nouveau écrire aux destinataires de GMail

Si on expédie un message à un destinataire @gmail.com, quelques secondes plus tard, on voit apparaître dans les logs la requête DNS suivante :

Oct 6 14:04:59 dnsmasq[21288]: query[PTR] 
1.0.1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.0.h.g.f.e.d.c.b.a.1.0.0.2.ip6.arpa **from 74.125.18.211**

74.125.18.211 est une adresse (IPv4 !) de Google qui vient s'enquérir du reverse IPv6. Et le courriel est expédié sans encombre !

Bons paramétrages de reverse IPv6 à tous !

Tuesday, September 10 2013

Partager un fichier, le faire disparaître après partage et savoir (approximativement) qui l'a téléchargé

J'utilise souvent demo.ovh.eu (le service de partage mis en place par OVH, qui, contrairement à beaucoup d'autres, n'oblige pas à visualiser des publicités) pour partager aisément des fichiers sur internet. Toutefois, je souhaiterais parfois que le fichier soit effacé après téléchargement et savoir quand celui-ci a été téléchargé. Certains services proposent sans doute cela et l'outil Jyraphe (dont le développement est stoppé ?) le permet. Je vous propose toutefois une solution maison toute simple à mettre en place et extrêmement simpliste à déployer sur serveur web + PHP !

Soit le fichier mon_archive.7z à proposer au téléchargement. Soit /var/www/ la racine du serveur web accessible sur le net. On place le fichier mon_archive.7z dans un dossier /var/www/hidden/ qu'un fichier .htaccess protège de toute ouverture. On place ensuite le code suivant dans un fichier /var/www/telechargement-ici_chaîne_unique_non_devinable.php :

<?php
    $yourfile = "hidden/mon_archive.7z";

    if (file_exists($yourfile)) {
        $file_name = basename($yourfile);

        header("Content-Type: application/zip");
        header("Content-Disposition: attachment; filename=$file_name");
        header("Content-Length: " . filesize($yourfile));

        readfile($yourfile);
        unlink($yourfile);
        if (file_exists($yourfile)) {
            mail('moi@courriel.fr', 'Fichier téléchargé mais pas supprimé !', 'Le fichier "'.$file_name.'" a bien été téléchargé par '.$_SERVER["REMOTE_ADDR"].' et n\'a pas été supprimé.');
        }
        else {
            mail('moi@courriel.fr', 'Fichier téléchargé et supprimé !', 'Le fichier "'.$file_name.'" a bien été téléchargé par '.$_SERVER["REMOTE_ADDR"].' et a été supprimé.');
        }
    }
    else {
        print "Unknown file...";
        mail('moi@courriel.fr', 'Tentative de téléchargement infructueuse.', 'Qqn ('.$_SERVER["REMOTE_ADDR"].') a tenté en vain de télécharger le fichier "'.$yourfile.'".');
    }
    exit;
?>

Le fichier php propose donc le fichier au téléchargement quand l'utilisateur appelle https://monserveur/telechargement-1g2j0a7j8.php puis l'efface du serveur et vous préviens (par courriel) que le téléchargement a eu lieu. Il enregistre également l'adresse IP de la personne qui a effectué le téléchargement (certes, c'est très approximatif comme identification). Le mot de passe est en fait la chaîne arbitrairement complexe et longue placée dans l'URL pour accéder au fichier .php permettant le téléchargement.

On pourrait améliorer encore la sécurité en récupérant le mot de passe (la chaîne arbitraire) dans un paramètre GET (?pass=1g2j0a7j8 par exemple) et bannir une IP qui ferait plus de 3 ou 4 tentatives d'accès infructueuses.

Le cahier des charges est respecté, ce n'est pas tout à fait automatique mais ça ne devrait pas être trop difficile à scripter si vous avez de nombreux fichiers de la sorte à mettre à disposition. Et surtout, votre archive (peut-être très confidentielle) ne transite pas sur un serveur tierce.

Thursday, June 6 2013

"Stress test" pour une application Web - cas pratique sur Raspberry

Ceux qui auront lu mon précédent article ne seront pas étonnés si j'annonce que j'ai tout récemment déployé une application web (Zend Framework 1 + Doctrine 2 + PHP5 + MySQL) sur un (petit - euh... enfin normalement petit) Raspberry Pi (modèle B). Toutefois, je décidai d'étudier plus avant le système mis en place en le soumettant à un 'stress test' simulant un fort afflux d'utilisateurs effectuant diverses requêtes au sein de l'application.

Les applications de 'stress test' ne manquent pas et j'avais déjà entendu parler de JMeter et Tsung. Mais pour ce test, je décidai d'utiliser Gatling : logo-Gatling-StressTool.png

Gatling (open source, disponible sur http://gatling-tool.org/) est codé en Scala et s'exécute sans difficulté dans un environnement disposant d'une machine virtuelle Java. Pas d'installation nécessaire : on décompresse l'archive et les binaires de l'application sont disponibles dans /bin/.

Mise en place d'un scénario de stress : à la main...

Les scénarios de test de Scala sont à créer et placer dans /user-files/simulations dans des fichiers scala. La structure de base d'un fichier est la suivante :

import com.excilys.ebi.gatling.core.Predef._
import com.excilys.ebi.gatling.http.Predef._
import com.excilys.ebi.gatling.jdbc.Predef._
import Headers._
import akka.util.duration._
import bootstrap._
import assertions._

class SimulationWithFollowRedirect extends Simulation {
  val scn = scenario("My scenario")
            .exec(http("My Page")
              .get("http://mywebsite.com/page.html"))
  
  setUp(scn.users(1))
}

Il est donc possible en Scala de coder la liste des actions qu'effectueront les utilisateurs virtuels (des requêtes GET, des requêtes POST, le lancement de certaines routines PHP...). A la fin du fichier, la simulation est lancée par

  setUp(scn.users(x))

où x (entier naturel strictement positif) représentera le nombre d'utilisateurs qui seront simulés concurremment sur l'application.

Mise en place d'un scénario de stress : en automatique pour aller plus vite !

L'écriture du scénario "à la main" est très souple mais un petit peu complexe. Il existe donc un petit utilitaire (recorder) particulièrement pratique qui peut venir à notre rescousse. Il s'agit d'une application qui vient se positionner comme un proxy sur le navigateur web et qui enregistre toutes les opérations effectuées par le navigateur directement sous la forme d'un fichier Simulation.scala utilisable par Gatling.

Le 'recorder' se lance par :

sh bin/recorder.sh

Si les ports du proxy (HTTP/HTTPS, spécifiés en haut à gauche) conviennent, on clique sur 'Start' et désormais l'application enregistrera tout mouvement réalisé au travers du proxy.

Gatling-recorder.png

Une fois l'enregistrement terminé, on peut bien sûr modifier le scénario de simulation (suppression des pauses non nécessaires, suppression de certaines étapes...) en éditant le fichier MaSimulationDuJour.scala qui aura été créé dans /user-files/simulations. On peut notamment augmenter le nombre d'utilisateurs qui seront simulés :

  setUp(scn.users(100))

et on peut simuler une montée en charge progressive par la commande finale :

  setUp(scn.users(100).ramp(200)

qui signifie que 100 utilisateurs se connecteront progressivement pendant 200 secondes (soit 1 nouvel utilisateur toutes les 2 secondes). Bien sûr, si votre serveur répond bien et que la durée de simulation est courte alors il est possible que vous n'ayez jamais 100 utilisateurs connectés en même temps (car une fois que l'utilisateur simulé a terminé toutes les étapes alors il se déconnecte à moins que vous ne paramétriez des boucles). Le rapport d'analyse (cf. infra) vous permettra de bien visualiser ce phénomène.

Lancement du stress test

On lance donc gatling

sh bin/gatling.sh

qui propose de choisir la simulation à lancer. Et c'est parti !

L'état d'avancement du 'stress test' s'affiche dans la console. Une fois celui-ci terminé, un rapport est généré et est accessible dans le dossier /results/.

Voici un petit aperçu d'un rapport obtenu (sur un PC de bureau 4 coeurs +4 Go de RAM) : Gatling_-_stresstest1.png Gatling_-_stresstest2.png

Conclusion du stress test

Sur mon Raspberry Pi, je suis un peu déçu car dès 10 utilisateurs en concurrence les accès à la base de données et les requêtes pour les contenus non statiques mettent un temps long (les moyennes vont de 20 à 40 secondes selon les requêtes) à s'exécuter... Je m'attendais à ce que la Raspberry Pi ne tienne pas bien la charge mais je pensais la limite atteinte moins vite. C'est également le signe que le code de l'application n'est pas optimisé pour une exécution très légère et très économe en ressources ! Il va me falloir plonger dans le code pour optimer tout cela !

Très bonne journée à tous et bons 'stress tests' !

Wednesday, June 5 2013

Paramétrer Nginx pour accueillir Zend Framework

Nginx est un serveur web réputé pour sa légèreté. Toutefois, les habitués d'Apache (comme moi) pourront être quelque peu déroutés lors des premiers paramétrages.

Activer, désactiver un site

Par exemple, si les répertoires /etc/nginx/sites-available et /etc/nginx/sites-enabled rappellent bien /etc/apache2/sites-available et /etc/apache2/sites-enabled, il n'y a dans le package nginx pour Debian (au moment où ces lignes sont écrites) pas d'équivalent aux commandes (fort pratiques) a2ensite et a2dissite. Il faut donc recourir à la main à la création de liens comme ci-dessous :

cd /etc/nginx/sites-enabled
ln -s ../sites-available/monSite

puis redémarrer le serveur par

service nginx restart

Toutefois, il semble que certains utilisateurs astucieux s'activent : https://github.com/perusio/nginx_ensite.

La gestion de PHP

La gestion de PHP est également différente : il n'y pas le mod_php mais il est proposé d'utiliser FastCGI Process Manager (PHP FPM) comme décrit ici.

Cas pratique : avec une application Zend Framework 1

Voici le code du "virtual host" qui m'a permis de faire fonctionner l'application (basée sur Zend Framework 1) avec Nginx :

server {
  server_name app.domain.tld;
  root /var/www/app/public;
  index index.php;
  try_files $uri $uri/ @notfile;

  location @notfile {
    rewrite ^(.*) /index.php last;
  }

  location ~ \.php$ {
   fastcgi_pass unix:/var/run/php5-fpm.sock;
   fastcgi_index /index.php;
   fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
   include fastcgi_params;
  }
}

Et pour passer des paramètres comme cela se fait dans Apache avec

RequestHeader add MY_SETTING my_value

on utilisera dans Nginx la commande :

fastcgi_param MY_SETTING my_value;

En espérant que ces petites astuces vous permettront de mieux faire cohabiter Zend Framework et Nginx !

Wednesday, December 26 2012

Demander aux robots de ne pas indexer un site internet

Il y a certains sites que l'on ne souhaite pas voir apparaître sur les moteurs de recherche - il faut donc expliquer aux moteurs de recherche qu'ils n'ont pas être indexés.

Facile, il suffira de créer un fichier robots.txt à la racine du site avec ce contenu :

User-agent: *
Disallow: /