Du libre, du code, des idées, du mélange d’ArraKISS…

De l’épice pour la pensée

Aux utilisateurs du CHATONS 3hg.fr et ouaf.xyz, en cette fin d'année, il est temps de faire un peu de tri.

Certains ne se sont jamais connectés avec leur comptes : sauf alerte de leur part, ils seront supprimés.
Certains comptes n'ont pas été utilisés depuis plus de 6 mois : ces derniers seront fermé aussi.

N'hésitez pas à nous faire signe si besoin.

logo 3hg

Pour ceux que ça intéresse, voici comment je procède pour savoir si un utilisateur a consulté ses messages. Non, je ne regarde pas les logs, c'est beaucoup plus simple : je regarde la date de dernier accès au dossier des utilisateurs. Dans l'exemple ci-dessous, c'est réglé sur 6 mois :


DOMAINS='3hg.fr
ouaf.xyz
yeuxdelibad.net'

for d in $DOMAINS; do
        for u in /mnt/bigstorage/vmail/$d/*; do
                if [ ! -d $u/Maildir ]; then
                        echo "Never logged : $(basename $u)"
                else
                        LASTACCESS=$(stat -f %m $u/Maildir)
                        if [ $LASTACCESS -lt $SIXMONTHAGO ]; then
                                echo $(basename $u)
                        fi
                fi
        done
done

Bon, c'est très spécifique à ma configuration, mais c'est juste pour l'idée.

Avec les copains geeks, on fait tourner sur mon serveur un CHATONS depuis 6 mois environ. Mais non, pas un "chaton" 🐱, un CHATONS, initiative lancée par Framasoft pour décentraliser le web et permettre à chacun de proposer des services.

logo chatons

Nous nous orientons principalement sur l'hébergement de mails, avec un accent sur la confidentialité puisque le webmail est accessible via un service caché tor. Il y a aussi des salons de discussion et des pastebins chiffrés. Deux domaines sont gérés : 3hg.fr et ouaf.xyz selon le degré de sérieux souhaité. Un domaine sobre et un domaine pour les chatons qui veulent passer incognito :P

À ce jour, il y a 121 comptes. 121 !!! oO

À ceux qui hésitent à lancer leur propre service CHATONS, voici quel investissement cela demande (en gros).

Au début :
Il faut mettre en place le serveur. C'est le plus long et le plus fastidieux. Selon les choix que vous faites, entre du tout prêt (YUNOHOST) ou quelque chose de plus pointu correspondant à ce que vous souhaitez proposer (chiffrement du disque, hébergement du nom de domaine, accès chiffré...), il faut compter entre une semaine et un mois. Ça dépend aussi de votre aisance avec ces notions.

Quotidiennement :
Tous les jours, autant que possible, il faut essayer de réaliser ces tâches :

  • Vérifier si des mises à jour de sécurité sont disponibles et les appliquer : de 5 à 10 minutes en moyenne.
  • Répondre aux questions des utilisateurs qui rencontrent un souci pour paramétrer leur compte ou autre : 5 minutes en moyenne.
  • Inscrire un nouvel utilisateur s'il y a demande : 3 minutes en moyenne par demande d'inscription.
  • Vérifier quels serveurs sont mis en attente par spamd qui fait du greylisting et peut refuser des mails légitimes si l'expéditeur n'a pas toujours la même adresse IP. C'est rare, mais lorsque ça arrive il faut ajouter l'IP sur liste blanche à la main. C'est un antispam redoutable, d'autant plus efficace lorsqu'il est associé à spamassassin (qui tourne lui aussi sur le serveur), mais il demande un certaine veille. Il faut environ 5 minutes en moyenne.
  • Lire les rapports quotidiens générés par le serveur sur sa bonne santé : 2 minutes en moyenne.

Bien sûr, parfois c'est plus, parfois c'est moins, mais vous vous en doutez ;)

De temps en temps :
Vérifier que la zone DNS se porte bien, puisque j'ai choisi de l'héberger afin de respecter encore plus la vie privée des utilisateurs. Les demandes de résolution vers les domaines du CHATONS font autorité chez moi. Il y a eu un peu de cafouillage au début, mais le travail de 22decembre est maintenant rodé, et il suffit de regarder environ tous les mois sur dnsviz que DNSSEC est bien correct.

Faire des sauvegardes supplémentaires au cas où, tous les mois aussi pour les mails.

Les mises à jour de sécurité sont à réaliser aussi vite que possible. Tous les 6 mois, une nouvelle version d'OpenBSD est publiée et je me donne l'objectif de le faire au plus vite, sans tout casser non plus ;). Il faut entre 15 et 30 minutes pour ça, tout dépend.

Performances

Actuellement, seulement 1,1G d'espace disque est utilisé. Merci aux utilisateurs qui récupèrent directement leurs mails sur leur ordinateur. À ce rythme, on a vraiment de la marge.
La charge du système est très faible et le service mail ne consomme quasiment aucun temps de calcul de mon petit serveur. Même le filtre spamassassin se fait oublier. J'ai un serveur très modeste, et en regardant la charge système, c'est comme si le démon mail+antispam n'existait pas. :)
Il faut dire que le parefeu rejette pas mal de bruit (avec BlockZones et vilain), tout comme spamd, ce qui préserve le serveur.

Et alors?

À l'heure où la neutralité du net est encore mise à mal, notamment aux USA, je suis ravi que nous nous soyons lancé à l'aventure, puisque ça marche bigrement bien :)

Tout ce blabla pour dire merci à ceux qui nous font confiance et nous aident généreusement à maintenir ce service, notamment via liberapay ou par de gentils messages.
L'aventure n'est pas prête de s'arrêter :D

image de NPH content

Vous avez peut-être entendu parler des CHATONS, le Collectif des Hébergeurs Alternatifs, Transparents, Ouverts, Neutres et Solidaires.
Alors que vos données et la plupart des sites webs consultés sont hébergés par les GAFAM (google, amazon, facebook, apple, microsoft), l'initiative CHATONS est à mon avis déterminante. On l'a vu lors de la vague de cyberattaques récente, ou si vous regardez la série M. Robot : les bombes ça fait mal, un reset numérique aussi. Êtes-vous tranquilles sur qui héberge vos données?
Tout ces éléments m'ont motivé pour devenir, à mon niveau, membre des CHATONS.

Cependant, cela demande un peu de temps, sinon de la disponibilité. Heureusement, quelques copains sont partants pour suivre cette aventure :)
Vous l'avez peut-être déjà lu, nous avons lancé notre service d'hébergement sur 3hg.fr.

Dans cet article, je souhaite expliquer comment j'ai mis en place un serveur qui sert de CHATONS pour peut-être inspirer d'autres initiatives de ce genre.

Les contraintes
Les services proposés de doivent pas nécessiter trop de bande passante ni d'espace de stockage car le serveur sera auto-hébergé. Si nécessaire, selon le succès de l'opération, du matériel plus performant sera investit.

Oui, le service sera auto-hébergé. Sinon, comment assurer aux "clients" que leurs données sont bien effacées s'ils en font la demande si elles sont enregistrées sur un serveur loué ?

L'espace de stockage limité est quelque chose que les autres CHATONS n'ont pas, ou en tout cas dans une moindre mesure. Cependant, il y a un service trop rarement proposé qui pourtant s'affranchi très bien des contraintes ci-dessus : le mail.

Ce sera donc le service principalement proposé : une messagerie.

La mise en place
Le serveur doit être efficace, sécurisé et le plus simple possible à administrer. Sans surprises, j'ai fait le choix d'utiliser OpenBSD. Voici les étapes que j'ai suivies :

  • Réservation d'un nom de domaine chez gandi.net
  • Être serveur DNS autoritaire pour ce nom de domaine. Ce n'est pas au registre de collecter les informations sur ceux qui viendront sur mon serveur via ce domaine. Cette étape est facultative, mais puisqu'on peut, je le fais.
  • Installation d'un serveur mail comme décrit dans cet ouvrage. Les messages sortants sont signés (DKIM) et les messages entrants scannés avec spamassassin. Le webmail choisi est Rainloop car il supporte en partie le chiffrement GPG et est simple à mettre à jour contrairement à roundcube. Enfin, la connexion TLS est assurée par un certificat letsencrypt. En bonus, un accès via un service caché tor est proposé. Tout ça est décrit dans le manuel, pas de surprises.
  • Gérer les inscriptions. Alors que la plupart des inscriptions demandent une adresse mail, ce serait ridicule dans ce cas puisqu'on veut justement créer une adresse mail. J'ai donc écrit un peu de PHP pour réclamer les inscriptions.

Les inscriptions
Ce code PHP va proposer un formulaire où l'utilisateur demande un identifiant. Un captcha est fait maison (merci le code de blogotext :)) pour limiter les abus.
Une fois envoyé, ce formulaire envoie un mail aux administrateurs du site indiquant l'identifiant demandé et l'endroit où enregistrer le mot de passe pour le communiquer à l'utilisateur.

Une URL aléatoire est donnée à l'utilisateur pour récupérer ses identifiants lorsqu'ils seront prêt. Cela affiche en réalité le contenu du fichier rempli par l'administrateur lors de l'inscription et le supprime aussitôt.

Il est plus sûr de protéger avec la configuration du démon httpd le dossier contenant les identifiants.

Configuration /etc/httpd.conf :

location "/inscription/data*"   { block }

Formulaire d'inscription PHP
Si vous voulez l'utiliser, pensez à changer l'emplacement du formulaire d'inscription dans la variable "$GLOBALS['subscribe_dir']". Ce fichier est nommé "index.php" dans un dossier prévu pour l'inscription.


<?php
# *** LICENSE ***
# You can redistribute it under the terms of the MIT Licence.
# *** LICENSE ***
# File to subscribe to an account

/*

!!! Le dossier /data doit être interdit dans la config du serveur !!!

Si aucun argument : 
- Afficher un formulaire de contact qui propose le nom d'utilisateur, donne une adresse mail de contact en cas de problème
    - adresse mail souhaitée
    - mot de passe souhaité pour récupérer les identifiants
    - captcha

- Le formulaire est envoyé au sysadmin avec une url aléatoire
- Le script renvoie vers une page indiquant l'URL à suivre pour obtenir les informations sur le nouveau compte.

Si argument : 
- Vérifier si le fichier en argument existe dans /data
- Si oui, on affiche son contenu qui contient les identifiants avec un beau template, puis SUPPRIMER le fichier contenant les identifiants
- Si non, indiquer que la création du compte n'est pas encore prête ou périmée.
*/

session_start();

$GLOBALS['mail_domain'] = '3hg.fr';
$GLOBALS['mail_admin'] = 'notreal@3hg.fr'; 
$GLOBALS['subscribe_dir'] = '/chatons/inscription/';
$GLOBALS['subscribe_page'] = $GLOBALS['subscribe_dir'] . 'index.php';
$GLOBALS['nbname'] = array(
// Chiffres 0 à 16 pour captcha
'0' => 'zéro',
'1' => 'un',
'2' => 'deux',
'3' => 'trois',
'4' => 'quatre',
'5' => 'cinq',
'6' => 'six',
'7' => 'sept',
'8' => 'huit',
'9' => 'neuf',
'10' => 'dix',
'11' => 'onze',
'12' => 'douze',
'13' => 'treize',
'14' => 'quatorze',
'15' => 'quinze',
'16' => 'seize',
);
?>

<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="author" content="3hg team">
    <meta name="description" content="3hg.fr propose des services d'hébergement sur le modèle des CHATONS https://chatons.org/">
    <title>3hg.fr | Vos mails pour des humains par des humain.</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <link rel="icon" href="/favicon.png" type="image/png">
    <link rel="stylesheet" href="/css/style.css">
    <link rel="stylesheet" href="/css/fontello/css/fontello.css">
    <link rel='stylesheet' href='//cdn.jsdelivr.net/font-hack/2.020/css/hack.min.css'>
</head>
<body>
    <ul id="menu">
        <li><a href="/">3hg.fr</a></li>
        <li><a href="/chatons/index.html">CHATON-3HG</a></li>
    </ul>

    <div id="main">
        <h1 id="header">
            <a href="#">
                <img src="favicon.png" alt=".:: Inscription ::." id="logo"/>
            </a>
        </h1>


<?php

function random_str($length, $keyspace = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ')
# https://stackoverflow.com/questions/4356289/php-random-string-generator/31107425#31107425
{
    $keyspace = str_shuffle($keyspace );
    $str = '';
    $max = mb_strlen($keyspace, '8bit') - 1;
    for ($i = 0; $i < $length; ++$i) {
        $str .= $keyspace[random_int(0, $max)];
    }
    return $str;
}

function captcha() 
/* Invent captcha 
    return calculus string
    store expected result in _SESSION */
{
    $v1 = rand(0,16);
    $v2 = rand(0,100);
    $_SESSION['captcha'] = $v1 + $v2;

    $str = $GLOBALS['nbname'][strval($v1)] . " + " . $v2 . " = ";

    return $str;
}

function show_form()
{
    echo '<h2 id="inscription">Créer une adresse mail @3hg.fr</h2>';
    echo '<div id="contact_form">';
    echo '<form id="contact" class="formstyle" method="post" action="'.$GLOBALS['subscribe_page'].'">';
    echo '<ul>';
    echo '<li>';
    echo '<label for="user">Email </label>';
    echo '<input type="text" required id="user" name="user" pattern="[a-zA-Z0-9]+" placeholder="batman" maxlength="42"/> @'.$GLOBALS['mail_domain'];
    echo '<span>Adresse mail souhaitée</span>';
    echo '</li>';

    echo '<li>';
    echo '<label for="captcha">Capte-chat</label>';
    echo captcha() ;
    echo '<input type="number" required id="captcha" name="captcha" min="0" step="1" />';
    echo '<span>Êtes-vous humain ?</span>';
    echo '</li>';
    echo '<input type="submit" name="subscribe" value="Envoyer ✓" />';
    echo '</ul>';
    echo '</form>';
    echo '</div>';
}




/* Inscription demandée, on affiche la réponse */
if (!empty($_POST["subscribe"])) {
    if ( $_SESSION['captcha'] != $_POST['captcha'] ) {
        echo "Erreur de calcul ?";
    }
    else
    {
        $user = '';
        $admin_email = $GLOBALS['mail_admin'];

        // formulaire envoyé, on récupère tous les champs.
        if (!empty($_POST["user"])) {
            $user = trim($_POST["user"]);
        }

    
        if ($user != '') {

            $random_file = random_str(rand(10,75));
            $random_page = $GLOBALS['subscribe_page'] . "?patate=" . $random_file;

            $headers  = 'MIME-Version: 1.0' . "\r\n";
            $headers .= 'From: <noreply@3hg.fr>' . "\r\n" .
                    'Reply-To: <noreplay@3hg.fr' . "\r\n" .
                    'Content-Type: text/plain; charset="utf-8"; DelSp="Yes"; format=flowed '."\r\n" .
                    'Content-Disposition: inline'. "\r\n" .
                    'Content-Transfer-Encoding: 7bit'." \r\n" .
                    'X-Mailer:PHP/'.phpversion();

            $message = "Une nouvelle demande d'inscription a été faite.\r\n";
            $message .= "- Nom d'utilisateur demandé : ".$user . "\r\n";
            $message .= "- Identifiants à enregistrer dans /chatons/data/".$random_file.".txt\r\n";
            $message .= "\r\n";
            $message .= "Commandes à lancer :\r\n";
            $message .= "$ doas ajoutemailer 3hg.fr ".$user."\r\n";
            $message .= "$ doas infomailer ".$random_file.".txt\r\n";

        
            // Envoi du mail
            if (mail($admin_email, 'Demande de nouvelle inscription', $message, $headers)) {
                echo "<p>Votre demande est bien envoyée, des humains vont s'en occuper.</p>";
                echo "<p>Vous pourrez récupérer vos identifiants via: ";
                echo '<a href="'.$random_page.'">ce lien</a>.';
            } else {
                echo "<p>Une erreur est survenue lors de l'envoi du message</p>";
            };
        }
    }
}
else {
    if ( isset($_GET["patate"])) {
    $fichier =  $_GET["patate"]; 
    if ( ! ctype_alnum($fichier)){
        echo "You are a bad guy!";
        die();
    }

    $path = './data/'.$fichier.'.txt';
        if (file_exists($path)) {
            // On récupère le contenu et supprime le fichier
            $content = file_get_contents($path);
            unlink($path);

            echo "<p>Bienvenue sur 3hg.fr ☺.</p>";
            echo "<p>Vos identifiants sont : </p>";
            echo "<pre><code class='codevoid'>";

            echo $content;

            echo "</code></pre>";

            echo "<p>Ces informations sont déjà détruites, prenez-en note!</p>";
        }
        else{
            echo "<p>Il semble que votre compte ne soit pas encore prêt, ou bien le lien suivi est erroné ou périmé.</p>";
            echo "<p>Dans le premier cas, réessayez plus tard, des humains traitent votre demande.</p>";
        }

        
    }
    else {
        show_form();
    }
}
?>

<hr>

<p>Pour soutenir ce projet, n'hésitez pas à <a href="/chatons/index.html#donate" title="donate">faire un petit don</a> 😉</p>


</div>
<div id="footer">
    <em>3hg.fr &copy; 2016-2017 3hg team - <a href="./LICENCE" alt="Licence">LICENCE</a></em>
    <p class="center"><a href="http://3hg.fr" title="collectif 3hg" ><img src="/bouton3hg.gif" alt="3hg" /></a></p>
</div>

</body>
</html>

Les mots de passe
En l'état, c'est l'administrateur qui attribue le mot de passe pour l'utilisateur. Ça ne va pas.
On peut alors se tourner vers les solutions classiques d'outils PHP qui vont communiquer vers un dictionnaire ldap. Ça fonctionne sûrement très bien mais je n'ai pas trouvé de solution en laquelle j'avais vraiment confiance. Je choisis alors de me tourner vers une solution fiable d'un point de vue sécurité pour l'admin et l'utilisateur : SSH.

Lorsque l'utilisateur est créé, on le met dans un groupe particulier, par exemple "mailers".
On modifie la configuration de ssh pour que tous les utilisateurs de ce groupe n'aient accès qu'à une seule commande : "passwd", ceci afin de changer leur mot de passe :

/etc/ssh/sshd_config :

Match Group mailers
        X11Forwarding no
        AllowTcpForwarding no
        ForceCommand /usr/bin/passwd

Lorsque l'utilisateur tente de se connecter en SSH, il lui est alors proposé de modifier son mot de passe directement, sans la possibilité de faire autre chose.

$ ssh -p222 notreal@3hg.fr
notreal@3hg.fr's password:
Changing password for notreal.
Old password:
...
...

Quelques quotas
Je ne peux pas proposer un espace de stockage illimité pour les utilisateurs. Heureusement, OpenBSD a tout de prévu par défaut : je vais mettre des quotas pour les utilisateurs appartenant au groupe "mailers" :

  • Ajouter cette option au fstab : groupquota
# cat /etc/fstab : 
	782f1ddb783cdd13.b /mnt/bigstorage ffs rw,noexec,nodev,nosuid,softdep,noatime,groupquota 1 2
  • On monte la partition : mount -a
  • Définir les quotas pour tous les membres du groupe mailusers (partagé), il faut juste changer les limites. Un exemple pour 750M avec un dépassement possible jusqu'à 1G :
# edquota -g mailusers
	Quotas for group mailusers:
	/mnt/bigstorage: KBytes in use: 0, limits (soft = 750000, hard = 1000000)
			inodes in use: 0, limits (soft = 0, hard = 0)
  • Activer les quotas :
quotaon -a

Simplifier la vie des admins
C'est bien connu, il faut prendre soin de ses admins :)
Ah, et en plus, je suis fainéant, donc dès qu'il y a plus de 3 commandes à taper, j'en fais un script :D .
Vous avez peut-être vu dans le code PHP un message qui indique aux admins les commandes à lancer pour ajouter un utilisateur. Il s'agit de deux scripts qui permettent de créer un utilisateur et le placer dans le bon groupe d'utilisateurs avec un dossier personnel situé sur un espace de stockage dédié. L'autre script permet d'enregistrer les identifiants de l'utilisateur pour qu'il puisse les consulter et que le serveur http puisse supprimer ces identifiants lorsqu'ils sont affichés (permissions).


#!/bin/sh

if [ "$(whoami)" != "root" ]; then
	echo "You have to be root"
	exit 1
fi
if [ $# -ne 2 ]; then
	echo "usage:"
	echo "addmailuser domain.net user"
	exit 1
fi

/usr/sbin/useradd -m -d /dossier/contenant/les/mails/"$1"/"$2" -s /bin/sh -G mailers "$2"
if [ $? -eq 0 ]; then
	echo "Entrez le mot de passe pour ce nouvel utilisateur"
	/usr/bin/passwd "$2"

	echo "$2@$1    $2" >> /etc/mail/virtuals
	rcctl restart smtpd
else
	echo "Pseudo déjà pris"
fi

exit 0
#!/bin/sh
if [ "$(whoami)" != "root" ]; then
	echo "You have to be root"
	exit 1
fi

if [ $# -ne 1 ]; then
	echo "usage:"
	echo "inscriremailuser fichier.txt"
	exit 1
fi

FPATH="/dossier/contenant/le/site/mail/inscription/data/$1"
echo "Création de $FPATH"

/usr/bin/touch $FPATH

/usr/local/bin/vim $FPATH

if [ $? -eq 0 ]; then
	echo "Merci, l'utilisateur peut maintenant consulter ses identifiants"
fi

/usr/sbin/chown www:daemon $FPATH

exit 0

Conclusion
Je crois avoir réussi à mettre en place un truc assez simple à utiliser sans tomber dans l'utilisation d'un tas d'éléments qui seraient difficiles à sécuriser. L'avenir nous dira si c'est aussi gérable que je l'imagine. Il y a déjà 27 utilisateurs inscrits et nous cherchons à améliorer la communication avec ces derniers (forum créé) qui ne lisent pas toutes les instructions. La récupération de compte est un élément à envisager aussi.
J'encourage quiconque à se lancer dans l'aventure d'un CHATONS. Si vous avez encore des doutes, vous savez où me trouver ;)

Alors que vous êtes de plus en plus préoccupés par votre vie privée en ligne et que vous utilisez davantage de logiciels libres, vous avez peut-être encore vos comptes Gmail ou hotmail. Vos données et vos échanges sont alors inévitablement scannés mettant en cause toutes les précautions que vous prenez.

Avec le soutient des 3hg, j'ai eu envie de faire quelque chose d'utile pour tenter de répondre à ce problème. Nous vous proposons une adresse mail en @3hg.fr dans le cadre des CHATONS ainsi que quelques autres services tous disponibles via tor. Vous l'aurez deviné, le maître mot est "respect de la vie privée". Tout est expliqué sur notre site 3hg.fr et sur la fiche CHATONS.

L'architecture est à taille humaine puisqu'auto-hébergée. Je crois cependant que cela pourra rendre service à de nombreuses personnes.

N'hésitez pas à venir réclamer une adresse mail et à nous rapporter les éventuels bugs rencontrés.

Je publierai dans un prochain article des détails sur la mise en place de ce service pour celles et ceux qui souhaiteraient en faire autant.

À bientôt :)