automysqlbackup ou l'art de ne pas réinventer la roue

Rédigé par jdrien - - aucun commentaire
On trouve très souvent des personnes qui publient sur leur blog des scripts qui leur permettent de sauvegarder leurs bases de données avec MySQL. Ces scripts faits maison sont nombreux et tentent de répondre précisément aux besoins des rédacteurs.

En fait, la sauvegarde à chaud des bases de données simples est tellement évidente sous MySQL (un bête mysqldump suffit a priori) que l'on est vite tenté de réinventer la roue et de repartir de zéro. On arrivera certainement à un résultat satisfaisant, mais on sera sans doute passé à côté de fonctionnalités ou de problèmes importants (externalisation des sauvegardes, nettoyage, sécurité etc).

C'est suite à la publication sur le Planet Debian d'un énième script de ce type que j'ai appris qu'un outil intégré dans les dépôts de Debian existait : automysqlbackup.

Sous Debian donc, un simple sudo apt-get install automysqlbackup suffit à mettre en place une solution rapide de sauvegarde des bases sous MySQL.

D'origine, on arrive à un résultat très satisfaisant :
 - toutes les bases sont sauvegardées dans des répertoires bien ordonnés ;
 - les sauvegardes sont quotidiennes, hebdomadaires et mensuelles ;
 - les sauvegardes sont gérées par cron ;
 - pas d'utilisateur à renseigner : on utilise le mécanisme interne de debian (utilisateur MySQL debian-sys-maint) ;
 - les sauvegardes sont compressées ;
 - les sauvegardes sont nettoyées au fur et à mesure selon la durée de rétention définie.
 
Avec un peu de configuration on peut (fichier /etc/default/automysqlbackup) :
 - compresser les données avec bzip2 au lieu de gzip ;
 - exclure certaines bases ;
 - transmettre les logs de la sauvegarde par mail ;
 - effectuer des pre-traitements ainsi que des post-traitements : ainsi on peut facilement faire un rsync vers un autre serveur.

Bref, rien ne sert de réinventer la roue ! Et comme l'écrit Thomas Goirand, mainteneur du paquet pour Debian dans son commentaire à propos d'un script de sauvegarde :
Hi,
I'm the maintainer of automysqlbackup. Actually, you should really have a look into automysqlbackup. You thought about few of the problems you may have when doing backups, like the umask, and some others, but you forgot lots of them, and your script is missing many features of automysqlbackup (like daily, weekly, and monthly backups, which covers absolutely all needs). The nice part of automysqlbackup is also that it lived inside Debian for a large amount of time, and gathered feedback from users, which means that many, many, many small problems have been fixed in it. Over the years, I can even say that it's now a fork from the original code (it's unfortunate, and happened because of many things that I added in the package, plus upstream not adding them and releasing a new version which was really different and impossible to merge back).

I would strongly suggest to not work on your own, that's always less good than working as a team. If there's something that is missing in automysqlbackup (actually, I don't think there is), then it can be added, and I would welcome you to contribute patches.
PS : bien sûr, l'expérience de l'écriture de sa propre solution de sauvegarde peut être bénéfique sur le plan des connaissances. On comprend alors vraiment les choses. Et quand on voit des outils comme automysqlbackup on comprend justement qu'il est illusoire de croire que l'on peut penser à tout tout seul...

Quelques aventures avec ntp

Rédigé par jdrien - - aucun commentaire
Ce billet va présenter deux problèmes liés aux décalages avec les serveurs de référence de temps que j'ai rencontré il y a quelque temps sur les serveurs que j'administre.

Autant sur un PC bureautique il n'est pas nécessaire de se préoccuper de la finesse de la synchronisation avec les serveurs de temps (une simple mise à l'heure par ntpdate @server_de_temps au boot devrait suffire), autant le problème de la gestion de l'horloge est primordiale dans un contexte de serveur. En effet, outre le fait que le serveur ne sera que rarement rebooté et donc que la solution du ntpdate au boot est alors inadaptée, il est nécessaire que l'horloge interne du serveur soit correctement gérée à la fois pour les échanges avec les autres serveurs et pour les applications hébergées sur ledit serveur. De nombreuses applications nécessitent une gestion du temps monotone et ne supporte pas les remises à l'heure violentes.

Nous avions régulièrement des serveurs qui avaient un décalage trop important avec leurs serveurs de référence. Normalement, si le décalage est acceptable alors le démon ntpd va progressivement rattraper la dérive, petit à petit. Mais si le décalage est trop important, alors la synchronisation sera forcée. Et ce n'est pas bien !

On voit apparaître les messages suivants dans la log du démon ntpd :
time reset -0.291613 s

Ces time reset sont assez violents ; ils interviennent si le décalage n'est pas compris entre -0.128s et 0.128s. On peut obtenir facilement le décalage actuel par la commande suivante :
# /usr/sbin/ntpdate -q @IP_serveur_de_temps
server @IP_serveur_de_temps, stratum 6, offset -0.013661, delay 0.02574
 1 Aug 14:09:07 ntpdate[9017]: adjust time server @IP_serveur_de_temps offset -0.136612 sec

 
Ici le décalage est -0.136 seconde, donc trop important.

Nous avons pu voir deux cas différents :
 - le décalage est dû à un bug dans le firmware du serveur ;
 - le décalage est dû à un mauvais choix dans la source de temps choisi par le système.

Suite à une mise système sur des serveurs (passage en noyau 2.6.18), nous avons pu observer des décalages fréquents et des resynchronisations plusieurs fois par jour.
 
Premier cas : quand un bug de firmware entraîne des décalages de temps...
Il faut savoir que le noyau 2.6.18 utilise comme source de temps hpet (High Precision Event Timer) et non plus tsc (Time Stamp Counter) comme avant (pour plus d'information sur les sources de temps disponibles on peut lire le document http://www.makelinux.net/books/ulk3/understandlk-CHP-6-SECT-1).

 - pour vérifier la source de temps utilisée :
# cat /sys/devices/system/clocksource/clocksource0/current_clocksource
hpet

 - pour visualiser les sources disponibles :
# cat /sys/devices/system/clocksource/clocksource0/available_clocksource
acpi_pm jiffies hpet tsc


- il est fortement conseillé d'utiliser hpet qui doit être le plus précis normalement. J'ai effectué un test en changeant hpet par acpi_pm et la dérive était toujours importante :
# echo acpi_pm > /sys/devices/system/clocksource/clocksource0/current_clocksource

Le problème est que sur les serveurs que nous utilisions, des IBM x3850, un bug dans le firmware génère une dérive système importante. La version du firmware a donc un impact sur la gestion système du temps. Pour être honnête nous n'avions jamais pensé à regarder du côté des composants matériels pour contrôler cette gestion du temps !

Extrait du changelog du bios en v1.05 :
    *  IBM BIOS Flash Update System x3800/x3850/x3950/x3950E
          - Version 1.05, ZSE122A    (Suggested)
          > Problem(s) Fixed:
              - Fix operating system time drift, while using HPET.

              
Bien sûr nous utilisions une version plus ancienne (v1.04) qui était atteinte de ce fameux bug !

Nous avons pu procéder à la mise à jour du firmware, et depuis plus de soucis. La précision est au rendez-vous. J'ai effectué quelques mesures pendant deux jours avant la mise à jour du firmware : avec une prise de mesure par minute, la dérive moyenne constatée est de -0.224423 seconde. Cette dérive moyenne obligeait le démon ntpd à forcer la synchrnonisation environ 6 fois par jour. Après la mise à jour du firmware, nous avons constaté une dérive moyenne de 0.000773 seconde et plus aucune synchronisation forcée.

Second cas :
Si on peut mettre à jour un composant de type hpet pour améliorer la fiabilité, tant mieux. Mais si on ne dispose de ces composants ? C'est ce qui s'est passé sur un autre serveur, encore plus antique que les IBM x3850 du point précédent.

Dans le fichier de log de ntpd j'ai pu remarqué que les synchronisations forcées sont nombreuses (plus de 4 par jour parfois) :
     7 Aug 01:06:03 ntpd[17849]: time reset -0.167096 s
 
La dérive est donc importante et les écarts fluctuent.
Sur ces vieux serveurs, nous n'avons pas la chance d'avoir un composant type HPET et nous ne pouvions certainement pas chercher du côté des mises à jour de firmware.

Nous allons donc tenter de trouver une meilleure horloge.
 
Liste des sources de temps disponibles :
    [root] # cat /sys/devices/system/clocksource/clocksource0/available_clocksource
    acpi_pm jiffies tsc pit


Ces sources sont présentées dans l'ordre de préférence.
 
La source utilisée :
    [root] # cat /sys/devices/system/clocksource/clocksource0/current_clocksource
    tsc


Avec cette source (TSC : Time Stamp Counter) la moyenne du décalage est de 0.013591 seconde.
 
J'ai changé la source pour utiliser acpi_pm :
    echo acpi_pm > /sys/devices/system/clocksource/clocksource0/current_clocksource

J'ai supprimé le fichier drift et j'ai relancé ntpd.
 
Depuis la modification la moyenne du décalage est de -0.003481 seconde. Pour que cette modification soit prise en compte lors du prochain reboot, il faut ajouter l'option clocksource=acpi_pm au noyau dans le fichier /boot/grub/grub.conf.
 
Pour plus d'information sur les horloges, voir la page http://www.makelinux.net/books/ulk3/understandlk-CHP-6-SECT-1.

Conclusion : si un décalage se produit, il faut toujours faire à la qualité de la source de temps interne au serveur.

Bilan : habituellement en cas de problème NTP (dérive, resynchronisation etc.) on aura tendance à chercher du côté de la configuration du démon ntpd, d'un bug dans ledit démon ou bien encore on aura tendance à chercher du côté des serveurs de référence. Bref, on restera à un niveau applicatif pour ce module système et on ne cherchera pas nécessairement au niveau système pur (gestion des firmwares, configuration des paramètres du noyau).

2001, odyssée de l'uptime

Rédigé par jdrien - - aucun commentaire


Plus de 2 000 jours d'uptime pour un serveur, c'est pas mal. Et c'est suffisamment rare pour que celui puisse être noté. Typiquement le type de machine qui prend la poussière dans un coin et que l'on oublie... Il est vrai aussi qu'elle ne fait pas grand chose (juste un serveur de rebond pour administrer d'autres composants de temps en temps).

Pour les curieux : il s'agit d'un serveur IBM x336 (type 8837), mono-alimenté de surcroît. Jamais eu un seul problème avec cette machine.

Pour les grincheux : oui, je sais... Un uptime de 2001 jours c'est pas top au niveau des mises à jour des composants. On se traîne des vieilleries à tous les étages : firmwares bogués, outils systèmes inexistants, obsolètes ou bogués. Et pas de mise à jour de sécurité, en tout cas pour le noyau.

Mais la performance matérielle est tout de même belle !

Comment modifier les informations produits d'une lame IBM BladeCenter HS22

Rédigé par jdrien - - aucun commentaire
Il m'est arrivé de voir que certains serveurs IBM BladeCenter HS 22 perdaient un peu la tête de temps à autre : lors d'une simple interrogation des registres DMI via la commande dmidecode j'obtenais ceci
Product Name: IBM System x -[7870TH4]-
alors que j'attendais
Product Name: BladeCenter HS22 -[7870TH4]-

Il est possible de changer ce comportement via l'utilitaire asu fourni par IBM : en effet en lançant la commande asu show all on constate que l'on a les éléments suivants :
SYSTEM_PROD_DATA.SysInfoProdName=7870TH4
SYSTEM_PROD_DATA.SysInfoProdIdentifier=
SYSTEM_PROD_DATA.SysInfoSerialNum=1234567
Le champ SYSTEM_PROD_DATA.SysInfoProdIdentifier est vide ; si on compare avec un serveur HS22 qui répond correctement on observe que ce champ contient normalement l'information qui va bien :
SYSTEM_PROD_DATA.SysInfoProdName=7870TH4
SYSTEM_PROD_DATA.SysInfoProdIdentifier=BladeCenter HS22
SYSTEM_PROD_DATA.SysInfoSerialNum=1234567

Pour changer cette valeur on lance la commande suivante :
# asu set SYSTEM_PROD_DATA.SysInfoProdIdentifier 'BladeCenter HS22'
Après un reboot de la machine, la commande dmidecode répond correctement.
À noter que cette commande peut servir aussi à changer le numéro de série ou le type de machine ; utile lors du remplacement de la carte-mère.

Connaître la version du firmware des cartes fibres QLogic

Rédigé par jdrien - - aucun commentaire
Aide-mémoire : connaître la version des pilotes et des firmwares utilisés pour les cartes QLogic.

Nous devions mettre à jour un serveur IBM x3650 M3 sous CentOS 5.4 64 bits (noyau : 2.6.18-164.15.1.el5) avec 2 cartes bi-ports QLogic en utilisant le paquet qlgc_fw_fc_4g-mb1.90-2-sysx_linux_32-64.bin. Ce paquet, selon le changelog, devait apporter les versions suivantes :
* BIOS version 2.16
* EFI version 2.27
* FCode version 3.13
* Firmware version 5.03.06
Problème : nous ne savions pas où vérifier les versions des éléments qui devaient être mis à jour. En effet, nous utilisions, à tort, la commande systool qui nous indiquait une versions de fimrware qui nous semblait pertinente :
# systool -c fc_host -v
Class = "fc_host"
  Class Device = "host5"
  Class Device path = "/sys/class/fc_host/host5"
[...]
    supported_speeds    = "1 Gbit, 2 Gbit, 4 Gbit"
    symbolic_name       = "QLE2462 FW:v4.04.09 DVR:v8.03.00.1.05.05-k"
[...]
Sous Linux, on trouve dans le répertoire /sys/class/fc_host/host?/device/scsi_host:host? on trouve des fichiers optrom_* :
# cat optrom_bios_version
2.16
# cat optrom_efi_version
2.27
# cat optrom_fcode_version
3.13
# cat optrom_fw_version
5.03.06 1154
On trouve également deux autres fichiers qui correspondent au pilote utilisé :
# cat fw_version
4.04.09 (486)
# cat driver_version
8.03.00.1.05.05-k
Pour résumer, nous avons donc une carte avec deux firmwares bien distincts :
 - le firmware embarqué sur la carte (partie matérielle) ;
 - le firmware utilisé et chargé par le pilote (partie système).

Analyse des attaques DNS par RDoS

Rédigé par jdrien - - 1 commentaire

Résumé de l'attaque :

Utilisation de nos DNS Externes ouverts sur Internet pour effectuer un Déni de Service sur un serveur quelconque. Le but est d'utiliser notre infrastructure à des fins d'attaque. Il s'agit d'une attaque de type DRDoS par amplification.

stats_bind_rdos

Caractéristiques de l'attaque :

  • attaque de type déni de service (on tente de faire tomber un serveur en le bombardant de requêtes) [DoS] ;
  • attaque distribuée : il semble que l'attaque soit distribuée, c'est à dire que plusieurs machines sources soient utilisées (nous ne pouvons avoir de certitudes sur ce point) [D];
  • attaque par amplification : la requête qui est envoyée a un poids faible par rapport à la taille de notre réponse. On se sert de nos réponses pour amplifier l'attaque ;
  • attaque réflexive : nous sommes le vecteur de l'attaque. Nous sommes utilisés dans le déni de service [R].

Principe de l'attaque :

Un individu malveillant (que nous nommerons Mallory) décide d'attaquer un serveur web, celui de Bob. Pour ce faire, Mallory décide d'utiliser un réseau de PC zombies (un botnet, un réseau de machines infectées par un virus ou un troyen et que Mallory peut contrôler). C'est la partie distribuée de l'attaque.

Chaque machine zombie contrôlée par Mallory va envoyer des requêtes DNS en rafale sur notre serveur DNS. Les requêtes portent toujours sur les mêmes domaines (comportement scripté) et sont du type ANY, les plus coûteuses (la taille de nos réponses est plus importante que la taille des requêtes). C'est la partie amplification de l'attaque. Dans notre cas, en passant par notre DNS Mallory multiplie par 10 (voir calcul plus bas) sa capacité de nuisance.

Chaque requête transmise par les machines de Mallory a été forgée : l'adresse IP source a été usurpée ; elle ne correspond pas à la machine source de l'attaque mais à l'adresse IP de la victime, ici celle de Bob. Il s'agit de l'utilisation d'une faiblesse connue du protocole DNS (nous sommes en UDP, donc non connecté ; usurper une adresse IP dans le cadre de TCP n'est pas possible). C'est la partie réflexive de l'attaque.

Le serveur de Bob (le pauvre) va être saturé (ce serveur ou un équipement intermédiaire de l'infrastructure de Bob, comme un parefeu ou autre) par les réponses que nous lui transmettons. Bob ne verra comme source de l'attaque que notre propre adresse IP (celle de notre serveur DNS). Il pourra donc croire que nous avons essayé de le faire tomber.

Conclusion :

À mon sens, cette attaque pose trois problèmes principaux :
  • le risque de saturation est réel pour nos serveurs. Bien que nous ne soyons pas visés directement par les attaques (la volonté n'est pas de faire tomber notre serveur DNS), nous ne connaissons ni la capacité de nos serveurs ni la capacité de nuisance des attaquants (Mallory et sa bande) ;
  • les ressources de l'infrastructure sont utilisées pour mettre à mal des serveurs ; nous ne sommes que le bras armé d'attaquants qui utilisent (volent ?) notre puissance et notre bande passante. Dans le contexte que nous connaissons, où nous allons compter le nombre d'impressions par agents cela a de quoi laisser perplexe ;
  • le risque est diplomatique enfin : des serveurs gouvernementaux ou ministériels sont utilisés pour attaquer des ressources diverses (sites chinois, américains, irlandais). Cet impact n'est pas négligeable.

Quantification de l'effet amplification :

Sur un serveur DNS, nous lançons la capture des requêtes effectuées par une machine cliente :

[root] # tcpdump -i bond0 -s 0 src 192.168.120.73 or dst 192.168.120.73
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on bond0, link-type EN10MB (Ethernet), capture size 65535 bytes
11:41:51.568090 IP 192.168.120.73.47893 > mondns.domain:  16470+ ANY? toto1.domaine.fr. (32)
11:41:51.568267 IP mondns.domain > 192.168.120.73.47893:  16470* 6/0/3 SOA, NS dns.domaine.fr, MX mail.domaine.fr. 0, A toto.domaine.fr. (248)
 
11:42:40.451817 IP 192.168.120.73.36587 > mondns.domain:  22819+ ANY? toto2.domaine.fr. (29)
11:42:40.642098 IP mondns.domain > 192.168.120.73.36587:  22819 8/5/2 MX mail.domaine.fr. 20, SOA, NS dns.domaine.fr. (343)    
Les captures ont été tronquées bien sûr.

Depuis la machine cliente, lancement des commandes :

dig @192.168.130.201 toto1.domaine.fr ANY

Pour chaque domaine utilisé pour l'attaque par amplification, nous pouvons ainsi quantifier l'amplification. Nous voyons dans la capture les éléments suivants :

11:43:12.787273 IP 192.168.120.73.40997 > mondns.domain:  24721+ ANY? toto1.domaine.fr. (29)
11:43:12.825365 IP mondns.domain > 192.168.120.73.40997:  24721 9/5/2 MX relaismsg2.domaine.fr. 20, A reverse.domaine.net, SOA, NS  dns1.domaine.fr. (359)

La taille de la requête initiale est de 29 octets (sans compter les entêtes UDP et IP).

La taille de la réponse du serveur DNS est de 359 octets (sans compter les entêtes UDP et IP).

Le facteur d'amplification dans ce cas est 359/29 soit 12.37. Pour un octet reçu, nous en transmettons 12.37.

Soit un ratio moyen de 10.2. Pour un octet reçu, nous transmettons en moyenne 10.2 octets.

Graphes MRTG pour Apache

Rédigé par jdrien - - aucun commentaire

Script PERL apache2 :


#!/usr/bin/perl
# can return hits or bytes (counters)
@res = `GET http://localhost:80/server-status`;
foreach $res (@res) {
    if ($res =~ /Server uptime: (.*)$/) { $up = $1; last } else { next }
    if ($res =~ /Server at/) { $server = $res; last } else { next }
}

@res = `GET http://localhost:80/server-status?auto`;

foreach $res (@res) {
    if ($res =~ /Total Accesses: (\d+)/) { $d1 = $1; next }
    if ($res =~ /Total kBytes: (\d+)/) { $d2 = $1 * 1024; next }
}
$d1 = int($d1);
$d2 = int($d2);
if ($ARGV[0] eq "hits") {
    print "$d1\n";
    print "$d1\n";
} elsif ($ARGV[0] eq "bytes") {
    print "$d2\n";
    print "$d2\n";
}

print "$up\n";
$server = "mon_serveur";
print "$server\n";

que l'on lance par ./apache2 hits ou ./apache2 bytes

Partie du fichier de configuration MRTG :

## Apache2 hits ##
Target[apache2_hits]: `/etc/mrtg-sys/apache2 hits`
Colours[apache2_hits]: LIGHT BLUE#7AAFFF,BLUE#1000FF,DARK GREEN#006000,VIOLET#FF00FF
Options[apache2_hits]: perhour, nopercent, growright, noinfo, nobanner
PageTop[apache2_hits]: <h1>Hits Apache2</h1>
MaxBytes[apache2_hits]: 1000000
YLegend[apache2_hits]: hits/heure
ShortLegend[apache2_hits]: par heure   
LegendO[apache2_hits]: Hits:
Legend2[apache2_hits]: Hits horaires
Legend4[apache2_hits]: Hits Horaires max
Title[apache2_hits]: Hits horaires du serveur Apache
WithPeak[apache2_hits]: wmy

## Apache2 Traffic ##
Target[apache2_traffic]: `/etc/mrtg-sys/apache2 bytes`
Colours[apache2_traffic]: LIGHT BLUE#7AAFFF,BLUE#1000FF,DARK GREEN#006000,VIOLET#FF00FF
Options[apache2_traffic]: nopercent, growright, noinfo, nobanner
PageTop[apache2_traffic]: <h1>Traffic Apache</h1>
MaxBytes[apache2_traffic]:16000
AbsMax[apache2_traffic]:20000
YLegend[apache2_traffic]: octets/s
ShortLegend[apache2_traffic]: o/s
LegendO[apache2_traffic]: Traffic Apache:
Legend2[apache2_traffic]: Traffic Apache
Title[apache2_traffic]: Traffic du serveur Apache
WithPeak[apache2_traffic]: wmy
Legend4[apache2_traffic]: Traffic max Apache

Pour que cela fonctionne il faut bien sûr que le mod_status soit activé pour Apache.

Fil Rss des articles de ce mot clé