Tech Blog.

Thoughts, stories, ideas.

Yubikey Validation Server Setup

9. July 2017

Si le YubiCloud ne doit pas être utilisé pour la validation des mots de passe uniques Yubico (OTP), les serveurs de validation peuvent également être utilisés par eux-mêmes. Ce n’est pas très difficile, mais la configuration redondante est plutôt mal documentée.

Aperçu

MySQL est utilisé comme backend et Apache comme frontend. Les deux composants yubikey-val et yubikey-ksm sont des applications PHP simples, qui consistent en quelques fichiers.

Installation

Serveur Web

Vous devez d’abord installer Apache, PHP et MySQL. En raison de la dépendance des paquets yubikey-ksm et yubikey-val, aucun serveur MariaDB ne peut être utilisé.
Ensuite, deux bases de données (ykksm et ykval) avec les utilisateurs correspondants (ykksm_reader et ykval_verifier) devraient être créées.

yubikey_ksm

Dans le Yubikey Key Storage Module (KSM), les Yubikeys individuels sont enregistrés, c’est-à-dire que toutes les données (y compris la clé secrète AES) de tous les Yubikeys sont enregistrées ici. Le service peut être utilisé pour vérifier si une Yubikey avec mot de passe unique (OTP) associé est valide, mais pas s’il s’agit d’une attaque par rejeu.
Comme le logiciel ne sait pas comment synchroniser les serveurs, ceci est résolu avec une configuration MySQL Master-Slave. Un[manuel] correspondant (https://www.digitalocean.com/community/tutorials/how-to-set-up-master-slave-replication-in-mysql), comment cela peut être fait, est disponible par exemple sur DigitalOcean. Veuillez noter que seule la base de données ykksm doit être synchronisée (binlog_do_db = ykksm).
Sur une Debian, le logiciel yubikey_ksm est simplement installé par apt install yubikey-ksm. Après cela, Apache et la base de données sont déjà configurés. Si vous souhaitez modifier la configuration par la suite, vous trouverez les fichiers correspondants dans /etc/yubico/ksm/. Un guide d’installation plus complet[Guide d’installation] (https://developers.yubico.com/yubikey-ksm/Installation.html) se trouve à Yubico.
Apache est configuré pour qu’il y ait un alias global /wsapi/decrypt as /usr/share/yubikey-ksm/ykksm-decrypt.php, s’il y a plusieurs VirtualHosts sur Apache, ils doivent être désactivés dans la configuration et seul le serveur virtuel nécessaire pour yubikey_ksm doit être activé.

De nouveaux Yubikeys peuvent être créés avec l’outil ykksm-gen-keys. Ceci donne la sortie suivante :

$ ykksm-gen-keys 1
1,cccccccccccb,42e31d069785,cf00b1f4c2c80e395b5e7532a5929cba,d05f7e394f0e,2016-03-22T13:12:25, 

La table yubikeys est disponible dans la base de données. Ceci a le schéma suivant :

CREATE TABLE `yubikeys` (
  `serialnr` int(11) NOT NULL,
  `publicname` varchar(16) NOT NULL,
  `created` varchar(24) NOT NULL,
  `internalname` varchar(12) NOT NULL,
  `aeskey` varchar(32) NOT NULL,
  `lockcode` varchar(12) NOT NULL,
  `creator` varchar(8) NOT NULL,
  `active` tinyint(1) DEFAULT '1',
  `hardware` tinyint(1) DEFAULT '1',
  PRIMARY KEY (`publicname`),
  UNIQUE KEY `publicname` (`publicname`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

Si vous voulez créer de nouveaux Yubikeys et les stocker dans la base de données, vous pouvez le faire avec le script suivant :

#!/bin/bash

MYSQL='mysql'

NEXTID=$(echo "SELECT t1.serialnr + 1 FROM ykksm.yubikeys t1 WHERE NOT EXISTS (SELECT serialnr FROM ykksm.yubikeys t2 WHERE t2.serialnr = t1.serialnr + 1) LIMIT 1;" | $MYSQL | tail -n 1)
if [ -z "${NEXTID}" ]; then
    NEXTID='1'
fi

KEY="$(ykksm-gen-keys ${NEXTID} | grep -v ^#)"

IFS=',' read -r -a ARR <<< "$KEY"

SQL="INSERT INTO ykksm.yubikeys VALUES (${ARR[0]}, '${ARR[1]}', '${ARR[5]}', '${ARR[2]}', '${ARR[3]}', '${ARR[4]}', 'bash', 1, 1);"
echo $SQL | $MYSQL

echo "Set Yubikey:"
echo "ykpersonalize -1 -y -a${ARR[3]} -o fixed=${ARR[1]} -o uid=${ARR[2]}"

yubikey_val

Le[Yubikey Validation Service] (https://developers.yubico.com/yubikey-val/) effectue la validation des mots de passe à usage unique (OTP). Les points suivants sont vérifiés et traités :

  • Client : Le client demandeur doit se vérifier lui-même, chaque client a un identifiant et un mot de passe correspondant. Cela empêche que tous les clients ne puissent pas faire une demande. Dans ce cas, le client est un démon ssh ou un site web, pas l’utilisateur avant lui.
  • Yubikey : L’OTP est transmis au service yubikey_ksm. Si l’OTP est valide, le service yubikey_val teste s’il s’agit d’une attaque en rejeu.
  • Sync : Les autres serveurs de validation sont informés du compteur courant de la Yubikey, de sorte qu’aucune attaque de relecture ne peut être effectuée sur un autre serveur de validation.
    Sur un système Debian, l’installation se fait avec apt install yubikey-val. Les fichiers de configuration correspondants se trouvent dans le répertoire /etc/yubico/val/.
    Après cela, Apache est déjà configuré globalement à nouveau. S’il y a plusieurs VirtualHosts, la configuration doit être configurée spécifiquement pour un seul VirtualHost. Les alias suivants doivent être configurés :
  • /wsapi/2.0/verify als /usr/share/yubikey-val/ykval-verify.php
  • /wsapi/verify als /usr/share/yubikey-val/ykval-verify.php
  • /wsapi/2.0/sync als /usr/share/yubikey-val/ykval-sync.php
  • /wsapi/2.0/resync als /usr/share/yubikey-val/ykval-resync.php
  • /wsapi/revoke als /usr/share/yubikey-val/ykval-revoke.php

Base de données

La base de données contient trois tables :

  • clients
    clients
    C’est ici que les clients (par exemple un PAM ou Mediawiki) qui peuvent demander le serveur de validation sont enregistrés.
CREATE TABLE `clients` (
  `id` int(11) NOT NULL,
  `active` tinyint(1) DEFAULT '1',
  `created` int(11) NOT NULL,
  `secret` varchar(60) NOT NULL DEFAULT '',
  `email` varchar(255) DEFAULT NULL,
  `notes` varchar(100) DEFAULT '',
  `otp` varchar(100) DEFAULT '',
  PRIMARY KEY (`id`),
  UNIQUE KEY `id` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
  • queue
    queue<br
    Dans la file d’attente se trouvent les entrées qui doivent être synchronisées avec d’autres serveurs de validation. Les entrées sont traitées par le service système ykval-queue.
CREATE TABLE `queue` (
  `queued` int(11) DEFAULT NULL,
  `modified` int(11) DEFAULT NULL,
  `server_nonce` varchar(32) NOT NULL,
  `otp` varchar(100) NOT NULL,
  `server` varchar(100) NOT NULL,
  `info` varchar(256) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
  • yubikeys
    yubikeys<br
    Dans ce tableau, les Yubikeys et leurs compteurs correspondants sont entrés. Cette table est synchronisée avec les autres serveurs de validation par yubikey_val lui-même.
CREATE TABLE `yubikeys` (
  `active` tinyint(1) DEFAULT '1',
  `created` int(11) NOT NULL,
  `modified` int(11) NOT NULL,
  `yk_publicname` varchar(16) NOT NULL,
  `yk_counter` int(11) NOT NULL,
  `yk_use` int(11) NOT NULL,
  `yk_low` int(11) NOT NULL,
  `yk_high` int(11) NOT NULL,
  `nonce` varchar(40) DEFAULT '',
  `notes` varchar(100) DEFAULT '',
  PRIMARY KEY (`yk_publicname`),
  UNIQUE KEY `yk_publicname` (`yk_publicname`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

Synchronisation

Le service a son propre mécanisme de synchronisation. Puisque le compteur le plus élevé (l’OTP) de chaque Yubikeys doit être connu sur tous les serveurs, ceci n’est pas résolu par une réplication MySQL. Cela aurait pour conséquence que les compteurs plus profonds seraient également synchronisés.
Pour permettre la synchronisation des serveurs, la configuration doit d’abord être adaptée. Par exemple, les deux hôtes srv-tfvalid-01 (IP 128.66.1.1.1) et srv-tfvalid-02 (IP 128.66.1.2) sont utilisés. Les paramètres de configuration suivants doivent être réglés :

  • __YKVAL_SYNC_POOL__
    Saisissez ici les serveurs avec lesquels vous souhaitez effectuer la synchronisation.
$baseParams['__YKVAL_SYNC_POOL__'] = array(
  "https://srv-tfvalid-01/wsapi/2.0/sync",
  "https://srv-tfvalid-02/wsapi/2.0/sync"
);
  • __YKVAL_ALLOWED_SYNC_POOL__
    Toutes les adresses IP de tous les serveurs de validation sont entrées ici pour qu’ils puissent se synchroniser.
$baseParams['__YKVAL_ALLOWED_SYNC_POOL__'] = array(
  "127.0.0.1",
  "128.66.1.1",
  "128.66.1.2"
);
  • __YKVAL_RESYNC_IPS__
    Cette valeur est la valeur ___YKVAL_ALLOWED_SYNC_POOL___.
$baseParams['__YKRESYNC_IPS__'] = $baseParams['__YKVAL_ALLOWED_SYNC_POOL__'];
  • __YKVAL_SYNC_DEFAULT_LEVEL__
    Cette valeur définit le niveau minimum en pourcentage du nombre de serveurs de validation qui doivent être synchronisés avec succès avant que l’OTP soit déclaré valide. Si les serveurs ne sont pas disponibles, l’OTP peut être déclaré invalide en raison d’un trop petit nombre de réponses pendant la synchronisation.
    Des valeurs comprises entre 0 et 100 sont possibles. S’il y a deux serveurs dans l’ensemble du pool de synchronisation et que le serveur 1 est requis, il a le niveau de synchronisation suivant :

    • Serveur 2 en ligne : 100
    • Serveur 2 hors ligne : 0
      S’il y a trois serveurs dans l’ensemble du pool de synchronisation et que le serveur 1 est requis, il a les niveaux de synchronisation suivants :
    • Les deux serveurs en ligne : 100
    • Un serveur en ligne, un autre hors ligne : 50
    • Les deux serveurs hors ligne : 0

Pour qu’un serveur puisse être hors ligne dans une configuration avec deux serveurs, la valeur doit être mise à 0 comme suit :
“PHP
BaseParams[‘YKVAL_SYNC_DEFAULT_LEVEL‘] = 0 ;

##### Services de synchronisation
Le service système ykval-queue peut être lancé à systemd avec le fichier de service suivant :
"Ini
[unité]
Description=File d'attente de synchronisation du serveur de validation des clés Yubikey
Après=réseau.cible

[Service]
ExecStart=/usr/sbin/ykval-queue
Redémarrage=en panne

[Installer]
WantedBy=multi-utilisateur.target

En outre, la tâche cron qui déclenche la synchronisation doit être créée. Le cronjob doit être créé par combinaison Serveur de validation – Serveur de validation et ressemble à ceci :

* * * * * * * /usr/sbin/ykval-synchronize validation-server-2 all

Créer de nouveaux clients de validation

De nouveaux clients peuvent être créés avec l’outil ykval-gen-clients. Avec le Bash Script suivant, les clients peuvent être automatiquement créés et sauvegardés dans la base de données :

#!/bin/bash

MYSQL='mysql'
ERRORMSG='Failed to insert new client with query '

CLIENT="$(ykval-gen-clients 1 2>&1)"

echo "USE ykval; ${CLIENT#$ERRORMSG}" | $MYSQL

echo "Client configuration:"
echo ${CLIENT#$ERRORMSG}

Utiliser le serveur de validation

Les serveurs de validation doivent être testés avant utilisation. Par exemple, il faut vérifier si une attaque de rediffusion sur le deuxième serveur n’est pas possible après que la validation a déjà été effectuée sur le premier serveur. Un autre test consiste à savoir si les bases de données MySQL synchronisent et traitent les entrées de la table “`ykval.queue“.

SSHd

Si un serveur SSH doit être sécurisé avec TwoFactor, le plus simple est de le faire dans PAM (Pluggable Authentication Modules for Linux). Il existe un module PAM supplémentaire (pam_yubico) qui demande le serveur de validation Yubikey.
Dans cet exemple, PAM est un client du serveur de validation, un ID et une clé avec ykval-gen-clients`` doivent donc être générés pour PAM. Seuls les utilisateurs du groupe POSIXUsersdevraient avoir à faire une validation TwoFactor, pour les autres un login sans suffit. L'ID des Yubikeys est lié à l'utilisateur en LDAP, c'est-à-dire que les utilisateurs qui doivent faire une validation TwoFactor ont un attribut en LDAP (dans l'exemple : ``yubikey``) qui correspond au nom public de leurs Yubikeys (exemple : ````cccccccccccccccccb````). La configuration suivante est également ajoutée à ````/etc/pam.d/sshd. Mieux après la ligne qui fait l’authentification par mot de passe, par exemple pam_unix.so ou pam_ldap.so dans la chaîne “auth. Ceux-ci peuvent également être inclus avec un@includeprovenant par exemple du ````common-auth, donc une configuration finie ne peut pas être spécifiée ici.

auth [success=2 default=ignore] pam_succeed_if.so user notingroup Users
auth [success=1 default=ignore] pam_yubico.so id=1 \
                                              
key=bjMN3jRHquwHr5NqNKN+LEFZUjY= \
                                              
urllist=https://srv-tfvalid-01/wsapi/2.0/verify;https://srv-tfvalid-02/wsapi/2.0/verify \
                                              
ldap_uri=ldap://ldap1.example.com:389/;ldap://ldap2.example.com:389/ \
                                              
ldapdn=cn=users,dc=example,dc=com \
                                              
user_attr=uid \
                                              
yubi_attr=yubikey \
                                              
verbose_otp
auth requisite                  
pam_deny.so

Après cela, la connexion au serveur doit être testée (Précaution: Toujours garder une connexion root ouverte, car si quelque chose ne fonctionne pas, il se peut que vous ne puissiez plus vous connecter).