Aller au contenu | Aller au menu | Aller à la recherche

Blog de Thomas Martin

lundi 28 juin 2010

Sauvegarder la configuration de Cisco IOS vers un serveur distant avec Kron

Introduction

La sauvegarde de la configuration des équipements réseaux (switch, routeurs, bornes Wi-Fi, etc) est un point souvent négligé. Pourtant, ces équipements jouent souvent un rôle clé, et l'incapacité de restaurer rapidement la configuration suite à un crash matériel peut provoquer la paralysie d'un réseau pendant de longues heures. Cette sauvegarde est parfois faite de façon manuelle après la phase initiale de configuration, avec le risque d'oublier de le faire lors des prochaines modifications. Il est donc préférable, lorsque l'équipement le permet, d'effectuer cette sauvegarde de façon automatique et récurrente vers une machine distante. Voyons comment faire cela sous Cisco IOS, en utilisant le planificateur de tâches Kron, semblable au programme Cron en environnement Unix.

Mise en place

Une fois connecté au Cisco avec Telnet ou SSH, on passe en mode administrateur, puis en mode config :

switch> enable
switch# conf t

On crée une nouvelle policy-list pour Kron, nommée backupConfig, qui sera composée d'une ou plusieurs commandes à exécuter :

switch(config)# kron policy-list backupConfig

On utilise la commande cli pour ajouter une commande dans notre policy. Cette commande utilisera show running-config afin d'écrire la configuration courante sur la sortie standard (on pourrait aussi utiliser show startup-config pour écrire la configuration stockée en mémoire flash). Ensuite, l'opérateur pipe (|) est utilisé pour rediriger cette sortie vers la commande redirect, qui permet de rediriger un flux vers un serveur FTP, HTTP, TFTP, etc. On utilise ici un stockage vers un serveur FTP :

switch(config-kron-policy)# cli show running-config | redirect ftp://<host>/<path>/cisco.txt
switch(config-kron-policy)# exit

On définit maintenant à quel moment exécuter cette policy. Pour cela on créé une occurrence nommée backupConfig_occurence. Dans cet exemple ce sera à 01h15, chaque jour (mot-clé recurring) :

switch(config)# kron occurrence backupConfig_occurence at 01:15 recurring
switch(config-kron-occurrence)# policy-list backupConfig
switch(config-kron-occurrence)# exit
switch(config)# exit

Pour vérifier la bonne prise en compte de notre tâche, et voir le délai avant son exécution :

switch# show kron schedule

Voilà, il ne reste plus qu'à attendre l'heure programmée, et vérifier la présence du fichier envoyé. Le bon fonctionnement de tout cela nécessitant que le Cisco soit pleinement configuré (date et heure, adresse IP, passerelle réseau, DNS, etc).

Enfin, tout cela ne dispense bien sûr pas de sauvegarder cette nouvelle configuration en mémoire flash en prévision d'un futur reboot :

switch# write mem

dimanche 6 juin 2010

Pré-compilation de scripts Python

L'interpréteur Python dispose d'une fonctionnalité permettant de mettre en cache la phase de compilation d'un fichier source. Cela se traduit par la création de fichiers avec l'extension .pyc, placés au même niveau que les fichiers .py correspondant. Ceux-ci contiennent alors le bytecode résultant de la compilation. Cela permet d'améliorer la vitesse de chargement d'un module lors de sa prochaine invocation (mais non sa vitesse d'exécution).

Par défaut, Python effectue automatiquement cette opération pour les fichiers sources composant un module lors de son chargement. Il est nécessaire que le répertoire contenant les fichiers soit accessible en écriture par l'utilisateur invoquant Python, afin de pouvoir écrire les fichiers .pyc. Cela n'est pas forcément le cas pour les modules fournis par une distribution Linux par exemple, qui vont être installés dans une arborescence système, comme /usr/lib. Ou alors dans le cas d'une application web, où le serveur web n'a pas accès en écriture aux fichiers sources.

Afin de contourner cette limitation, il est possible de pre-créer les fichiers .pyc sans même exécuter le code correspondant. Cela nécessite d'utiliser le module compileall. Voici un exemple d'utilisation pour pré-compiler tous les fichiers du répertoire mymodule :

python -m compileall ./mymodule

A noter qu'il est possible d'obtenir un niveau d'optimisation supplémentaire en invoquant Python avec l'option -o. Les fichiers compilés auront alors l'extention .pyo.

mercredi 2 juin 2010

MySQL errno 24 : augmenter le nombre de descripteurs de fichiers

Si vous obtenez une erreur de ce type, lors d'un mysqldump par exemple :

mysqldump: Got error: 1016: Can't open file: './db/table.frm' (errno: 24) when using LOCK TABLES

C'est que votre serveur MySQL tente d'ouvrir trop de fichiers simultanément.

Pour augmenter le nombre maximal de fichiers pouvant être ouverts, vous pouvez ajuster le paramètre suivant dans la section [mysqld] du fichier my.cnf, dans la limite permise par votre système d'exploitation :

open_files_limit = 2048

La valeur par défaut étant de 1024.

samedi 16 janvier 2010

Installer Debian sur une machine virtuelle Amazon EC2

Introduction

J'ai eu récemment l'occasion de mettre en oeuvre une infrastructure LAMP, reposant sur la plate-forme d'hébergement de machines virtuelles d'Amazon, nommé EC2, pour Elastic Compute Cloud.

Le principe de fonctionnement est le suivant : on créé une image AMI (Amazon Machine Image), contenant le système de fichiers du système d'exploitation à démarrer. Il est possible d'utiliser et de personnaliser des AMI fournis par Amazon, ou de la créér de zéro. Le noyau, quant à lui, est à sélectionner parmi ceux proposés par Amazon.

Ensuite, cette image est téléchargée vers l'infrastructure de stockage d'Amazon, S3 (Simple Storage Service). Après enregistrement de celle-ci, elle peut être instanciée en une ou plusieurs machines virtuelles.

Une particularité de cette solution est que les données stockées dans le système de fichiers racine des machines virtuelles ne sont pas persistantes. Une fois une instance terminée (via la commande halt par exemple, ou via l'interface d'Amazon), celles-ci sont perdues ! Il faut alors utiliser pour les données applicatives une autre fonctionnalité d'Amazon, les EBS (Elastic Block Storage). Il s'agit de disques virtuels que l'on peut ajouter à une instance, accessibles sous forme de simples block devices que l'on peut formater et monter. A noter que depuis peu il est possible d'utiliser un EBS en tant que système de fichiers racine, ce qui permet de démarrer et d'arrêter une machine à volonté, sans nécessité d'instancier à nouveau une AMI.

Mise en oeuvre

Ce premier article décrit les étapes à suivre pour créér sa propre image AMI de Debian 5.0, l'envoyer vers Amazon, et la démarrer. Il vous faudra évidemment pour cela un compte Amazon Web Services.

Création de l'image

Création d'une image d'une taille de 1 Go et montage sous /mnt/ami :

# EC2_AMI_NAME=debian50
# dd if=/dev/zero of=$EC2_AMI_NAME.img bs=1M count=1024
# mkfs.ext3 -F $EC2_AMI_NAME.img
# mkdir /mnt/ami
# mount -o loop $EC2_AMI_NAME.img /mnt/ami

Installation et exécution de l'outil debootstrap, qui permet le téléchargement et l'installation d'un système Debian de base dans le point de montage. Attention, une architecture 32 bits est requise pour pouvoir démarrer des instances de type Small.

# aptitude update
# aptitude install debootstrap
# debootstrap --arch i386 lenny /mnt/ami

Montage des pseudo systèmes de fichier :

# mount -t proc proc /mnt/ami/proc/
# mount -t devpts devpts /mnt/ami/dev/pts/

Changement du répertoire racine vers le point de montage (chroot) et installation des packages nécessaires :

# chroot /mnt/ami
# aptitude install udev libc6-xen ssh

Configuration des points de montage dans /etc/fstab tel que recommandé dans la documentation :

/dev/sda1  /         ext3    defaults        1 1
NONE /dev/pts devpts gid=5,mode=620 0 0
none /dev/shm tmpfs defaults 0 0
none /proc proc defaults 0 0
none /sys sysfs defaults 0 0
/dev/sda2 /mnt ext3 defaults 0 0
/dev/sda3 swap swap defaults 0 0

Ajout des lignes suivantes au fichier /etc/network/interfaces pour configurer l'interface eth0 en DHCP :

auto lo eth0
iface lo inet loopback
iface eth0 inet dhcp

Il est également nécessaire d'ajouter sa clé SSH dans /root/.ssh/authorized_keys, ou de définir un mot de passe pour le compte root.

Enfin, quitter le chroot, et démonter l'image :

# /etc/init.d/ssh stop
# exit
# umount /mnt/ami

 

Génération de l'image AMI

Pour la suite des opérations, il est nécessaire de télécharger et décompresser les Amazon EC2 API Tools et Amazon EC2 AMI Tools. On installe également les dépendances nécessaires.

# aptitude install ruby libopenssl-ruby unzip sun-java6-jre
# EC2_AMI_TOOLS=ec2-ami-tools-1.3-XXXXX
# EC2_API_TOOLS=ec2-api-tools-1.3-XXXXX

Il faut également générer une clé et un certificat X.509, et faire pointer les variables d'environnements ci-dessous vers les fichiers téléchargés. Ceux-ci seront utilisés pour effectuer des requêtes vers les web services d'Amazon.

# EC2_PRIVATE_KEY=pk-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.pem
# EC2_CERT=cert-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.pem

Enfin, noter son EC2 user ID, généralement visible en haut à droite des pages d'AWS.

# EC2_USER_ID=XXXX-XXXX-XXXX

Création de l'image AMI :

# export EC2_HOME=$EC2_AMI_TOOLS
# $EC2_AMI_TOOLS/bin/ec2-bundle-image -i $EC2_AMI_NAME.img \
-k $EC2_PRIVATE_KEY -c $EC2_CERT -u $EC2_USER_ID -r i386

 

Upload sur S3

Il faut maintenant télécharger l'image vers Amazon S3. Pour cela, il est nécessaire de récupérer son Access Key ID et sa Secret Access Key sur la page Security Credentials. Il faut également sélectionner la région où sera localisée l'instance (US ou EU), ainsi que la bucket S3 où sera stockée l'AMI.

# EC2_ACCESS_KEY=XXXXXXXXXXXXXXXXXXXX
# EC2_SECRET_KEY=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# EC2_REGION=EU
# EC2_BUCKET=XXXXXXXX
# $EC2_AMI_TOOLS/bin/ec2-upload-bundle -m /tmp/$EC2_AMI_NAME.img.manifest.xml \
-a $EC2_ACCESS_KEY -s $EC2_SECRET_KEY -b $EC2_BUCKET \
--location $EC2_REGION

 

Enregistrement de l'instance

Il est nécessaire de déclarer l'image à Amazon pour pouvoir l'instancier. L'option --url est nécessaire pour préciser que l'on s'adresse à la région Europe d'EC2.

# export EC2_HOME=$EC2_API_TOOLS
# export JAVA_HOME=/usr/lib/jvm/java-6-sun-1.6.0.12
# $EC2_API_TOOLS/bin/ec2-register \
--url http://eu-west-1.ec2.amazonaws.com \
-n $EC2_AMI_NAME \
$EC2_BUCKET/$EC2_AMI_NAME.img.manifest.xml

La commande retourne l'ID de l'AMI qui vient d'être enregistrée.

Instanciation

L'instanciation peut également se faire via une requête sur AWS :

# EC2_AMI_INSTANCE_ID=ami-XXXXXXXX
# EC2_AKI=aki-7e0d250a
# EC2_RAMDISK=ari-7d0d2509
# $EC2_API_TOOLS/bin/ec2-run-instances $EC2_AMI_INSTANCE_ID \
-K $EC2_PRIVATE_KEY \
-C $EC2_CERT \
--kernel $EC2_AKI --ramdisk $EC2_RAMDISK \
--region eu-west-1

Le noyau utilisé (aki-7e0d250a) est un 2.6.21.7-2.fc8xen, suffisamment récent pour l'utilisation de udev. Ce n'est pas le cas du noyau par défaut.

Connexion à la machine

Les instances créées peuvent être listées à l'aide de la commande suivante :

# $EC2_API_TOOLS/bin/ec2-describe-instances -K $EC2_PRIVATE_KEY \
-C $EC2_CERT --url http://eu-west-1.ec2.amazonaws.com

Parmi les informations obtenues, on peut notamment connaître le nom DNS public de l'instance créé, de la forme ec2-XXX-XXX-XXX-XXX.eu-west-1.compute.amazonaws.com. A noter que ces informations sont également disponibles via l'interface web.

Enfin, il ne reste plus qu'à se connecter avec le compte root à sa nouvelle machine !

mercredi 21 octobre 2009

Utilisation de PHP5 en mode CGI

Utiliser PHP en tant que module Apache est la façon classique de faire. Une autre solution est de l'utiliser en tant que simple programme CGI. Cela peut permettre d'utiliser une version différente de PHP que celle chargée en tant que module, ou alors de limiter l'utilisation mémoire d'Apache. Pour cela, une méthode intéressante est d'utiliser le module mod_actions, qui permet entre autre d'associer un script CGI à un type MIME.

Voici les étapes à effectuer, sur un système Debian :

Installation du CGI PHP5 :

# aptitude install php5-cgi

Activation de mod_actions :

# a2enmod actions

Utiliser enfin les directives suivantes au sein d'un virtualhost, d'un fichier .htaccess ou d'un bloc <directory>, pour utiliser le CGI PHP5 avec les fichiers dotés d'une extension .php :

AddHandler cgi-php5 .php
Action cgi-php5 /cgi-bin/php5

lundi 5 octobre 2009

Mise en oeuvre de DKIM et DomainKeys sous Debian Lenny

Voici un récapitulatif de la mise en place des protocoles d'authentification SMTP DKIM et DomainKeys sous Debian Lenny. Le serveur de mail utilisé est Postfix, mais tout MTA sachant communiquer avec les milter de Sendmail peut normalement être utilisé. La signature et la vérification des messages sera effectuée pour le domaine <domain>. Voici les étapes :

Installation de dkim-filter et dk-filter :

# aptitude install dkim-filter dk-filter

Ajouter dans le fichier /etc/dkim-filter.conf un ensemble de directives indiquant le nom du domaine qui va utiliser DKIM, un nom de selector (exemple : 2009), et le nom du fichier qui contiendra la clé privée utilisée pour la signature. L'utilisation des selector permet notamment de changer et/ou révoquer facilement une clé, ou d'utiliser des clés différentes sur des serveurs de mails différents.

Domain      <domain>
KeyFile /etc/ssl/dkim_<domain>_<selector>.key
Selector <selector>

Générer la clé :

# openssl genrsa -out /etc/ssl/private/dkim_<domain>_<selector>.key

Et en extraire la partie publique :

# openssl rsa -in /etc/ssl/private/dkim_<domain>_<selector>.key \
-pubout -outform PEM

Dans la zone DNS du domaine <domain>, ajouter l'enregistrement suivant. La valeur de <key> correspond à la sortie de la commande précédente, contenue entre les lignes _BEGIN PUBLIC KEY_ et _END PUBLIC KEY_ :

<selector>._domainkey IN TXT "v=DKIM1; g=*; k=rsa; p=<key>"

Ajouter les paramètres de démarrage de dkim_filter dans /etc/default/dkim-filter. Le fichier /etc/dkim.hosts contient la liste des serveurs dont les mails sortants seront chiffrés :

SOCKET="inet:2505@localhost"
DAEMON_OPTIONS="-l -i /etc/dkim.hosts"

Les paramètres de dk-filter, dans /etc/default/dk-filter, sont similaires, à l'exception que tout est passé via les options, celui-ci n'utilise pas de fichier de configuration.

DAEMON_OPTS="$DAEMON_OPTS -d <domain>  -S <selector> -i /etc/dkim.hosts \
-s /etc/ssl/private/dkim_<domain>_<selector>.key"
SOCKET="inet:2506@localhost"

Puis les redémarrer :

# /etc/init.d/dkim-filter start
# /etc/init.d/dk-filter start

Reste enfin à utiliser ces milter au niveau de Postfix, pour cela ajouter les directives suivantes au fichier /etc/postfix/main.cf :

milter_default_action = accept
milter_protocol = 2
smtpd_milters = inet:localhost:2505 inet:localhost:2506

Et redémarrer Postfix :

# /etc/init.d/postfix restart

Un test basique de fonctionnement est alors d'envoyer un mail à destination d'un domaine effectuant des vérifications DKIM, yahoo.com par exemple.

# nc 127.0.0.1 25 <<EOT
HELO localhost
MAIL FROM: root@<domain>
RCPT TO: <account>@yahoo.com
DATA
Subject: Test DKIM
.
QUIT
EOT

Les signatures DKIM et DomainKeys sont correctement vérifiées si l'en-tête Authentication-Results contient dkim=pass et domainkeys=pass.

On peut également envoyer un mail à destination de son domaine, et vérifier que l'en-tête Authentication-Results est bien ajoutée, et valide.

vendredi 19 juin 2009

Gérer plusieurs instances de MySQL

Voici un résumé de la mise en oeuvre de multiples instances MySQL sur un
serveur Debian, à l'aide de l'outil mysqld_multi. Cette solution permet par
exemple d'offrir un accès complet à MySQL dans le cadre d'un hébergement
mutualisé (l'utilisateur peut alors créer ses propres bases, gèrer ses
utilisateurs, etc). Cela peut être aussi utilisé pour cloisonner totalement les
bases de données de différentes applications, et ainsi d'ajuster finement des
paramètres tels que max_connections pour chacune d'elles.

Voici les étapes :

  • Ajouter une ou plusieurs sections [mysqldN] dans /etc/mysql/my.cnf, où N
    correspond au numéro d'instance, et <instance> à son nom.
[mysqldN]
mysqld = /usr/bin/mysqld_safe
user = mysql-<instance>
port = 3307
socket = /var/run/mysqld-<instance>/mysqld.sock
pid-file = /var/run/mysqld-<instance>/mysqld.pid
datadir = /home/mysql/<instance>

Si vous utilisez les options --log, --log-bin ou --log-error, il est
nécessaire de les redéfinir dans chaque configuration d'instances (voir
Running Multiple MySQL Servers on the Same Machine).

Note : pour faire tourner l'instance avec un utilisateur différent (comme dans
cette exemple) il est à priori nécessaire de commenter le paramètre user = mysql dans
la section [mysqld] du my.cnf, sinon mysqld_multi retourne une erreur :

Ignoring user change to 'mysql-<instance>' because the user was set to 'mysql'
earlier on the command line

Décommenter ce paramètre ne gène pas le lancement de l'instance initiale.

  • Créer le compte système qui fera tourner l'instance.
useradd -r mysql-<instance>
  • Créer le répertoire de données de l'instance, et les répertoires annexes.
mysql_install_db --datadir=/home/mysql/<instance>
chown -R mysql-<instance> /home/mysql/<instance>
mkdir /var/run/mysqld-<instance>
chown mysql-<instance> /var/run/mysqld-<instance>
  • Démarrage de l'instance
mysqld_multi --verbose --no-log start N

Où N fait référence au numéro de l'instance.

Il est maintenant possible de s'y connecter en utilisant le numéro de port
TCP/IP spécifié plus haut, et en saisissant un mot de passe vide :

mysql -h 127.0.0.1 --port=3307 -u root -p

Si vous choisissez d'utiliser un mot de passe root commun à toutes vos
instances, vous trouverez pratique d'ajouter la section suivante à votre
fichier .my.cnf :

[mysqld_multi]
user = root
password = "<password>"

Enfin, voici un exemple de script d'init permettant de démarrer et d'arrêter
proprement toutes vos instances :

#!/bin/sh

case "$1" in
start)
mysqld_multi start
;;
stop)
mysqld_multi stop
;;
*)
echo "Usage: $0 {start|stop}"
exit 1
esac

exit 0

samedi 13 juin 2009

Mise en place de DSPAM comme agent de livraison pour Postfix

DSPAM est un logiciel anti-spam pouvant aisément être utilisé comme agent
de livraison Postfix. Cela évite d'utiliser certains hacks, comme la
réinjection SMTP. Dans ce mode, DSPAM agit comme un relais qui accepte un mail
sur son entrée standard, le traite en fonction de votre configuration (ajout
d'en-têtes, préfixage de [SPAM] au sujet, etc), et le délivre à un agent de
livraison final (directive TrustedDeliveryAgent dans dspam.conf).

Pour cela il suffit d'ajouter une ligne de ce type à votre master.cf :

dspam unix - n n - 1 pipe flags=DORqhu user=dspam:mail
argv=/usr/local/bin/dspam-wrapper
--user ${recipient} --deliver=innocent,spam

Et de positionner ensuite une directive virtual_transport = dspam, dans le
cas de l'utilisation de comptes virtuels. Il est aussi possible de l'activer
seulement pour certains utilisateurs à l'aide de la table transport(5).

Toutefois, pour que cela reste fiable, il est nécessaire que DSPAM retourne un
code d'erreur 75 (tempfail) en cas de soucis, afin que Postfix conserve
celui-ci en file d'attente. Sur ce point, la version courante de DSPAM (3.8.0)
souffre d'un bug génant : si l'agent de livraison final retourne un code
d'erreur, DSPAM ne retournera pas ce même code (contrairement à ce qui est
indiqué dans la section EXIT VALUE de la page de man), mais 255. Ce qui
entraîne une perte pure et simple du mail !

En attendant, pour contourner ce problème, il est possible de mettre en place
un wrapper qui retournera le code 75 dans toutes les situations d'erreur.

Exemple d'un fichier dspam-wrapper :

#!/bin/sh
cat | /usr/local/bin/dspam $* || return 75

jeudi 6 novembre 2008

Importer un mot de passe MD5 dans un champ userPassword d'OpenLDAP

J'ai eu récemment l'occasion de migrer des comptes stockés dans une base de
données PostgreSQL vers OpenLDAP. Les mots de passe étaient stockés sous forme
de hash MD5 au format hexadécimal. f71dbe52628a3f83a77ab494817525c6 par
exemple.

Ma première approche a été d'importer directement cette valeur dans le champ
userPassword en les préfixant de {MD5}. En effet OpenLDAP gère de
manière transparente de nombreux formats de mot de passe.

Malheureusement ceci ne marche pas. Les MD5 doivent être stockés sous forme
hexadécimal dans OpenLDAP. Voici le bout de code Perl permettant la conversion,
que j'ai mis un certain temps à écrire :

use MIME::Base64;
my $md5_hexa = "f71dbe52628a3f83a77ab494817525c6";
my $md5_base64 = "{MD5}".encode_base64(pack("H*", $md5_hexa), "");

dimanche 12 octobre 2008

Abook et Nokia N95

Depuis plusieurs mois je voulais importer dans mon Nokia N95 mes contacts
stockés dans le logiciel Abook (compagnon idéal de Mutt).
C'est aujourd'hui chose faite à l'aide de la solution de Grégory Colpart.

En résumé :

  • Exporter ses contacts Abook au format Vcard avec la ligne de commande
    suivante :
abook --convert --infile ~/.abook/addressbook --outformat gcrd
  • Stocker chaque entrée Vcard dans un fichier distinct (peu importe le nom)
    avec un encodage iso-8859-1. Ce script peut être utilisé pour cela.
  • Copier ces fichiers dans le répertoire Others/contacts/ du téléphone.
  • Aller dans Contacts > Options > Copier > "Depuis carte memoire".

Et voila, tous vos contacts sont importés, et la plupart des champs de Abook
(adresse postale, site web, etc) sont normalement pris en compte.

P.S. : Pour ceux qui utilisent encore la version fournie par leur opérateur du système
d'exploitation du N95 (comme moi jusqu'à aujourd'hui), je leur conseille vivement
(mais toutefois à leurs risques et périls) de consulter cette page
et d'utiliser la version 1.0.38.14 de Nemesis (les version précédentes n'ayant
pas fonctionné pour moi).

- page 2 de 3 -