Archives annuelles : 2019

Instal­ler un serveur Bitwar­den_rs

Avoir des mots de passe solides, c’est bien (et même indis­pen­sable), mais s’en souve­nir… c’est dur. On serait tenté de tout enre­gis­tré dans son navi­ga­teur, avec un mot de passe maître pour stocker les mots de passe de façon chif­frée mais… Fire­fox par exemple a un système de chif­fre­ment par mot de passe maître tout pourri.

Il existe un paquet de gestion­naire de mot de passe libre. Évacuons tous ceux basé sur KeePass ou ses succes­seurs : pour utili­ser ses mots de passe sur un autre PC ou sur son télé­phone, il faut synchro­ni­ser le fichier conte­nant les mots de passe et s’il y a un souci de synchro et que le fichier se retrouve corrom­pu… paf, pastèque !.

J’ai essayé Pass­bolt ou encore l’ap­pli­ca­tion Pass­man de Next­cloud mais quand j’uti­li­sais la sécu­rité maxi­male qu’ils propo­sent… mon Fire­fox plan­tait (oui, quand on me propose des réglages de parano, je les utilise). Sans comp­ter qu’ils ne proposent pas d’ap­pli Android.

Et puis, j’ai testé Bitwar­den. Et c’est pas mal du tout, mais… c’est du C# et ça utilise une base de données SQL Server. Deux trucs Micro­soft.

Bon, passant outre mon aver­sion, j’ai testé. Dans du Docker (quand je vous dis que je suis passé outre mon aver­sion !). C’était pas mal du tout.

Mais en voulant tester le partage de mot de passe (dans l’hy­po­thèse d’une utili­sa­tion chez Frama­soft), j’ai rencon­tré une limi­ta­tion : pour créer une orga­ni­sa­tion (un groupe de personnes qui se partagent des mots de passe) de plus de deux personnes, il faut payer, même quand on héberge soi-même le serveur Bitwar­den. Pourquoi pas. C’est un busi­ness model comme un autre (mais bon, grmpf).

Par contre, les tarifs, c’est un très gros grmpf : 3 dollars par utili­sa­teur et par mois. Pour Frama­soft, cela ferait 3$ * 35 personnes * 12 mois = 1 260$ par an. Y a un autre plan qui pour­rait conve­nir, qui nous revien­drait à 780$ par an. C’est quand même pas négli­geable (surtout pour une asso­cia­tion qui ne vit quasi­ment que de vos dons) alors qu’on héber­ge­rait nous-même le service.

J’avais laissé tombé quand ces derniers jours, une implé­men­ta­tion en Rust de Bitwar­den est passée dans ma time­line Masto­don : https://github.com/dani-garcia/bitwar­den_rs. Et celle-ci n’a pas la limi­ta­tion sur les équipes (mais il encou­rage à donner des sous au projet upstream).

J’ai d’abord testé avec le contai­ner Docker fourni par le déve­lop­peur puis j’ai tenté la compi­la­tion pour voir si ça passait, et ça passe crème !

La grosse diffé­rence, outre la non-limi­ta­tion des orga­ni­sa­tions, c’est que la base de données est, pour l’ins­tant, SQLite. Ce qui peut avoir des consé­quences sur les perfor­mances lorsque la base est très solli­ci­tée.

Ceci dit, Frama­drop tourne toujours avec une base SQLite et ça fonc­tionne bien, et mon instance Lutim, ainsi que Frama­pic ont long­temps utilisé SQLite.

Bref, voyons comment compi­ler et instal­ler cette version de Bitwar­den en Rust.

Compi­la­tion

On va avoir besoin des back­ports Debian pour instal­ler npm (pour compi­ler l’in­ter­face web) :

echo "deb http://ftp.debian.org/debian stretch-backports main" | sudo tee /etc/apt/sources.list.d/backports.list
sudo apt update

Instal­la­tion des dépen­dances :

sudo apt install pkg-config libssl-dev
sudo apt install -t stretch-backports npm

Instal­la­tion de rustup, qui nous four­nira le compi­la­teur Rust :

curl https://sh.rustup.rs -sSf > rustup.sh

On n’exé­cute pas direct un script tiré du web ! On regarde d’abord s’il ne va pas faire de salo­pe­ries :

vi rustup.sh

On le rend exécu­table :

chmod +x rustup.sh

On installe le compi­la­teur Rust (il sera dans notre $HOME) :

./rustup.sh --default-host x86_64-unknown-linux-gnu --default-toolchain nightly

On source un fichier qui nous permet de l’ap­pe­ler

source $HOME/.cargo/env

Gagnons du temps en clonant le projet bitwar­den_rs et l’in­ter­face web (qu’il faut compi­ler aussi) en même temps .

git clone https://github.com/dani-garcia/bitwarden_rs
git clone https://github.com/bitwarden/web.git web-vault

Compi­la­tion de Bitwar­den_rs :

cd bitwarden_rs
cargo build --release

Le résul­tat de la compi­la­tion est dans bitwarden_rs/target/release/.

Compi­la­tion de l’in­ter­face web :

cd ../web-vault
# On se positionne sur le dernier tag en date
git checkout "$(git tag | tail -n1)"
# Un petit patch pour que ça fonctionne avec notre installation
wget https://raw.githubusercontent.com/dani-garcia/bw_web_builds/master/patches/v2.8.0.patch
# On vérifie le patch
cat v2.8.0.patch
git apply v2.8.0.patch
npm run sub:init
npm install
npm run dist

ATTENTION : on m’a dit que la compi­la­tion de l’in­ter­face web prenait 1,5Gio de RAM, assu­rez-vous que vous en avez assez de libre.

Et on copie l’in­ter­face web dans le dossier où attend le résul­tat de la compi­la­tion de bitwar­den_rs :

cp -a build/ ../bitwarden_rs/target/release/web-vault/

Instal­la­tion

On va instal­ler Bitwar­den_rs dans /opt/bitwarden et on le fera tour­ner avec l’uti­li­sa­teur www-data :

cd ..
sudo rsync -a --info=progress2 bitwarden_rs/target/release/ /opt/bitwarden/
chown -R www-data: /opt/bitwarden

Puis on va créer un service systemd, /etc/systemd/system/bitwarden.service :

[Unit]
Description=Bitwarden Server (Rust Edition)
Documentation=https://github.com/dani-garcia/bitwarden_rs
After=network.target

[Service]
# The user/group bitwarden_rs is run under. the working directory (see below) should allow write and read access to this user/group
User=www-data
Group=www-data
# The location of the .env file for configuration
EnvironmentFile=/etc/bitwarden_rs.env
# The location of the compiled binary
ExecStart=/opt/bitwarden/bitwarden_rs
# Set reasonable connection and process limits
LimitNOFILE=1048576
LimitNPROC=64
# Isolate bitwarden_rs from the rest of the system
PrivateTmp=true
PrivateDevices=true
ProtectHome=true
ProtectSystem=strict
# Only allow writes to the following directory and set it to the working directory (user and password data are stored here)
WorkingDirectory=/opt/bitwarden/
ReadWriteDirectories=/opt/bitwarden/

[Install]
WantedBy=multi-user.target

Pour l’in­ter­face d’ad­mi­nis­tra­tion, on va créer un token avec :

openssl rand -base64 48

La confi­gu­ra­tion se fait via des variables d’en­vi­ron­ne­ment qu’on va mettre dans /etc/bitwarden_rs.env :

SIGNUPS_ALLOWED=false
WEBSOCKET_ENABLED=true
ADMIN_TOKEN=Un token généré avec `openssl rand -base64 48`
ROCKET_ADDRESS=127.0.0.1
WEBSOCKET_ADDRESS=127.0.0.1
SMTP_HOST=127.0.0.1
SMTP_FROM=bitwarden@example.org
SMTP_PORT=25
SMTP_SSL=false

Vous remarque­rez que je dis à Bitwar­den d’en­voyer les mails via le serveur SMTP local. À vous de faire en sorte qu’il fonc­tionne. Allez voir le wiki du projet pour voir quelles variables vous pour­riez ajou­ter, enle­ver, modi­fier…

Puis :

sudo systemctl daemon-reload
sudo systemctl enable bitwarden
sudo systemctl start bitwarden
sudo systemctl status bitwarden

Nginx

On installe Nginx s’il n’est pas déjà installé :

sudo apt install nginx

Confi­gu­ra­tion du virtual­host :

server {
    listen 80;
    listen [::]:80;
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name bitwarden.example.org;

    access_log /var/log/nginx/bitwarden.access.log;
    error_log /var/log/nginx/bitwarden.error.log;

    ssl_certificate      /etc/letsencrypt/live/bitwarden.example.org/fullchain.pem;
    ssl_certificate_key  /etc/letsencrypt/live/bitwarden.example.org/privkey.pem;

    ssl_session_timeout 5m;
    ssl_session_cache shared:SSL:5m;

    ssl_prefer_server_ciphers On;
    ssl_protocols TLSv1.2;
    ssl_ciphers 'EECDH+aRSA+AESGCM:EECDH+aRSA+SHA384:EECDH+aRSA+SHA256:EECDH:+CAMELLIA256:+AES256:+CAMELLIA128:+AES128:+SSLv3:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!DSS:!RC4:!SEED:!ECDSA';

    ssl_dhparam /etc/ssl/private/dhparam4096.pem;
    add_header Strict-Transport-Security max-age=15768000; # six months
    gzip off;

    if ($https != 'on') {
        rewrite ^/(.*)$ https://pass.framasoft.org/$1 permanent;
    }

    root /var/www/html;

    # Allow large attachments
    client_max_body_size 128M;

    location ^~ '/.well-known/acme-challenge' {
        default_type "text/plain";
        root /var/www/certbot;
    }

    location / {
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_pass http://127.0.0.1:8000;
    }

    location /notifications/hub {
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_pass http://127.0.0.1:3012;
    }

    location /notifications/hub/negotiate {
        proxy_pass http://127.0.0.1:8000;
    }
}

Pour créer /etc/ssl/private/dhparam4096.pem :

sudo openssl dhparam -out /etc/ssl/private/dhparam4096.pem 4096

Pour le certi­fi­cat Let’s Encrypt, on commente le brol rela­tif à ssl puis :

sudo nginx -t && sudo nginx -s reload
sudo apt install certbot
sudo mkdir /var/www/certbot/
certbot certonly --rsa-key-size 4096 --webroot -w /var/www/certbot/ --agree-tos --text --renew-hook "/usr/sbin/nginx -s reload" -d bitwarden.example.org

Une fois qu’on a le certi­fi­cat, on décom­mente le brol ssl puis :

sudo nginx -t && sudo nginx -s reload

Sauve­garde

Créer le script de sauve­garde /opt/backup_bitwarden.sh :

#!/bin/bash
function bwbackup {
    DATE=$(date '+%a%H')

    # Database
    if [[ ! -d /opt/backup_bitwarden/sqlite-backup/ ]]
    then
        mkdir -p /opt/backup_bitwarden/sqlite-backup/
    fi
    echo ".backup /opt/backup_bitwarden/sqlite-backup/db.${DATE}.sqlite3" | sqlite3 /opt/bitwarden/data/db.sqlite3 2>> /opt/backup_bitwarden/backup.log
    if [[ "$?" -ne "0" ]]
    then
        echo "Something went wrong with bitwarden database backup, please see /opt/backup_bitwarden/backup.log on verity" | mail -s "Bitwarden database backup" tech@framalistes.org
        bwbackup
    fi

    # Files
    if [[ ! -d /opt/backup_bitwarden/files-backup/ ]]
    then
        mkdir -p /opt/backup_bitwarden/files-backup/
    fi
    rsync -a --delete --exclude db.sqlite3 /opt/bitwarden/data/ /opt/backup_bitwarden/files-backup/$DATE/ 2>> /opt/backup_bitwarden/backup.org
    if [[ "$?" -ne "0" ]]
    then
        echo "Something went wrong with bitwarden files backup, please see /opt/backup_bitwarden/backup.log on verity" | mail -s "Bitwarden files backup" tech@framalistes.org
        bwbackup
    fi
}
bwbackup

Puis :

sudo chmod +x /opt/backup_bitwarden.sh
sudo mkdir /opt/backup_bitwarden
sudo chown www-data: /opt/backup_bitwarden
sudo apt install sqlite3

Puis, dans le cron de l’uti­li­sa­teur www-data :

42 4 * * * /opt/backup_bitwarden.sh

Logs

J’aime bien avoir mes logs dans un dossier dédié pour ce genre de service.

Dans /etc/rsyslog.d/bitwarden.conf :

if $programname == 'bitwarden_rs' then /var/log/bitwarden/bitwarden.log
if $programname == 'bitwarden_rs' then ~

Dans /etc/logrotate.d/bitwarden :

/var/log/bitwarden/bitwarden.log
{
        rotate 52
        dateext
        weekly
        missingok
        notifempty
        compress
        sharedscripts
        postrotate
                invoke-rc.d rsyslog rotate > /dev/null
        endscript
}

Puis :

sudo mkdir /var/log/bitwarden
sudo chown root:adm /var/log/bitwarden
sudo service rsyslog restart

Fail2­ban

Un fail2­ban qui surveille les logs, ça permet de bloquer les petits malins qui font du brute­force

Dans /etc/fail2ban/filter.d/bitwarden.conf :

[INCLUDES]
before = common.conf

[Definition]
failregex = ^.*Username or password is incorrect\. Try again\. IP: <HOST>\. Username:.*$
ignoreregex =

Dans /etc/fail2ban/jail.d/bitwarden.local :

[bitwarden]
enabled = true
port = 80,443
filter = bitwarden
action = iptables-allports[name=bitwarden]
logpath = /var/log/bitwarden/bitwarden.log
maxretry = 3
bantime = 14400
findtime = 14400

Pour la page d’ad­min, dans /etc/fail2ban/filter.d/bitwarden-admin.conf :

[INCLUDES]
before = common.conf

[Definition]
failregex = ^.*Unauthorized Error: Invalid admin token\. IP: <HOST>.*$
ignoreregex =

Dans /etc/fail2ban/jail.d/bitwarden-admin.local :

[bitwarden-admin]
enabled = true
port = 80,443
filter = bitwarden-admin
action = iptables-allports[name=bitwarden]
logpath = /var/log/bitwarden/bitwarden.log
maxretry = 3
bantime = 14400
findtime = 14400

Fina­le­ment :

sudo service fail2ban restart

Conclu­sion

Voilà, vous devriez avoir un serveur Bitwar­den_rs fonc­tion­nel. Plus qu’à aller sur l’in­ter­face web que vous venez de mettre en place ou télé­char­ger les clients et à les utili­ser !

Pour impor­ter vos mots de passe de Fire­fox, il faut passer par une appli­ca­tion pour les expor­ter, puis aller dans les outils de votre client (ou de l’in­ter­face web).

EDIT 15/01/2019 Rempla­ce­ment de la mention de l’ap­pli­ca­tion Next­cloud Pass­words par l’ap­pli­ca­tion Pass­man (je me suis trompé).

EDIT 17/01/2019 Rempla­ce­ment de npm run dist par npm run dist:selfhost dans la compi­la­tion de l’in­ter­face web. Cela désac­tive Google Analy­tics (voir https://github.com/bitwar­den/web/issues/243#issue­comment-412852726)

EDIT 18/01/2019 Rempla­ce­ment de npm run dist:selfhost par npm run dist dans la compi­la­tion de l’in­ter­face web. Google Analy­tics est déjà désac­tivé par le patch. Il semble­rait que j’ai vu passer des requêtes vers Google Analy­tics à cause du cache de mon navi­ga­teur qui gardait une version non patchée.

EDIT 18/01/2019 Ajout d’un aver­tis­se­ment sur la consom­ma­tion de RAM lors de la compi­la­tion de l’in­ter­face web.

Crédits : Photo par Matt Artz sur Unsplash

Me soutenir sur Tipeee Me soutenir sur Liberapay

Créer une boutique en ligne avec Word­press

Dans mon précé­dent article, j’évoquais le fait que j’ai ouvert ma boutique en ligne. Je vais expliquer un peu comment j’ai fait pour la mettre en place.

Le logi­ciel de base : Word­press

Pourquoi Word­press et pas Pres­ta­shop ou Magento qui sont des outils dédiés à la vente en ligne ? Plusieurs raisons à cela :

  • je connais déjà bien Word­press, je n’avais pas spécia­le­ment envie de m’enquiqui­ner à instal­ler d’autres trucs ;
  • Word­press, bien que ce soit au départ un moteur de blog, est un CMS que l’on peut tordre dans pas mal de sens. Je me suis dit que j’avais envie de voir si c’était simple d’en faire un site de vente en ligne ;
  • j’ai quand même essayé d’uti­li­ser Pres­ta­shop… sans réus­sir à passer la dernière étape d’ins­tal­la­tion : la mise en place de la base de données tombait en timeout à chaque fois (j’ai pas un énorme serveur et il est déjà bien plein de trucs).

Bref : on commence par instal­ler un Word­press. Je ne vais pas détailler, c’est un sujet fort bien traité sur les Inter­netz.

Les exten­sions

Pour trans­for­mer Word­press en boutique en ligne, il faut instal­ler quelques modules. Mais avant ça, voici ceux que j’ai installé pour la sécu­rité, les perfor­man­ces… :

  • Antis­pam Bee, pour l’an­tis­pam ;
  • iThemes Secu­rity, pour la sécu­rité ;
  • Smush, pour réduire la taille des images ;
  • WP Super Cache, pour les perfor­mances.

Ensuite, des exten­sions pour amélio­rer la boutique, mais pas obli­ga­toires :

  • Contact Form 7, pour le formu­laire de contact ;
  • Google XML Site­maps, pour amélio­rer le réfé­ren­ce­ment ;
  • Masto­don Auto­post, pour pouet­ter auto­ma­tique­ment quand on ajoute un article à la boutique.

Voici les exten­sions pour la boutique elle-même :

  • WooCom­merce, l’ex­ten­sion prin­ci­pale, propo­sée par la boîte qui déve­loppe Word­press, donc ça va, j’ai assez confiance sur la compa­ti­bi­lité ;
  • WooCom­merce Blocks, pour faire fonc­tion­ner WooCom­merce avec le nouvel éditeur de Word­press ;
  • WooS­wipe, pour avoir une gale­rie d’image sur les pages des produits (quand on clique sur l’image pour zoomer, pis pour voir les autres images, vous voyez le genre) ;
  • WooCom­merce Weight Based Ship­ping, pour gérer les frais d’en­voi selon le poids de la commande ;
  • Payment Gate­way Based Fees and Discounts for WooCom­merce, pour pouvoir ajou­ter des frais selon la méthode de paie­ment choi­sie.

Le thème

Il va de soit qu’un thème pour un blog a peu de chance d’al­ler pour faire une boutique. J’ai choisi le thème Shop Isle, que je trouve simple et bien foutu. J’en ai néan­moins fait un thème enfant pour déga­ger ces cochon­ne­ries de google fonts.

Les frais d’en­voi

L’ex­ten­sion « WooCom­merce Weight Based Ship­ping » me permet de défi­nir des frais d’en­voi selon le poids de la commande ainsi que sa desti­na­tion (vous imagi­nez bien qu’en­voyer deux cartes postales en France ne coûte pas le même prix qu’en envoyer 15 dans un autre pays).

Cette exten­sion est parfaite, à l’ex­cep­tion de l’in­ter­face pour choi­sir les pays de desti­na­tion quand on crée les règles : ça va bien quand on ajoute une ou deux desti­na­tions, mais pas quand on doit en sélec­tion­ner 12 (france métro­po­li­taine + DOM/TOM) ou plus (les pays de l’UE).

Person­nel­le­ment, j’ai choisi de faire des frais d’en­voi à prix plus ou moins coûtant : le tarif des timbres, arrondi un peu au-dessus pour faire le prix de l’en­ve­loppe. Je ne dis pas que je ne fais pas un peu de béné­fice dessus, mais ça se compte à coup de centimes.

Le paie­ment

WooCom­merce embarque déjà plusieurs moyens de paie­ments, je dois dire que c’est très bien foutu !

J’ai activé le vire­ment SEPA, parce que ça ne coûte rien, ni à l’en­voyeur, ni au desti­na­taire. Par contre, comme ça prend du temps (le vire­ment prend géné­ra­le­ment 24h pour appa­raître sur les comptes, sans comp­ter que certaines banques mettent plusieurs jours pour accep­ter un nouvel IBAN et permettre des vire­ments vers celui-ci), j’ai ajouté la possi­bi­lité d’uti­li­ser Paypal : ça propose d’uti­li­ser son compte Paypal (et c’est assez répandu pour que ça soit pratique pour un paquet de gens) pour payer ou la carte bancaire. Par contre, ça m’a fait deux blagou­nettes :

  • pour effec­ti­ve­ment pouvoir récu­pé­rer les paie­ments, j’ai du passer mon compte en compte busi­ness. Rien de bien méchant, mais la récu­pé­ra­tion des sous ne fonc­tion­nait pas et rien n’in­diquait sur Paypal que c’était ce qu’il fallait faire (il y avait juste un message d’er­reur complè­te­ment inutile). Une fois mon compte passé en busi­ness, plus de souci ;
  • mais du coup, des frais s’ap­pliquent (pas pour le client, qui paie bien ce que ma boutique lui indiquait, mais pour moi : je ne récu­père pas autant d’argent que ce qu’a payé le client). Comme je ne souhaite pas en être de ma poche, j’ai installé « Payment Gate­way Based Fees and Discounts for WooCom­merce » qui me permet d’ajou­ter le pour­cen­tage (3,4%) et le forfait (0,25€) de la commis­sion lorsqu’on choi­sit Paypal pour payer.

Condi­tions géné­rales de vente

Pour les rédi­ger, j’ai d’abord cher­ché sur le web, et je suis tombé sur https://www.donnees­per­son­nelles.fr/cgv, qui propose carré­ment une exten­sion Word­press. Après l’avoir instal­lée, je me suis contenté de repom­per les CGV qu’elle propo­sait : ça m’a permis, tout d’abord, de les lire, et ensuite de corri­ger des typos.

Après quoi, j’ai désins­tallé l’ex­ten­sion 😁

Conclu­sion

Je ne pense pas qu’il soit néces­saire pour moi de trop détailler le réglage des diffé­rentes exten­sions : les infos se trouvent assez faci­le­ment sur le web, et même si les réglages sont touf­fus, c’est assez intui­tif. La plus grosse partie du temps fut perdue dans la recherche des exten­sions et du thème kivon­bien.

Après quelques tâton­ne­ments, la mise en place de ma boutique fut assez simple. J’es­père que cet article servira à d’autres pour leur éviter de cher­cher autant que moi.

Crédits : Photo par Mike Petrucci sur Unsplash

Me soutenir sur Tipeee Me soutenir sur Liberapay