# Belenios Belenios est un service développé par l'Inria recréant un bureau de vote complet en ligne avec autant voire plus de sécurité grâce à des bulletins chiffrés. Il a été mis en place pour l'assemblée générale du Crans en 2020, alors que la pandémie de Covid-19 empêchait toute réunion physique. ## Installation On considère que l'on dispose d'une machine virtuelle neuve installée sous Debian Bullseye. Belenios n'est malheureusement pas encore packagé dans Debian. Par chance, toutes ses dépendances le sont. On installe donc toutes les dépendances via APT, puis on compile Belenios manuellement. ### Dépendances Belenios est intégralement écrit en OCaml. On installe toutes ses dépendances Debian, comme indiqué dans le README : ```bash sudo apt update sudo apt install --no-install-recommends bubblewrap build-essential ca-certificates cracklib-runtime jq libgd-securityimage-perl libgmp-dev libncurses-dev libpcre3-dev libssl-dev libsqlite3-dev m4 pkg-config unzip wget zip zlib1g-dev ``` On installe ensuite toutes les dépendances OCamL depuis les paquets Debian, ce qui est plus économe par rapport à compiler toutes les bibliothèques avec Opam : ```bash sudo apt install --no-install-recommends dune eliom libatdgen-ocaml-dev libcalendar-ocaml-dev libcmdliner-ocaml-dev libcryptokit-ocaml-dev libcsv-ocaml-dev libgettext-ocaml-dev libzarith-ocaml-dev ``` On doit enfin installer `ocsigenserver`, qui sert de serveur web tel Nginx ou Apache adapté pour les projets OCaml : ```bash sudo apt install --no-install-recommends ocsigenserver ``` ### Compilation de Belenios On commence par cloner le dépôt dans un endroit adapté : ```bash sudo git clone https://gitlab.inria.fr/belenios/belenios.git /opt/belenios -b 1.14 ``` Il suffit ensuite dans le dossier `/opt/belenios` de lancer `make build-release-server`. ### Liens symboliques Pour avoir des binaires à des endroits cohérents avec la distribution Debian, on ajoute des liens symboliques à des endroits pertinents : ```bash sudo ln -s /opt/belenios/_run/usr/lib/belenios /usr/lib/ocaml/belenios sudo ln -s /opt/belenios/_run/usr/lib/belenios-platform /usr/lib/ocaml/belenios-platform sudo ln -s /opt/belenios/_run/usr/lib/belenios-platform-js /usr/lib/ocaml/belenios-platform-js sudo ln -s /opt/belenios/_run/usr/lib/belenios-platform-native /usr/lib/ocaml/belenios-platform-native sudo ln -s /opt/belenios/_run/usr/lib/belenios-server /usr/lib/ocaml/belenios-server sudo ln -s /opt/belenios/_run/usr/lib/belenios-tool /usr/lib/ocaml/belenios-tool sudo ln -s /opt/belenios/_run/usr/share/belenios-server /usr/share/belenios-server ``` ### Configuration de ocsigenserver On commence par créer les dossiers de données qui nous intéressent, avec les bonnes permissions : ```bash sudo -u ocsigen mkdir -p /etc/ocsigenserver/conf.d /var/lib/belenios /var/lib/belenios/data /var/lib/belenios/upload /var/lib/belenios/spool /var/log/belenios ``` On ajoute enfin le fichier de configuration fourni par Belenios dans `/etc/ocsigenserver/conf.d/belenios.conf`, en remplaçant les bonnes variables : ```xml 8001 /var/log/belenios /var/lib/belenios/data /var/lib/belenios/upload 1024kB 500 /var/run/ocsigenserver_command utf-8 ``` Il faut noter que ``ocsigenserver`` n'est pas lancé au démarrage par défaut et un ``systemctl start ocsigenserver`` ne fonctionne pas, un `service ocsigenserver start` en revanche si. Pour autoriser `ocsigenserver` à se lancer au démarrage, il faut modifier le fichier `/etc/default/ocsigenserver` pour écrire `LAUNCH_AT_STARTUP=true`. Il sera ensuite possible de démarrer le serveur grâce à systemd. En redémarrant `ocsigenserver`, Belenios sera accessible sur son port 80. Après une configuration de reverse-proxy près, Belenios est déjà accessible :) Pour modifier le logo, il faut regarder autour de `/usr/share/belenios-server/logo.png`. ### Déployer avec Ansible L'ensemble des opérations décrites sont déployées par le rôle Ansible du Crans . Il prend en configuration le nom de domaine utilisé (``belenios.domain``), des adresses mails de contact (`belenios.email_contact` et `belenios.email_from`) ainsi que les paramètres du CAS (`belenios.cas.name` et `belenios.cas.server`, voir ci-dessous). ## Utilisation Toute personne ayant un compte Crans peut créer une élection sur Belenios en se connectant via le CAS du Crans. Cela se configure sur la ligne du fichier de configuration ocsigenserver : ```xml ``` On peut remplacer le nom par ``CAS Cr@ns`` et le serveur par . Une fois connecté, on peut créer et administrer une élection. ### Gestion des mots de passe Belenios propose deux modes pour gérer les mots de passe : * Automatique (mode dégradé : les codes de vote seront générés par le serveur) * Manuel (mode sécurisé : un tiers se chargera des codes de vote) Dans le premier mode, Belenios se charge de générer les codes de vote et les envoie lui-même par mail. Dans le second mode, recommandé, c'est vous qui envoyez vous même les codes de vote aux électeurs. Le code de vote ne servant qu'à débuter l'élection pour une personne, la sécurité ne réside pas ici. C'est plus ou moins l'équivalent de donner son nom au bureau de vote. Ce n'est pas une information sensible. À la fin du vote on demande aux votants de réellement s'identifier avant de glisser les bulletins dans l'urne. On dispose de deux moyens d'authentification : * Générer des mots de passe confidentiels (hashés sur le serveur) par personne, géré par Belenios ; * Utiliser un CAS. Il va de soi qu'on vous recommande la deuxième option. Cela peut être n'importe quel serveur CAS, pas nécessairement celui du Crans. Par exemple, on utilisera pour le Crans, pour la Note Kfet, ou pour celui de l'Inria. Pensez bien à autoriser Belenios à utiliser votre serveur CAS, et à faire attention à ce que les pseudos renvoyés soient en ASCII ! Plus d'informations ici : . ### Inscription des électeurs La liste des électeurs doit être arrêtée avant la création de l'élection. La liste doit être donnée sous la forme `ADRESSE@EMAIL,PSEUDO`. Depuis la dernière version, il est également possible de définir un poids par électeur. **Atention :** Belenios ne supporte pas l'UTF-8 dans les pseudos. Assurez-vous de garder des pseudos ASCII. Et dans les adresses e-mail, mais cela va de soi. #### Générer la liste des adhérents avec Re2o Pas besoin de plus d'une ligne : ```python "\n".join(map(lambda user: f"{user.get_mail},{user.pseudo}", utils.all_adherent(including_asso=False).filter(adherent__isnull=False))) ``` C'est faux : il faut importer `utils` et sans doute écrire dans un fichier. ### Déclaration des autorités de déchiffrement Il s'agit de l'équivalent des assesseurs qui vont contrôler et dépouiller l'élection. Il peut y en avoir plusieurs. Chacun aura sa clé, et la clé sera nécessaire pour le dépouillement. Dans tous les cas, Belenios lui-même est une autorité de déchiffrement mais il est recommandé d'avoir une autorité extérieure. **IMPORTANT :** Cela tient plus du mauvais pressentiment que de l'expérience, mais pensez bien à VRAIMENT conserver la clé privée en lieu sûr, elle n'est pas récupérable. Jeter sa clé privée, c'est comme acheter une urne en verre incassable avec une serrure qui tient le coup et jeter le trousseau dans les égouts, en veillant à la fondre et la broyer avant. Vous pourrez ajouter des bulletins dans l'urne mais jamais la dépouiller. ### Élection Une fois l'élection créée, il n'est plus possible de la modifier, ce qui est normal. Il est possible de définir les horaires d'ouverture de l'élection (attention : les horaires sont sur le fuseau UTC !). Pour voter, chaque participant doit présenter son code d'élection, voter pour chacune des questions, puis soumettre son bulletin en s'authentifiant via le moyen défini. Son bulletin est ensuite chiffré et enregistré. Il est possible de revoter autant de fois que nécessaire, chaque vote annulant le précédent. ### Dépouillement Après l'élection, et pas avant (ce qui n'est de toute façon pas possible), chaque autorité de déchiffrement doit soumettre sa clé privée pour ouvrir l'urne. Une fois cela fait, les résultats sont publics sur la page de l'élection.