PROJET AUTOBLOG


blog'o'm0le

source: blog'o'm0le

⇐ retour index

Petite histoire de debugging (sendemail)

mercredi 7 octobre 2020 à 13:15

Je vous raconte comment j'ai failli envoyé un bug report à Debian 🙂
TL;DR: Une dépendances manquante pour le paquet sendemail m’empêchait d'envoyer des mail via TLS.

Dans notre architecture, nous avons un serveur sous XEN, et différentes VM pour différentes fonctions, dont une "WEB" (pour les sites), une "DATA" et enfin une "MAIL" qui est notre serveur mail.
Je voulais changer de méthode d'envoi de mail en local, je suis donc passé au package sendEmail (pas sendmail donc) pour avoir l'auth STARTTLS. Mais, pour une raison inexpliquée, certaines VM arrivaient à envoyer des mails et d'autre non.

Première chose, vérifier les logs;

  1. Du côté du serveur de mail : rien de particulier (comme l'authentification ne marchait pas)
  2. Du côté du client mail (sendemail) : l'envoi en mode debug me donnait quelques indices :

depuis la VM WEB (impossible d'envoyer un mail) :

sendemail -u subject -m message -f user@domain.tld -t user@domain.tld -s mailserver -xu user@domain.tld -xp password -vvvv
DEBUG => Connecting to mailserver
DEBUG => My IP address is: 10.0.1.1
DEBUG => evalSMTPresponse() - Checking for SMTP success or error status in themessage: 220 mailserver ESMTP Postfix (Debian/GNU)
DEBUG => evalSMTPresponse() - Found SMTP success code: 220
SUCCESS => Received:     220 mailserver ESMTP Postfix (Debian/GNU)
INFO => Sending:         EHLO WEB
DEBUG => evalSMTPresponse() - Checking for SMTP success or error status in themessage: 250-mailserver, 250-PIPELINING, 250-SIZE 502400000, 250-ETRN, 250-STARTTLS, 250-ENHANCEDSTATUSCODES, 250-8BITMIME, 250 DSN
DEBUG => evalSMTPresponse() - Found SMTP success code: 250
SUCCESS => Received:     250-mailserver, 250-PIPELINING, 250-SIZE 502400000, 250-ETRN, 250-STARTTLS, 250-ENHANCEDSTATUSCODES, 250-8BITMIME, 250 DSN
DEBUG => The remote SMTP server supports TLS :)
NOTICE => Authentication not supported by the remote SMTP server!
INFO => Sending:         MAIL FROM:user@domain.tld
DEBUG => evalSMTPresponse() - Checking for SMTP success or error status in themessage: 530 5.7.0 Must issue a STARTTLS command first
DEBUG => evalSMTPresponse() - Found SMTP error code: 530
ERROR => Received:       530 5.7.0 Must issue a STARTTLS command first

depuis la VM DATA (où les mails fonctionnaient sans problème) :

# sendemail -u subject -m message -f user@domain.tld -t user@domain.tld -s mailserver -xu user@domain.tld -xp password -vvvv
DEBUG => Connecting to mailserver
DEBUG => My IP address is: 10.0.1.2
DEBUG => evalSMTPresponse() - Checking for SMTP success or error status in themessage: 220 mailserver ESMTP Postfix (Debian/GNU)
DEBUG => evalSMTPresponse() - Found SMTP success code: 220
SUCCESS => Received:     220 mailserver ESMTP Postfix (Debian/GNU)
INFO => Sending:         EHLO DATA
DEBUG => evalSMTPresponse() - Checking for SMTP success or error status in themessage: 250-mailserver, 250-PIPELINING, 250-SIZE 502400000, 250-ETRN, 250-STARTTLS, 250-ENHANCEDSTATUSCODES, 250-8BITMIME, 250 DSN
DEBUG => evalSMTPresponse() - Found SMTP success code: 250
SUCCESS => Received:     250-mailserver, 250-PIPELINING, 250-SIZE 502400000, 250-ETRN, 250-STARTTLS, 250-ENHANCEDSTATUSCODES, 250-8BITMIME, 250 DSN
DEBUG => The remote SMTP server supports TLS :)
DEBUG => Starting TLS
INFO => Sending:         STARTTLS
DEBUG => evalSMTPresponse() - Checking for SMTP success or error status in themessage: 220 2.0.0 Ready to start TLS
DEBUG => evalSMTPresponse() - Found SMTP success code: 220
SUCCESS => Received:     220 2.0.0 Ready to start TLS
DEBUG => TLS: Using cipher: ECDHE-RSA-AES256-GCM-SHA384
DEBUG => TLS session initialized :)
INFO => Sending:         EHLO DATA
[...]

Dans les deux cas, le serveur supporte TLS, mais le "STARTTLS" n'est pas envoyé depuis ma VM WEB.

Les configurations et les accès/restrictions étant les mêmes, gnutls installé sur les deux machines, j'ai commencé à rédiger mon bug report en m'aidant de : https://www.debian.org/Bugs/Reporting

L'une des étapes du rapport de bug debian est d'envoyer les infos du package, dont l'une d'elle (https://www.debian.org/Bugs/Reporting#findpkgver) est :
dpkg --status

Bien m'en a pris, car j'ai pu me rendre compte de cette intéressante ligne :

# dpkg --status sendemail
Package: sendemail
[...]
Suggests: libio-socket-ssl-perl, libnet-ssleay-perl

Effectivement, ces deux paquets ne sont pas des dépendances, mais des suggestions …. néanmoins très indispensable pour envoyer des mails en TLS 🙂

J'ai pu régler mon bug et m’éviter de passer pour un idiot à remplir un rapport de bug inutile…

La fin du tracking ... commence -aussi- sur le m0le-o-blog

samedi 23 juin 2018 à 11:46

Voilà voilà, en suivant le pas de Tuxicoman nous nous sommes concertés et force est de constater qu'on s'en fout un peu des logs / statistiques..

Surtout si c'est pour compter les gens qui n'ont PAS de bloqueur de pub (a priori, la grosse majorité de l'auditoire du blog, non ?)

Bref, on retire Piwik/Matomo, mis en place ici en février 2012. Ça file quand même ..

Juste pour le fun, voici quelques stats, sorties de nulle part :

Je ne vais pas faire d'interprétation parce qu'au final... on s'en fout toujours, non ?

PS : en résumé, m0le-o-blog est sans pub (depuis toujours) et sans tracker !

Backup avec Borg via ssh(fs) sur Synology

dimanche 1 avril 2018 à 18:12

Tant qu'à faire un peu de ménage sur notre dédié, je me suis décidé à changer de mode de backup en passant à Borg.

Le postulat

Les prérequis

Dans mon cas, j'utilise un script sur mon synology qui récupère son IP public et qui l'envoie dans un fichier "ip_syn" sur le serveur m0le periodiquement

Les tâches

  1. Créer un utilisateur "backup" sur le synology avec SSH + SFTP + SSH key
  2. Configurer sshfs avec une clé SSH sur le client
  3. Installer, initialiser et tester le repo Borg
  4. Automatiser le tout avec un script

Création de l'utilisateur backup

Tout se passe depuis l'interface web, il faut s'assurer que l'utilisateur a le droit dans un dossier, disons /Backup (monté dans /volume1/Backup/)

Pour que la connexion par clé ssh fonctionne, il faut :

  1. Que l'utilisateur fasse partie du groupe administrators pour avoir accès au login SSH
  2. Activer le "User Home" Service dans Users > Advanced. Cela permet d'avoir un "vrai" répertoire pour l'utilisateur et pouvoir stocker les clés SSH de l'utilisateur (dans /var/services/homes/<user>/.ssh/authorized_keys
  3. Avoir les bons paramètres de sécurités/accès dans le dossier .ssh et autoriser la connexion par clé

On peut s'en sortir en exécutant ces commandes :

chmod 755 /var/services/homes/<user>
chmod 700 /var/services/homes/<user>/.ssh
chmod 600 /var/services/homes/<user>/.ssh/*
chown -R <user>:users /var/services/homes/<user>/.ssh

Il faut également s'assurer que ces deux lignes soit décommenté dans /etc/ssh/sshd_config:

PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys

Installation de la clé ssh + sshfs + borg

Pour installer les dépendances sous Debian:

m0le# apt install sshfs

On passe à la génération de la clé ssh + l'envoi sur le synology

m0le# ssh-keygen -t rsa -b 4096 // Je genère une clé sans passphrase (pour automatiser le montage avec sshfs)

m0le# ssh-copy-id <user>@<ip_synology> -p <port> // j'envoie la clé vers le synology

m0le# ssh <user>@<ip_synology> -p <port> // Je vérifie que j'arrive bien à me connecter au server, sans demander de mot de passe.

On teste l'existence d'un dossier "Backup" accessible sur le synology

backup@synology$ cd Backup // j'utilise mon utilisateur dédié "backup"
backup@synology Backup$ touch test // Je crée un fichier

On crée enfin le répertoire local pour monter le répertoire Backup avec sshfs

m0le# mkdir -p /mnt/syno // Je créer le repertoire pour le montage via SSHFS

m0le# sshfs <user>@<ip_synology>/Backup/ /mnt/syno -p <port> // je monte le dossier Backup de mon synology sur le server m0le

m0le# ls -l /mnt/syno // Si le fichier "test" s'affiche, c'est tout bon !

m0le# rm /mnt/syno/test // J'en ai plus besoin

Installation et initialisation de BorgBackup

On va dabord créer un repo qui va héberger nos "archives".

(les archives stockeront nos fichiers, le repo est l'endroit ou seront inventorier ces archives)

m0le# apt install borgbackup // installation de borgbackup

m0le# borg init --encryption=repokey /mnt/syno/<repo> // création du repo en prenant soin de créer un mot de passe !

m0le# borg create /mnt/syno/<repo>::test /etc/ // Je créer une sauvegarde du dossier "/etc" dans un archive nommé "test" dans mon repo "/mnt/syno/<repo>"

Faire des tests et les supprimer

m0le# borg create --stats /mnt/syno/<repo>::test2 /etc/ // Je crée une deuxième archive "test2" du dossier /etc/ : Ca devrait être bcp plus rapide car "test" existe déjà.

m0le# borg list /mnt/syno/<repo>::test2 // Si je liste le contenu du dossier "/etc", c'est tout bon !

m0le# borg delete /mnt/syno/<repo>::test // Je supprimer mes tests

m0le# borg delete /mnt/syno/<repo>::test2 // Je supprimer mes tests

Script d'automatisation

Si tout va bien jusqu'ici, c'est qu'on a de quoi créer des archives Borg (manuellement pour l'instant), sur un repertoire de notre synology via sshfs.

Plutôt pas mal, on va donc automatiser ça ! Voilà ce que le script (cf source) fait :

  1. Il monte le répertoire sshfs
  2. Il crée un backup avec le nom de la machine + date courante
  3. Il effectue le nettoyage des archives si besoin (rétention)
  4. Il démonte le répertoire de backup

Évidemment, il faudra faire vos modifs comme celles que j'ai apportées par rapport à la source (cf les paramètres au debut)

#!/bin/bash

# Mount parameters
mount="/mnt/syno/"

# Borg parameters
repo="/mnt/syno/m0le"
pass="legrosmotdepasse!!"
backup_dir="/etc /root /usr/local/bin"

# Synology parameters
syno_user="backup"
syno_ip=`cat /home/ip_syn`
syno_port="22"
syno_dir="/Backup/"

# Setting this, so the repo does not need to be given on the commandline:
export BORG_REPO={repo}

# Setting this, so you won't be asked for your repository passphrase:
export BORG_PASSPHRASE=${pass}
# or this to ask an external program to supply the passphrase:
export BORG_PASSCOMMAND='pass show backup'

# some helpers and error handling:
info() { printf "\n%s %s\n\n" "$( date )" "$*" >&2; }
trap 'echo $( date ) Backup interrupted >&2; exit 2' INT TERM

info "Mount ${mount} from ssh://${syno_user}@${syno_ip}:${syno_port}/${syno_dir}"

sshfs ${syno_user}@${syno_ip}:${syno_dir} ${mount} -p ${syno_port}

info "Starting backup: ${backup_dir}"

# Backup the most important directories into an archive named after
# the machine this script is currently running on:

borg create \
--verbose \
--filter AME \
--list \
--stats \
--show-rc \
--compression lz4 \
--exclude-caches \
--exclude '/home/*/.cache/*' \
--exclude '/var/cache/*' \
--exclude '/var/tmp/*' \
\
::'{hostname}-{now}' \
$backup_dir \

backup_exit=$?

info "Pruning repository"

# Use the `prune` subcommand to maintain 7 daily, 4 weekly and 6 monthly
# archives of THIS machine. The '{hostname}-' prefix is very important to
# limit prune's operation to this machine's archives and not apply to
# other machines' archives also:

borg prune \
--list \
--prefix '{hostname}-' \
--show-rc \
--keep-daily 7 \
--keep-weekly 4 \
--keep-monthly 6 \

prune_exit=$?

# use highest exit code as global exit code
global_exit=$(( backup_exit > prune_exit ? backup_exit : prune_exit ))

info "Unmounting ${mount}"

umount ${mount}

if [ ${global_exit} -eq 1 ];
then
info "Backup and/or Prune finished with a warning"
fi

if [ ${global_exit} -gt 1 ];
then
info "Backup and/or Prune finished with an error"
fi
exit ${global_exit}

Il ne reste plus qu'à exécuter le script, vérifier l'archive et son contenu et enfin rajouter un petit cron qui va bien 😉

Source

sshfs/ssh key sur Synology
Borg backup commands + script

Certificat wildcard avec letsencrypt

vendredi 16 mars 2018 à 20:34

Petite note de service : j'ai mis en place notre certificat wildcard pour m0le.net via letsencrypt de façon relativement simple.

Grosso modo, il n'y a plus qu'un certificat pour tous les sous-domaines que nous utilisons (ainsi qu'un certificat pour m0le.net tout cours)

Je devais :

Génération et activation du certificat

Voici en gro la manip (sous Debian) :

# certbot --version

# certbot certonly --manual -d *.m0le.net --preferred-challenges dns-01 --server https://acme-v02.api.letsencrypt.org/directory

Suppression des anciens certificats (après test 😉 )

# certbot -delete --cert-name sub.m0le.net //autant de fois que de sous domaine

Et bim, je ne dois renouveler plus que deux certificats (un pour m0le.net, un pour *.m0le.net)... Merci letsencrypt !

Autopsie d'une dataviz [9] : une carte "entonnoir" pour les régionales 2015

samedi 19 décembre 2015 à 17:59

Retour sur la réalisation des cartes réalisées pour Rue89 Strasbourg lors des deux tours des régionales 2015. Objectif : rendre compte, sur une même interface, des résultats électoraux aux niveaux communal, département et régional.

app_acal

5 200 communes, dix départements, trois régions : ce sont des chiffres-clés de l'Alsace-Champagne-Ardenne-Lorraine (ACAL), nouvelle région administrative créée fin 2014.

Les élections qui ont déterminé la composition du nouveau conseil régional ont été l'occasion de tenter de la cartographie très ambitieuse chez Rue89 Strasbourg. Je vais tenter un résumé le plus exhaustif possible des différentes étapes de ce boulot.

Le bon exemple du Huffington Post

La principale source d'inspiration de ces cartes est ce très bel exemple d'analyse électorale proposée par le Huffington Post, et codée avec la fameuse librairie D3js.

L'application du Huffington repose sur le principe d'un entonnoir : on propose à l'internaute deux niveaux de lecture, avec d'un côté le vote des 300 communes du Massachussets, et de l'autre les 14 comtés de cet Etat.

Crédit : Huffington Post

Huffington Post

Les résultats des plus grands territoires apparaissent comme une synthèse des communes qui les composent, un peu comme si on les avait lâchés dans un entonnoir.

On observe des bastions démocrates et républicains bien délimités au niveau communal, ce qui se ressent sur les résultats cantonaux.

massa_2

Huffington Post

A l'échelle de l'ACAL, on passait à un niveau bien plus costaud, avec près de 5 200 villes à cartographier. L'échelle départementale d'à peine dix unités me paraissait trop faible, tandis que l'échelle cantonale, plus proche de l'application du Huffington, ne me paraissait pas la plus compréhensible.

Bref, trois niveaux commençaient à émerger pour les futures élections régionales : les communes, les départements, et les régions.

A ce stade, il était temps de se pencher sur la faisabilité technique de la chose.

Un squelette solide avant de démarrer les festivités

En furetant un peu, je suis tombé sur ce gabarit avec code source directement inspiré de la carte du Huffington. Ca m'a suffi pour commencer les tests avec mes propres fichiers géographiques, soigneusement préparés sur le logiciel QGis.

Sans faire un récap' de tous les atermoiements techniques, j'en ai appris plus sur l'option CSS "hidden", qui contrairement au "opacity" de l'exemple, permet de masquer toutes les options d'un calque.

Il y a également eu quelques lignes de code dédiées à un effet de zoom sur les communes de chaque département, directement calqué sur cet exemple publié par le créateur de D3 lui-même.

L'idée était d'encourager l'exploration des données en permettant à l'utilisateur d'accéder à des communes trop petites pour être consultées depuis la vue d'ensemble.

Une des options ajoutées à ce stade a été l'affichage des sous-préfectures seulement lorsqu'un département est zoomé pour offrir des repères supplémentaires.

Une fois le squelette prêt, le plus dur restait à faire : le connecter à des données, dans l'idée de traiter en direct les résultats de ces élections régionales.

Un parser en PHP qui a fait ses preuves

Une fois le modèle de carte prêt à être montré, je l'ai envoyé à Tom Wersinger, développeur chez Rue89, pour lui demander son avis.

Tom nous avait déjà filé un précieux coup de main au moment des élections départementales, où on avait pu apprécier la puissance d'un parser en PHP codé par ses soins.

Pour le dire vite, il permet de traduire un tableur Google en json, en paramétrant (assez) simplement quelques options comme l'identifiant de la feuille Google.

Dès que la connexion est établie entre le parser et le tableur, un petit F5 permet de générer une nouvelle version du json. Un nouveau rafraîchissement sur la carte et le tour est joué. Sans douleur, donc !

Comme on passait quand même à une échelle largement supérieure à celle des départementales, je voulais m'assurer que le parser supporterait la charge.

Tom a eu la gentillesse de m'aider dans cette tâche sur son temps libre, avec en plus :

Et après plusieurs heures de codage intensif, nous sommes arrivés à une carte du second tour de la dernière présidentielle optimale, bien reliée à une feuille de calcul Google :

acal_pre012

Cliquez sur l'image pour l'agrandir

XML et CSV

Restait plus, à ce stade, qu'à nous assurer d'avoir des données régulièrement mises à jour le jour J. Là, ça s'est un peu compliqué, car :

Mais heureusement, le Ministère de l'Intérieur allait mettre à disposition de la presse des XML mis à jour tous les quarts d'heure. La principale difficulté consistait à convertir ce format composé de balises en tableur prêt à être copié/collé dans Google Drive.

Je dois reconnaître que ce n'est pas franchement mon domaine, contrairement au camarade Ettore Rizza. Ettore a écrit un script directement taillé pour les XML de l'ACAL.

Une fois digéré par Open Refine, on obtenait grâce à ce script des données bien propres et prêtes à être téléchargées au format CSV.

Plus qu'à mettre en oeuvre tout ça le grand soir venu :-)

Les limites de l'exercice

Dans l'ensemble, tout s'est passé sans encombre, mais il faut quand même signaler quelques embûches et aspects perfectibles, notamment :

Le bilan

Ce travail de longue haleine a payé avec des audiences plutôt bonnes pour ce genre d'événements sur Rue89 S : 18 000 vues pour le premier tour, et à peu près la moitié pour le second.

Nous avons également réussir à corriger le tir pour les faiblesses repérées lors du premier tour (notamment les villes manquantes) pour pouvoir optimiser le traitement live.

J'ai également codé une nouvelle version de la carte pour le second tour, en intégrant un dégradé selon le pourcentage du vainqueurConcrètement, cela nous a permis de passer de ça :

acal_m0le_t1

Cliquez sur l'image pour accéder à la page du premier tour

A ça :

acal_m0le_t2

Cliquez sur l'image pour accéder à la page du second tour

Petite fierté strictement perso : notre carte du premier tour s'est retrouvé dans le Top 10 hebdomadaire du Global Investigative Journalism Network. Pour la petite histoire, c'est la seconde fois de l'année :-) !

Le template codé avec Tom va maintenant nous permettre d'étudier en profondeur l'ACAL, territoire plein de disparités comme en témoignent ces "cartes de force" du PS, du FN et des Républicains :

psfnlracal

Bref, ça promet pour 2016 !

J'en profite pour remercier une nouvelle fois les excellents Tom, Ettore et Joël pour leur précieuse aide !

PS : le code source de la carte du premier tour sera bientôt publié.