Self-hosted password manager: installing Passbolt on FreeBSD

Arthur Duarte CC-BY-SA-4.0

Arthur Duarte CC-BY-SA-4.0

Password managers, or password safes, are an important thing these days. With the constant pressure we (IT people) put our users under to setup a different password for every single registration/application/web site, it's the best, if not only, way to keep track of these secrets. On one hand, the isolated client-side software can be really powerful and/or well integrated with the OS or the software ecosystem of the user, but it lacks the modern touch of "cloud" that makes your data available anywhere and anytime. On the other hand, a full commercial package will come with client for every device you own, and a monthly fee for cloud synchronization, but you have absolutely no control over your data (just imagine that tomorrow the company you rely on goes bankrupt).
Better safe than sorry: I don't rely on cloud services. It comes at a cost, but it's quite rewarding to show the world another way exists.
Disclaimer: I don't give a sh*t about smartphones, so my needs are computer-centric.

In order to store passwords, and more generally speaking "secrets", in such a way that I can access them anywhere/anytime, I've tried Passbolt. Passbolt is an OpenSource self-hosted password manager, written in PHP/Javascript with a database back end. Hence, install and config are not for the average Joe. On the user side it's quite clean and surprisingly stable for alpha software. So once a LAMP admin has finished installing the server part, any non-skilled user can register and start storing passwords.

Enough chit-chat, let's install.

My initial setup was a vanilla FreeBSD 10.3 install, so I've had to make everything. I won't replay every single step here, especially on the configuration side.

Prerequisites:

pkg install apache24
pkg install mod_php56
pkg install php56-gd
pkg install pecl-memcached
pkg install mysql57-server
pkg install pecl-gnupg
pkg install git
pkg install php56-pdo_mysql
pkg install sudo
pkg install php56-openssl
pkg install php56-ctype
pkg install php56-filter

Everything else should come as a dependency.

Tuning:

Apache must allow .htaccess, so you'll have to put an AllowOverride All somewhere in your configuration. You must also load the Rewrite module. Also, go now for SSL (letsencrypt is free and supported). Non-SSL install of Passbolt are for demo purpose only.
Apache will also need to execute gnupg commands, meaning the www user needs an extended $PATH. The Apache startup script provided on FreeBSD sources Apache environment variables from /usr/local/sbin/envvars and this very file sources every /usr/local/etc/apache24/envvars.d/*.env, so I've created mine:

$ cat /usr/local/etc/apache24/envvars.d/path.env
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/games:/usr/local/sbin:/usr/local/bin

You also need to tune your MySQL server. If you choose the 5.7, you must edit it's configuration. Just add the following line into [mysqld] section of /usr/local/etc/mysql/my.cnf:

sql_mode = 'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION'

This is due to a bug in Passbolt and could be useless in a not to distant future.

Install recipe:

You can now follow the install recipe at https://www.passbolt.com/help/tech/install.
Generating the GPG key is quite straightforward but you have to keep in mind that Apache's user (www) will need access to the keyring. So if you create this key and keyring with a different user, you'll have to mv and chown -R www the full .gnupg directory somewhere www can read it (outside DocumentRoot is perfectly fine).

Use git to retrieve the application code into appropriate path (according to your Apache config):

cd /usr/local/www
git clone https://github.com/passbolt/passbolt.git

Edit php files as per the documentation.

Beware the install script: make sure you chown -R www the whole passbolt directory before using cake install.
On FreeBSD you won't be able to use su to run the install script, because www's account is locked. You can use sudo instead:

sudo -u www app/Console/cake install --no-admin

Same for the admin account creation:

sudo -u www app/Console/cake passbolt register_user -u patpro@example.com -f Pat -l Pro -r admin

Follow the end of the install doc, and you should be ok. Install the Firefox passbolt extension into your browser, and point to your server.

I'm pretty happy with passbolt so far. I'll have to install a proper production server, with SSL and all, but features are very appealing, the passbolt team is nice and responsive, and the roadmap is loaded with killing features. Yeah BRING ME 2FA \o/.

Monter un serveur d’authentification multifacteur 3/3

insertedDans deux articles précédents j'ai présenté la création d'un serveur de validation YK-VAL et d'un serveur de clé YK-KSM permettant de créer une infrastructure d'authentification double facteur basée sur Yubico OTP.

Dans ce dernier article je vais détailler quelques étapes importantes pour connecter un client, toujours en FreeBSD 10.3. Dans ce contexte, le client est en fait un service authentifié (un serveur sshd par exemple).

Prérequis

À ce stade, posséder une Yubikey dont vous pourrez configurer un des slots est impératif. Il est aussi pertinent de télécharger sur votre poste le Yubikey Personalization Tool. Et il vous faut bien évidemment une machine sous FreeBSD 10.x qui servira de serveur sshd.

Générer une clé d'API

La validation d'une authentification par OTP Yubico requière que l'utilisateur fournisse un OTP reconnu, c'est à dire que sa Yubikey soit enregistrée dans le YK-KSM, et que l'OTP envoyé soit valide. Il est aussi nécessaire que la connexion entre le client (ici sshd+pam) et le serveur YK-VAL soit "authentifiée" par une clé d'API.

Dans l'idéal, chaque client individuel doit disposer de sa propre clé d'API, c'est plus sûr. Et même si cela peut occasionner des lourdeurs, cela permet de révoquer une clé d'API sans mettre par terre l'ensemble des clients.

La première étape pour ajouter un client dans l'infrastructure est donc de créer une clé d'API. Pour cela, il faut se connecter sur le serveur YK-VAL, et lancer la commande suivante :

ykval-gen-clients --urandom --notes "client de test 1"
1,VI5eTtCSAjdmp473G3rWFq+pL1k=

Cette commande vous donne en résultat une clé d'API, associée au client "1". La clé d'API et les informations connexes sont injectées dans la base de données du serveur YK-VAL.

Enregistrer une Yubikey

Chaque Yubikey compatible Yubico OTP dispose de deux slots de configuration. Le premier est réglé par défaut sur Yubico OTP, mais il est impossible d'en extraire la clé privée de chiffrement (configuration d'usine). Cette clé est enregistrée dans le YK-KSM des serveurs yubico.com, donc elle est opérationnelle si vous souhaitez l'utiliser pour vous authentifier sur des services qui s'appuient sur le cloud de yubico.com. Nous souhaitons nous appuyer sur notre propre infrastructure privative, donc cette clé n'est pas utilisable.
Si vous souhaitez conserver cette clé initiale, vous devrez créer une nouvelle clé privée sur le slot 2 de votre Yubikey (et je vous y encourage). Si vous êtes sûr de ne pas en avoir l'usage, vous pouvez simplement écraser le slot 1 de la Yubikey avec votre nouvelle clé privée. Sachez que l'écrasement d'un slot est irréversible : la clé privée fournie par Yubico sera définitivement perdue.

Ceci posé, vous pouvez connecter votre Yubikey à votre machine, et lancer le Yubikey Personalization Tool.
Dans l'interface, choisissez le premier onglet en haut à gauche "Yubico OTP", et cliquez sur "Quick".
La fenêtre ci-dessous est affichée :
- choisissez le slot 1 (écrasement de la configuration d'usine) ou le slot 2 (vierge)
- décochez la case "Hide values"
- copiez précieusement les chaînes de caractères des trois champs, ainsi que le serial number au format décimal ("Dec") qui se trouve au milieu à droite de la fenêtre.

Yubico Personalization Tool

Il s'agit ensuite d'enregistrer ces informations dans la base de données du YK-KSM. Dans le cadre de ces tests, j'ai simplement injecté la clé à la main dans MySQL :

INSERT INTO yubikeys VALUES (4263215,"vvgrneginvdf","","578fba7ca791","fd69d1ecc644f36dde9dfc742cf2e3fa","00000000","",1,1);

Les champs sont dans l'ordre d'apparence : le numéro de série "Dec" de votre clé physique, la date de création (non renseignée), la "Public Identity" de votre clé de chiffrement, la "Private Identity" de votre clé de chiffrement, et enfin la "Secret Key". Les champs suivants sont "lockcode", "creator" (vide), "active" et "hardware". Laissez-les simplement comme présenté ci-dessus.

Dès que vous avez procédé à l'insertion, vous pouvez tester que la clé est bien reconnue par le serveur YK-KSM. Générez un OTP avec votre clé en appuyant un court instant sur le bouton si vous utilisez le slot 1, ou 2-3 secondes si vous utilisez le slot 2 (placez au préalable votre curseur dans un document txt).
Ensuite tapez la commande suivante sur le serveur YK-KSM :

curl 'http://localhost/wsapi/decrypt?otp=vvgrneginvdfddffbdhgefnrdtgcrnntccchndebhdiv'

ou vvgrneginvdfddffbdhgefnrdtgcrnntccchndebhdiv est l'OTP que vient de générer votre clé.
Vous obtiendrez alors la réponse suivante :

OK counter=0001 low=8250 high=45 use=02

Vous pouvez ensuite tester que votre Yubikey passe bien la validation de bout en bout. À partir d'un terminal sur YK-VAL, lancez la commande suivante :

ykclient --url "http://127.0.0.1/wsapi/2.0/verify" --apikey VI5eTtCSAjdmp473G3rWFq+pL1k= 1 vvgrneginvdfihrudhtffnjigivctkujtfjlkiniideg --debug

L'argument --apikey doit être suivi de la clé d'API que vous avez générée plus haut. Elle est suivit d'un espace, puis du numéro d'ID du client que vous avez inséré (et donné dans la sortie de la commande ykval-gen-clients). À la suite de ce client ID, on injecte un OTP, et éventuellement l'argument --debug.

Si tout va bien, vous devez obtenir dans la sortie :

Input:
  validation URL: http://127.0.0.1/wsapi/2.0/verify
  client id: 1
  token: vvgrneginvdfihrudhtffnjigivctkujtfjlkiniideg
  api key: VI5eTtCSAjdmp473G3rWFq+pL1k=
Verification output (0): Success

Configuration du client

Pour brancher un serveur sshd sur une infrastructure d'authentification double facteur, le plus simple est en général d'utiliser un plugin PAM. Sur FreeBSD, on peut en quelques secondes installer le nécessaire :

pkg install pam_yubico

Ce plugin s'appuie sur deux choses : l'URL de votre service YK-VAL, et une liste qui associe les logins des utilisateurs avec une clé ("Public Identity").
Vous pouvez créer le fichier qui associe l'uid UNIX à la "Public Identity" très simplement :

cat "patpro:vvgrneginvdf" >> /etc/yubikey

Puis dans /etc/pam.d/sshd il faut ajouter la directive qui permettra à PAM de faire la requête vers YK-VAL. La ligne suivante doit être ajoutée :

auth      required      /usr/local/lib/security/pam_yubico.so mode=client authfile=/etc/yubikey id=1 key=VI5eTtCSAjdmp473G3rWFq+pL1k= url=http://192.168.0.100/wsapi/2.0/verify?id=%d&otp=%s

juste au dessus de la ligne :

auth      required      pam_unix.so     no_warn try_first_pass

authfile pointe vers votre fichier associant uid et clé OTP, id est la Client ID créée lors de l'ajout du client sur YK-VAL, key est la clé d'API associée à ce client. Pour finir, url est l'adresse du service de vérification sur YK-VAL. On peut tout à fait inscrire le nom du serveur YK-VAL dans l'URL à la place de son adresse IP, néanmoins en cas d'avarie du DNS il est souhaitable que l'authentification continue de fonctionner.

Dernière étape : la configuration du serveur sshd. Il s'agit assez simplement de modifier /etc/ssh/sshd_config pour s'assurer que les paramètres suivants sont actifs :

PasswordAuthentication no
ChallengeResponseAuthentication yes

Relancez ensuite sshd avec la commande service sshd restart et tentez la connexion à partir d'une machine sur laquelle votre Yubikey est connectée :

$ ssh patpro@192.168.0.104
YubiKey for `patpro': 
Password for patpro@test10.patpro.net:
Last login: Fri May  6 21:33:58 2016 from 192.168.0.2
FreeBSD 10.3-RELEASE (GENERIC) #0 r297264: Fri Mar 25 02:10:02 UTC 2016

Welcome to FreeBSD!
...

Enjoy.

Bibliographie

Pour réaliser cette infrastructure privative d'authentification double facteur et les articles qui en découlent, je me suis appuyé sur les sources suivantes :

yubikey-ksm, principes et installation.
yubikey-val, principes et installation.
Building a local Yubikey server infrastructure (sur Linux).
yubico-pam, README.
YubiKey on FreeBSD HOWTO, aspect "client" uniquement, utilisant en plus pam_per_user.

Monter un serveur d’authentification multifacteur 2/3

Dans un article précédent, j'ai présenté les étapes nécessaires à l'installation du serveur de validation YK-VAL de Yubico sur FreeBSD 10.3. Ce serveur s'intègre dans l'infrastructure d'authentification double facteur Yubico selon le schéma ci-dessous.
proposition d'infrastructure YK-VAL YK-KSM

D'autres modèles sont possibles bien évidemment, comme celui qui consiste à mettre les services YK-VAL et YK-KSM sur la même machine.
La suite des opérations consiste à créer le serveur YK-KSM en suivant la documentation officielle de Yubico, et les informations ci-après.

Serveur de clés YK-KSM

Pour assurer la sécurité lors des manipulations de clés, ce serveur est supposé n'utiliser que des fichiers chiffrés via OpenPGP/GnuPG. Aussi, l'outil ykksm-import nécessite-t-il qu'une clé GnuPG soit utilisée pour chiffrer les clés en amont, à leur création sur le poste de l'administrateur par exemple. Il est néanmoins tout à fait possible de ne pas utiliser les commandes ykksm-gen-keys et ykksm-import pour faire fonctionner l'infrastructure d'auth double facteur. Il suffit alors de fournir les clés à la main en les injectant directement dans la table MySQL ad-hoc.

Les étapes supplémentaires liées à OpenPGP n'étant pas complexes à mettre en œuvre, je les présente tout de même.
Il s'agit donc dans un premier temps d'installer gnupg, et de créer une clé maîtresse. Cette clé est utilisée sur le poste qui servira à générer les clés Yubico (ici le serveur lui-même), et sur le serveur YK-KSM pour les déchiffrer au moment de les injecter dans la base de données.

Pour une raison qui m'échappe, le fonctionnement de pinentry-tty est assez hasardeux à l'intérieur d'une Jail, donc si vous souhaitez, comme moi initialement, faire l'installation du service YK-KSM dans une Jail, passez votre chemin, vous gagnerez du temps :)

La partie GnuPG est assez simple :

pkg install gnupg
gpg2 --full-gen-key

Et suivez l'exemple de la doc Yubico. Une fois que votre clé GnuPG est créée, vous pouvez passer à l'installation du service YK-KSM proprement dite.

pkg install git help2man p5-DBI mysql56-server p5-DBD-mysql apache24 mod_php56 php56-xml php56-curl php56-hash php56-pdo_mysql php56-mcrypt
git clone git://github.com/Yubico/yubikey-ksm.git
cd yubikey-ksm

L'utilisation de GIT n'est pas obligatoire, on peut aussi bien télécharger le master.zip à partir de github, comme je l'ai fait pour YK-VAL.
Tout comme pour ce dernier, le Makefile est inexploitable en l'état, j'ai donc eu recours à quelques bricoles pour générer l'environnement adéquat avant d'installer les fichiers à la main :

for DIR in $(awk '/prefix = / {print $3}' Makefile); do
	[ -d $DIR ] || mkdir -p $DIR
done

La commande awk '/prefix = / {print $1"="$3}' Makefile nous donne une série de variables, à laquelle j'ajoute DESTDIR, que l'on fourni ensuite à bash :

etcprefix=/etc/yubico/ksm
binprefix=/usr/bin
phpprefix=/usr/share/yubikey-ksm
docprefix=/usr/share/doc/yubikey-ksm
manprefix=/usr/share/man/man1
wwwprefix=/var/www/wsapi
DESTDIR=/

Cette fois-ci, les commandes ykksm-* utilisables dans le shell sont codées en Perl avec un shebang compatible Linux, pas FreeBSD. On peut faire un lien symbolique de /usr/local/bin/perl vers /usr/bin/perl ou on peut corriger les scripts avant de les installer :

sed -i'.old' 's,/usr/bin/perl,/usr/local/bin/perl,' ykksm-import
sed -i'.old' 's,/usr/bin/perl,/usr/local/bin/perl,' ykksm-gen-keys
sed -i'.old' 's,/usr/bin/perl,/usr/local/bin/perl,' ykksm-export
sed -i'.old' 's,/usr/bin/perl,/usr/local/bin/perl,' ykksm-checksum

Puis on lance la copie des différents éléments :

cp .htaccess ${DESTDIR}${phpprefix}/.htaccess
cp ykksm-decrypt.php ${DESTDIR}${phpprefix}/ykksm-decrypt.php
cp ykksm-utils.php ${DESTDIR}${phpprefix}/ykksm-utils.php
cp ykksm-gen-keys ${DESTDIR}${binprefix}/ykksm-gen-keys
cp ykksm-import ${DESTDIR}${binprefix}/ykksm-import
cp ykksm-export ${DESTDIR}${binprefix}/ykksm-export
cp ykksm-checksum ${DESTDIR}${binprefix}/ykksm-checksum
cp ykksm-config.php ${DESTDIR}${etcprefix}/ykksm-config.php
cp ykksm-gen-keys.1 ${DESTDIR}${manprefix}/ykksm-gen-keys.1
cp ykksm-import.1 ${DESTDIR}${manprefix}/ykksm-import.1
cp ykksm-export.1 ${DESTDIR}${manprefix}/ykksm-export.1
cp ykksm-checksum.1 ${DESTDIR}${manprefix}/ykksm-checksum.1
cp ykksm-db.sql ${DESTDIR}${docprefix}/ykksm-db.sql
cp Makefile ${DESTDIR}${docprefix}/ykksm.mk
cp doc/* ${DESTDIR}${docprefix}/

L'étape suivante est l'installation de la base de données. Suivez simplement les instructions de l'étape 3 de la doc Yubico.

J'ai traité l'étape 4 différemment de ce qui est proposé. J'ai préféré tout mettre dans le fichier .htaccess :

<IfModule mod_php5.c>
  php_value include_path ".:/etc/yubico/ksm:/usr/share/yubikey-ksm"
</IfModule>

RewriteEngine on
RewriteRule ^([^/\.\?]+)(\?.*)?$ $1.php$2 [L]

L'étape 5 se traite exactement de la même manière que pour YK-VAL. Et l'étape 6 se fait simplement en créant les liens symboliques à la main.

À l'étape 7, tout comme pour YK-VAL, on renseigne le mot de passe MySQL dans le fichier de configuration ykksm-config.php.

Ensuite, sous réserve que votre serveur web soit lancé, il ne vous reste qu'à tester que tout fonctionne. Comme indiqué dans la doc, le résultat attendu est une erreur de clé inconnue, ce qui est tout à fait normal.

Fabrication de clés et import dans la base de données

Les vraies clés seront ajoutées ultérieurement. Mais vous pouvez néanmoins tester l'ajout de clés bidons via ykksm-gen-keys et ykksm-import.

La fabrication de 5 clés se fait comme ceci (doc officielle) :

ykksm-gen-keys --urandom 1 5 | gpg -a --encrypt -r 67A59965 -s > keys.txt

où 67A59965 est l'ID de la clé GnuPG fabriquée un peu plus haut.

Ensuite l'import des clés se fait de cette manière (doc officielle) :

ykksm-import --verbose --database 'DBI:mysql:dbname=ykksm;host=localhost' --db-user ykksmimporter --db-passwd mot-de-passe-mysql < keys.txt

Dans un troisième et dernier article il sera question de la partie vraiment intéressante : comment provisionner de vraies clés, et comment brancher un Client YK (un serveur sshd par exemple) sur votre nouvelle infrastructure d'authentification double facteur.

Monter un serveur d’authentification multifacteur 1/3

YubiKey-4-EdgeLe simple mot de passe est de plus en plus souvent pointé du doigt comme ne présentant plus les garanties requises pour l'authentification. L'alliance FIDO montre d'ailleurs l'exemple en assurant le développement et la promotion d'une infrastructure grand public d'authentification double facteur.

Quels outils pour l'authentification double facteur ?

Il est néanmoins des cas (nombreux) où FIDO et son U2F ne fonctionneront pas pour vous : pour toutes les authentifications qui ne passent pas par un navigateur web.

Pour tout le reste, et en particulier ce qui passe par PAM sur les UNIX et Linux, il existe quelques outils. Google Authenticator fonctionne bien, mais il nécessite deux choses importantes : que la machine à laquelle vous vous connectez accède librement à internet, et que vous utilisiez un client Google Authenticator, en général sur téléphone malin. Pour quelqu'un qui va s'authentifier rarement, disons 1 à 5 fois par semaine, c'est supportable : initier la connexion, sortir et déverrouiller son téléphone, lancer l'application, recopier le code temporaire (OTP), fermer l'application.
Sur un an je m'authentifie en ssh ou dans sudo environ 4000 fois. C'est à dire en moyenne plus de 11 fois par jour, pour des semaines de 7 jours.
En réalité je travaille toujours un peu moins le week end. Il en résulte qu'une journée de travail peut voir des pics autour de 60 authentifications.
Utiliser une authentification double facteur basée sur une appli mobile ou tout autre appareil affichant un code à recopier serait un échec dans un tel contexte.

C'est là que la Yubikey entre en jeu. Cette petite clé USB programmable est vue comme un clavier par votre ordinateur, et sur pression du doigt elle va taper pour vous l'OTP nécessaire à l'auth double facteur.
Par défaut, comme Google Authenticator, elle s'appuie sur des serveurs externes pour valider votre OTP. Le jour où pour une raison X ou Y votre réseau n'accède plus à ces serveurs, vous ne pourrez donc plus vous authentifier. C'est particulièrement problématique si vous tentez justement de reprendre la main sur votre firewall qui a décidé de bloquer l'accès à internet.
Heureusement, Yubico met à disposition de la communauté les outils nécessaires à la création d'un serveur de validation et d'un serveur de stockage des clés, permettant ainsi aux plus exigeants d'entre-nous de monter leur propre infrastructure d'authentification double facteur interne.

Ces outils sont bruts de fonderie, un peu mal dégrossis, et les instructions pour leur mise en place sont parfois approximatives. Le sujet devient encore plus épineux quand on tente de faire l'installation sur FreeBSD. Voici donc quelques instructions basées sur les notes prises lors de mes errances.

Monter des serveurs d'authentification Yubico sur FreeBSD

L'infrastructure d'authentification double facteur Yubico est composée de deux services : le service de validation (YK-VAL), c'est à dire celui auquel votre OTP va être envoyé par PAM, et qui donnera la réponse à PAM, et le service de stockage des clés (YK-KSM) sur lequel les clés des utilisateurs sont enregistrées.
Pour des raisons évidentes, il est recommandé de sécuriser au maximum ces deux services. L'idéal est donc de les installer sur deux machines différentes, et d'appliquer de la sécurité en profondeur dessus : firewall en entrée et sortie, si possible un réseau privé entre les deux serveurs, HTTPS partout, etc.

proposition d'infrastructure YK-VAL YK-KSM

Prérequis : pour aller au bout du process, il vous faudra acheter au moins une clé Yubikey, n'importe laquelle supportant "Yubico OTP".

Pour les besoins de cette maquette, j'ai créé 3 machines virtuelles FreeBSD 10.3. Une d'entre elle sera le serveur de validation ykval.patpro.net, une autre sera le serveur de clé yksm.patpro.net, et la dernière sera un serveur sshd sur lequel je souhaite activer l'authentification double facteur.

Serveur de validation YK-VAL

Sur une installation relativement vierge de FreeBSD 10.3, j'installe les composants suivants :

pkg install apache24 mod_php56 php56-xml php56-curl php56-hash bash sudo mysql57-server php56-pdo_mysql ykclient

Attention, pour une raison que je n'ai plus en tête, l'installation du serveur YK-KSM n'est pas compatible avec mysql57-server. Si vous installez YK-VAL et YK-KSM sur la même machine, choisissez mysql56-server !

Je récupère aussi les sources du serveur de validation Yubico :

fetch https://github.com/Yubico/yubikey-val/archive/master.zip
unzip master.zip

Et je tente de suivre les instructions présentées sur la documentation officielle Yubico. Je vous encourage à lire cette documentation en parallèle avec ce blog, car je ne reprends pas ici l'intégralité des explications.

Premier souci, le Makefile n'est pas fonctionnel sur FreeBSD, et j'ai du faire l'installation manuellement. J'ai tenté de scripter les choses un tout petit peu en créant automatiquement les répertoires manquants :

for DIR in $(awk '/prefix = / {print $3}' Makefile); do
	[ -d $DIR ] || mkdir -p $DIR
done

Puis en créant une série de variables qu'il faut injecter dans bash :

awk '/prefix = / {print $1"="$3}' Makefile
etcprefix=/etc/yubico/val
sbinprefix=/usr/sbin
phpprefix=/usr/share/yubikey-val
docprefix=/usr/share/doc/yubikey-val
manprefix=/usr/share/man/man1
muninprefix=/usr/share/munin/plugins
wwwprefix=/var/www/wsapi

Ensuite on peut copier les fichiers vers leur destination :

cp ykval-verify.php ${phpprefix}/ykval-verify.php
cp ykval-common.php ${phpprefix}/ykval-common.php
cp ykval-synclib.php ${phpprefix}/ykval-synclib.php
cp ykval-sync.php ${phpprefix}/ykval-sync.php
cp ykval-resync.php ${phpprefix}/ykval-resync.php
cp ykval-db.php ${phpprefix}/ykval-db.php
cp ykval-db-pdo.php ${phpprefix}/ykval-db-pdo.php
cp ykval-db-oci.php ${phpprefix}/ykval-db-oci.php
cp ykval-log.php ${phpprefix}/ykval-log.php
cp ykval-queue ${sbinprefix}/ykval-queue
cp ykval-synchronize ${sbinprefix}/ykval-synchronize
cp ykval-export ${sbinprefix}/ykval-export
cp ykval-import ${sbinprefix}/ykval-import
cp ykval-gen-clients ${sbinprefix}/ykval-gen-clients
cp ykval-export-clients ${sbinprefix}/ykval-export-clients
cp ykval-import-clients ${sbinprefix}/ykval-import-clients
cp ykval-checksum-clients ${sbinprefix}/ykval-checksum-clients
cp ykval-checksum-deactivated ${sbinprefix}/ykval-checksum-deactivated
cp ykval-nagios-queuelength.php ${sbinprefix}/ykval-nagios-queuelength
cp ykval-queue.1 ${manprefix}/ykval-queue.1
cp ykval-synchronize.1 ${manprefix}/ykval-synchronize.1
cp ykval-import.1 ${manprefix}/ykval-import.1
cp ykval-export.1 ${manprefix}/ykval-export.1
cp ykval-gen-clients.1 ${manprefix}/ykval-gen-clients.1
cp ykval-import-clients.1 ${manprefix}/ykval-import-clients.1
cp ykval-export-clients.1 ${manprefix}/ykval-export-clients.1
cp ykval-checksum-clients.1 ${manprefix}/ykval-checksum-clients.1
cp ykval-checksum-deactivated.1 ${manprefix}/ykval-checksum-deactivated.1
cp ykval-munin-ksmlatency.php ${muninprefix}/ykval_ksmlatency
cp ykval-munin-vallatency.php ${muninprefix}/ykval_vallatency
cp ykval-munin-queuelength.php ${muninprefix}/ykval_queuelength
cp ykval-munin-responses.pl ${muninprefix}/ykval_responses
cp ykval-munin-ksmresponses.pl ${muninprefix}/ykval_ksmresponses
cp ykval-munin-yubikeystats.php ${muninprefix}/ykval_yubikeystats
cp ykval-db.sql ${docprefix}/ykval-db.sql
cp ykval-db.oracle.sql ${docprefix}/ykval-db.oracle.sql

À ce stade on a installé différents scripts php dont le shebang est réglé sur un chemin "linux". On pourrait modifier tous les shebangs, mais il est plus simple de créer un lien symbolique de php au bon endroit :

ln -s /usr/local/bin/php /usr/bin/

Ensuite on s'attaque à la configuration de la base de données. J'ai opté pour MySQL, avec lequel je suis plus à l'aise.
Les étapes de la documentation officielle fonctionnent assez bien, mais les droits alloués à l'utilisateur ykval_verifier sont insuffisants. Il faut en effet lui donner les droits d'ajouter des clients dans la table ykval.clients. J'ai donc remplacé la ligne :

GRANT SELECT(id, secret, active) ON ykval.clients TO 'ykval_verifier'@'localhost';

par :

GRANT SELECT,INSERT,UPDATE ON ykval.clients TO 'ykval_verifier'@'localhost';

L'étape 4 de la doc. se résume à ces trois commandes :

mkdir /var/www/wsapi/2.0
ln -sf /usr/share/yubikey-val/ykval-verify.php /var/www/wsapi/2.0/verify.php
ln -sf /usr/share/yubikey-val/ykval-sync.php /var/www/wsapi/2.0/sync.php

L'étape 5 consiste à créer l'endroit où seront stockées les préférences de l'application, et à s'assurer qu'elles seront lisibles par Apache.

mkdir /etc/default
vi /etc/default/ykval-queue
ajouter la ligne : DAEMON_ARGS="/etc/yubico/val:/usr/share/yubikey-val"
vi /var/www/wsapi/2.0/.htaccess
ajouter les lignes suivantes : 
	RewriteEngine on
	RewriteRule ^([^/\.\?]+)(\?.*)?$ $1.php$2 [L]
	<IfModule mod_php5.c>
	  php_value include_path ".:/etc/yubico/val:/usr/share/yubikey-val"
	</IfModule>
cd /var/www/wsapi
ln -s 2.0/.htaccess /var/www/wsapi/.htaccess

À l'étape 6, il faut récupérer l'exemple de fichier de configuration ykval-config.php fourni avec le code de l'application, et le copier au bon endroit :

cp ykval-config.php /etc/yubico/val/

On édite ce fichier pour renseigner le mot de passe MySQL.

L'étape 7 permet de configurer Apache. Les instructions présentées sont valides pour apache 2.2, mais en version 2.4 il y a quelques modifications à faire. Notamment, autoriser l'accès se fait par la formule Require all granted. Il faut aussi activer le mod_rewrite qui n'est pas actif par défaut sur FreeBSD.

C'est l'occasion de configurer proprement le virtual host, d'activer SSL, etc.

Pour configurer syslogd lors de l'étape 8, il suffit d'ajouter la ligne suivante à /etc/syslog.conf :

local0.*              /var/log/ykval.log

et de faire un touch /var/log/ykval.log && service syslogd restart.

La rotation automatique pourra être gérée dans /etc/newsyslog.conf.

J'ai sauté l'étape 9, car je n'ai pas souhaité mettre en place de synchronisation entre différents YK-VAL pour cette maquette. C'est néanmoins une étape à valider si vous souhaitez mettre en place une infrastructure utilisable en production (ie. redondante).

À ce stade vous pourrez passer à l'étape 11. Cette dernière donnera sans doute lieu à de nombreux petits ajustements : config Apache, droits de fichiers, etc. Pas de panique, les logs fournissent normalement pas mal de pistes (notamment /var/log/ykval.log), et vous ne seriez pas ici si vous n'étiez pas capable de vous en sortir.

curl 'http://ykval.patpro.net/wsapi/2.0/verify?id=1&nonce=asdmalksdmlkasmdlkasmdlakmsdaasklmdlak&otp=dteffujehknhfjbrjnlnldnhcujvddbikngjrtgh'
h=CqcOcOH1yokoXcDimKDnElyP+f8=
t=2016-02-18T17:47:56Z0853
status=NO_SUCH_CLIENT

Lire la suite : la création du serveur YK-KSM.

Mise à jour FreeBSD : impact sur SSL/TLS

Dans le cadre de mon travail, j'administre quelques serveurs de messagerie à fort trafic. Certains tournent sous FreeBSD. Toute modification de ces serveurs, clés de voûte de notre infrastructure de messagerie, doit se faire avec prudence et en comparant leur fonctionnement avant et après le changement. Je suis aidé en cela par Splunk, un collecteur de logs qui me permet de faire des analyses poussées.
Splunk est notamment très doué pour afficher des tendances, des évolutions, et permettre de représenter quelques secondes ou minutes vos données sous forme graphique. Notamment, à chaque mise à jour de l'antispam, de l'antivirus, de Perl ou d'autres composants critiques, il me permet de vérifier en quelques instants que le temps de traitement des messages dans les différents filtres n'est pas dégradé par la mise à jour.
La montée de version de FreeBSD 9.x vers FreeBSD 10.1 m'a notamment permis de bénéficier d'une version d'OpenSSL plus récente, et supportant TLS 1.2. Ce changement n'est pas anodin. SSL est mort, TLS 1.0 suit le même chemin, il faut donc pouvoir utiliser TLS 1.2.
Voyons l'impact de cette mise à jour sur les échanges chiffrés avec les autres serveurs de messagerie (ici, uniquement les messages sortants) :

Évolution de la version de TLS dans les échanges suite à la mise à jour du système

Évolution de la version de TLS dans les échanges suite à la mise à jour du système

Évolution des algorithmes de chiffrement dans les échanges suite à la mise à jour du système

Évolution des algorithmes de chiffrement dans les échanges suite à la mise à jour du système

Cette rapide analyse ne porte que sur les échanges chiffrés : les échanges de mails avec les serveurs ne permettant pas le chiffrement TLS ne sont pas représentés. La passerelle de messagerie dont il est question ici fait tourner trois instances postfix en "postfix-multi", et voit transiter trois à cinq millions de messages par mois selon la période de l'année.

ZFS primary cache is good

Last year I've written a post about ZFS primarycache setting, showing how it's not a good idea to mess with it. Here is a new example based on real world application.
Recently, my server crashed, and at launch-time Splunk decided it was a good idea to re-index a huge apache log file. Apart from exploding my daily index quota, this misbehavior filed the index with duplicated data. Getting rid of 1284408 events in Splunk can be a little bit resource-intensive. I won't detail the Splunk part of the operation: I've ended up having 1285 batches of delete commands that I've launched with a simple for/do/done bash loop. After a while, I noticed that the process was slow and was making lots of disk IOs. Annoying. So I checked:

# zfs get primarycache zdata/splunk
NAME          PROPERTY      VALUE         SOURCE
zdata/splunk  primarycache  metadata      local

Uncool. This setting was set locally so that my toy (Splunk) would not harvest all ARC from the server, hurting production. For efficiency's sake, I've switched back the primary cache to all:

# zfs set primarycache=all zdata/splunk

Effect was almost instantaneous: ARC filled with Splunk data and disk IOs plummeted.

primarycache # of deletes per second
metadata 10.06
all 22.08

A x2.2 speedup on a very long operation (~20 hours here) is a very good argument in favor of primarycache=all for any ZFS user.

acceleration of a repetitive splunk operation thanks to ZFS primarycache setting

Acceleration of a repetitive splunk operation thanks to ZFS primarycache setting

Création de mots de passe en ligne de commande

keychainLa création de nouveaux mots de passe est une activité assez peu passionnante, d'autant que dans certains contextes on peut être amené à répéter l'opération plusieurs fois par jour. Plutôt que d'avoir à réfléchir - et donc de produire un résultat influencé par les travers de l'esprit humain - il est préférable de s'en remettre totalement à la machine.
L'aléa est bien meilleur, et le résultat est obtenu bien plus facilement. Il est bien sûr question ici de vrais mots de passe : large palette de caractères, longueur correcte, totalement aléatoires.

Voici deux fonctions assez simples qui trouveront leur place tout naturellement dans votre .bashrc ou .bash_profile sur *BSD (FreeBSD, Mac OS X, etc.). La seule condition étant de disposer des commandes jot et rs déjà présentées dans les articles "jot et seq, créer des séquences en ligne de commande" et surtout "Les bons mots de passe…".

Cette première fonction crée 5 mots de passe aléatoires dont les caractères sont pris entre les codes ASCII 32 (espace) et 126 (tilde). Par défaut, ces mots de passe font 25 caractères de long, mais la commande génère en fait un tirage de 500 caractères, ce qui permet de fabriquer 5 mots de passe de 100 chiffres, lettres, symboles en indiquant la longueur souhaitée comme paramètre. L'astuce ici tient dans l'utilisation de la tabulation comme séparateur en sortie de jot, ce qui permet d'avoir l'espace présent dans les mots de passe en sortie.

mdp-complexe() {
jot -s $'\t' -r -c 500 32 126 | rs -c$'\t' -g0 0 ${1-25} | head -5
}

Exemple d'utilisation :

$ mdp-complexe 
fnc\Y}02PSc6}{;0`T}LOeN?\
5W Y1Y8!o<VlTA2vuE}SU)g?]
'kGhRa=u|hJW#;6aDd[A&UR_/
n|$_f3S?[`pO2":+0e<;aTi\v
.nU\i.PhbPE5TfuXY)g+DiN~g

En imposant la longueur :

$ mdp-complexe 50
9Tu1StsL $Gk@K<X\R)xKv{JXYe|g>L^2T;|*GMASee@HX.Epj
T%2 N;VvLFVi]s>_~xpo^~vD8b2.Fb$02ay9sLgjW#,TQ>8JAO
7EyWUC)Cqm2F,72mIf$#vh3<sTx%j>*v't{Fump=Fb5cJeZir$
RfS638d~a.T#StF.t3%Z*`RG)/?#; H?liH2DielVvs#4IBp0a
G`OyIOzpYtt5Sh!92/zdp7^C98r.OtIV8Fk_ilYCvVI6~e@17T

Cette seconde fonction est basée sur la première, mais un filtrage est imposé à la sortie de jot pour ne garder qu'un sous-ensemble des caractères générés. Ici, les caractères a-z, A-Z, 0-9, _, / et - sont conservés. L'approche est relativement simple : il suffit d'ajouter à la liste entre [ ] les caractères que l'on souhaite conserver dans les mots de passe :

mdp-simple() {
jot -s $'\t' -r -c 500 32 126 | sed "s,[^a-zA-Z0-9_/-]"$'\t'",,g"|\
 rs -c$'\t' -g0 0 ${1-25} | head -5
}

Ce qui donne :

$ mdp-simple 
y0q/EKoZKN9ZqGGhr1triaB0l
VMFUNYNpopAu9NleSv0BxuuTh
W07eE4ef1A99yAl0UmP6EHo6_
9X4CWx7qgML6qxn9Y0nxhONpr
lw_eY4DYY414mrllNxe/FSUfM

Stockez ensuite le mot de passe choisi dans votre trousseau de mots de passe sécurisé.

Créer un trou noir DNS

Même si la question a déjà été largement traitée, je livre ici ma propre version d'un trou noir DNS. Le DNS blackhole, en anglais dans le texte, permet par exemple de s'assurer (dans une certaine mesure) que les utilisateurs de votre réseau ne peuvent pas se connecter trop facilement à des sites web vecteurs d'infection.
Le fonctionnement est simple : vous avez un réseau local, chez vous ou dans votre entreprise, et vous mettez à disposition de vos utilisateurs un serveur DHCP pour que les équipements qui se connectent puissent obtenir une adresse IP. Je pars du principe que sur ce réseau local, vous disposez aussi d'un serveur DNS. Un utilisateur se connecte avec votre réseau : le serveur DHCP lui donne une adresse IP pour que la nouvelle machine puisse parler sur le réseau, et fourni aussi l'adresse de votre serveur DNS. C'est donc par ce serveur que vous maitrisez que la machine de l'utilisateur va convertir les noms de domaine (www.patpro.net) en adresse IP (193.30.227.216).
Comme vous avez la maîtrise du serveur DNS, vous avez la maîtrise de la résolution des noms de domaine. Vous pouvez donc décider de bloquer la résolution de certains noms de sites web qui posent problème (gros pourvoyeurs de malware, régies publicitaires, facebook, etc.).

Je vais me baser ici sur la liste de malwaredomains.com qui regroupe environ 20000 noms de domaine qui sont, ou ont été, impliqués dans la distribution de malware (en général en infectant le visiteur imprudent). Il s'agit donc pour moi de défendre mon réseau en protégeant les utilisateurs.

Les informations sont largement inspirées - voire pompées - de la prose anglophone de Paul.

Pré-requis : un serveur DNS BIND que vous maîtrisez, et un réseau avec serveur DHCP qui indique l'adresse IP du DNS, de sorte que les clients qui se connectent utiliseront par défaut le serveur DNS sus-mentionné. Il faut bash, curl, et jot (sur linux il faut remplacer jot par seq).

Obtenir la liste des zones DNS à mettre en trou noir.

Préparer le lieu de stockage :

mkdir /etc/namedb/blackhole

J'utilise le script suivant, à lancer en root via une crontab (une fois par semaine suffit) :

#!/usr/local/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
ZONEFILE=/etc/namedb/blackhole/spywaredomains.zones
MIRRORS[1]="http://mirror1.malwaredomains.com/files/spywaredomains.zones"
MIRRORS[2]="http://mirror2.malwaredomains.com/files/spywaredomains.zones"
MIRRORS[3]="http://dns-bh.sagadc.org/spywaredomains.zones"

# fonctionne sur BSD uniquement, pour linux il faut
# remplacer par `seq`
CHOOSE=$(jot -r 1 1 ${#MIRRORS[@]})

if [[ "$(/usr/local/bin/curl ${MIRRORS[CHOOSE]} -z ${ZONEFILE} -o ${ZONEFILE}_new -s -L -w %{http_code})" == "200" ]]; then
	rm -f ${ZONEFILE}_old
	mv ${ZONEFILE} ${ZONEFILE}_old
	mv ${ZONEFILE}_new ${ZONEFILE}
	named-checkconf -z | grep -v ": loaded serial"
	if [ ${PIPESTATUS[0]} -eq 0 ]; then
		service named restart
	else
		echo "Error loading new zone file, reversing..."
		mv ${ZONEFILE} ${ZONEFILE}_invalid_$(date "+%Y%m%d")
		mv ${ZONEFILE}_old ${ZONEFILE}
	fi
fi

C'est loin d'être foolproof, mais ça fait le travail. Les options de curl permettent de ne télécharger le fichier que si il a été modifié depuis votre dernière mise à jour. le script choisit un miroir au hasard au moment de faire le comparatif ce qui évite de charger toujours le même serveur.

Configurer BIND pour gérer les zones téléchargées.

Il faut ajouter dans la configuration du serveur DNS une directive d'inclusion du fichier téléchargé ci-dessus. Il suffit pour cela d'ajouter la ligne suivante à la fin du fichier /etc/named/named.conf :

 include "/etc/namedb/blackhole/spywaredomains.zones";

Le fichier spywaredomains.zones fait pointer chaque zone vers un unique fichier de définition qu'il convient de créer et de renseigner : /etc/namedb/blockeddomain.hosts.
Ce fichier contient une définition minimaliste de zone DNS BIND. Faites-la pointer vers un serveur web existant, cela vous permettra d'afficher à vos utilisateurs une page web d'explication :

$TTL    86400   ; one day
@       IN     SOA    NOM-DE-VOTRE-SERV-DNS. NOM-DE-VOTRE-SERV-DNS. (
	1
	28800   ; refresh  8 hours
	7200    ; retry    2 hours
	864000  ; expire  10 days
	86400 ) ; min ttl  1 day

	NS     NOM-DE-VOTRE-SERV-DNS.

	       A       IP-DE-VOTRE-SERVEUR-WEB
*	IN     A       IP-DE-VOTRE-SERVEUR-WEB

Si vous ne souhaitez pas informer vos utilisateurs, remplacez simplement IP-DE-VOTRE-SERVEUR-WEB par 127.0.0.1. Mais je recommande tout de même la publication d'une page web d'information sur la quelle les utilisateurs pourront arriver si ils tentent de joindre un domaine présent dans la liste noire.

Avec ça, votre serveur DNS est transformé en trou noir pour l'ensemble des domaines répertoriés chez malwaredomains.com. En analysant les logs de votre serveur web, vous pourrez aussi déterminer rapidement qui sur votre réseau est infecté ou risque de l'être.

Références.

edit : correction d'une coquille dans le script