Keycloak + PAM + vsftpd

kortex
2022-09-15T16:28:44+02:00
Linux.général, keycloak, ftp, pam, pamd, vsftpd

Sommaire

Contexte

Stack technique

Ce que j'ai fait et qui fonctionne

Installation & configuration

PAM: création d'un fichier

Utilisateurs virtuels: création d'une base de données

Test

Ce que j'ai fait et qui ne fonctionne pas

Création d'un script Python

PAM: modification du fichier qui marchait

Test

Bonjour à tous,

Comme à mon habitude, le peu de fois que je post quelque chose sur ce forum, c'est pour un besoin un peu tordu ;)

Contexte

Ma société développe un logiciel: rien de bien original.

Comme bon nombre de logiciel, il y a une gestion des utilisateurs / identités: rien de bien original.

Le logiciel s'appuie sur Keycloak pour gérer les utilisateurs / identités: on commence l'originalité (nous ne sommes pas les seuls mais ce n'est pas non plus utilisé partout).

Nous avons souvent besoin de transmettre des données à nos utilisateurs.
C'est soit ponctuel soit de manière automatisée (== nous mettons à disposition les données et l'utilisateur les récupère, le tout dans des traitements automatisés).

Jusqu'à maintenant nous avions une fonctionnalité un peu archaïque basée sur des comptes SFTP.
Nous allons revoir toute cette partie pour avoir une solution un peu plus robuste / plus aboutie.

Mais j'ai un problème avec SFTP :

notre serveur SFTP est géré par OpenSSH

le fournisseur d'environ 50% de nos machines refuse d'ouvrir le port SSH en "any" : il n'accepte d'ouvrir le port que sur une liste bien précise d'adresses.

En discutant avec lui, une chose qu'il accepte c'est de m'ouvrir les ports FTP si je bascule en FTPS.
J'avoue ne pas avoir tenté une négociation pour démarrer un simple serveur SFTP (donc non SSH) sur un autre port. Je n'ai pas cherché non plus : je ne sais même pas s'il existe d'autres logiciels que OpenSSH qui permettrait de démarrer un simple serveur SFTP sur un port lambda.

Du coup je me suis lancé dans une idée un peu tordue : créer un serveur FTP qui serait connecté à Keycloak pour que les utilisateurs du logiciel développé en interne puissent bénéficier directement d'un FTP leur permettant de récupérer des données.

On ne va pas se mentir : je n'ai pas l'impression que les logiciels impliqués dans cette aventure soient vraiment fait pour ça à la base ;)
Donc pour l'instant j'en suis vraiment au stade de la recherche et je n'en suis pas encore vraiment à considérer la stabilité et/ou la sécurité.

Stack technique

A cet instant T mes recherches tournent autour de :

VSFTPd

PAM

Keycloak

un script Python exécuté par pam_exec.so pour interroger Keycloak

Je suis parti sur VSFTPd car il gère déjà les utilisateurs virtuels et qu'il est compatible avec PAM.

Ce que j'ai fait et qui fonctionne

Installation & configuration

J'ai installé et configuré VSFTPD.

Voici la configuration dans laquelle j'ai volontairement retiré les lignes commentées et vides (pour faciliter la lecture) :

allow_writeable_chroot=YES
anonymous_enable=NO
chroot_list_enable=NO
chroot_local_user=YES
connect_from_port_20=YES
dirmessage_enable=YES
dual_log_enable=YES
force_dot_files=YES
guest_enable=YES
guest_username=ftp
hide_ids=YES
listen=YES
local_enable=YES
local_root=/home/vftp/$USER
log_ftp_protocol=YES
max_clients=20
max_per_ip=2
pam_service_name=ftp_keycloak
user_config_dir=/etc/vsftpd/vsftpd_user_conf
user_sub_token=$USER
virtual_use_local_privs=YES
vsftpd_log_file=/var/log/vsftpd.log
write_enable=YES
xferlog_enable=YES
xferlog_file=/var/log/vsftpd_xfer.log
xferlog_std_format=YES

Si un paramètre est absent, alors je suis sur la valeur par défaut.

PAM: création d'un fichier

J'ai créé un fichier PAM /etc/pam.d/ftp_keycloak tel que :

## IT WORKS ##
auth       required     pam_userdb.so db=/etc/vsftpd/vsftpd-virtual-user
account    required     pam_userdb.so db=/etc/vsftpd/vsftpd-virtual-user
session    required     pam_loginuid.so
## /IT WORKS ##

Utilisateurs virtuels: création d'une base de données

J'ai créé une base de données locale :

# cd /etc/vsftpd

# db_load -T -t hash -f vsftpd-virtual-user.txt vsftpd-virtual-user.db

Avec un fichier vsftpd-virtual-user.txt tel que :

kortex
azerty1234

Test

J'ai testé avec FileZilla et ça fonctionne :

mon utilisateur peut se connecter

il peut écrire

etc

Et dans les logs de VSFTPd je vois bien un truc qui me plaît :

Thu Sep 15 14:01:13 2022 [pid 125098] CONNECT: Client "192.168.1.26"
Thu Sep 15 14:01:13 2022 [pid 125098] FTP response: Client "192.168.1.26", "220 (vsFTPd 3.0.3)"
Thu Sep 15 14:01:13 2022 [pid 125098] FTP command: Client "192.168.1.26", "USER kortex"
Thu Sep 15 14:01:13 2022 [pid 125098] [kortex] FTP response: Client "192.168.1.26", "331 Please specify the password."
Thu Sep 15 14:01:13 2022 [pid 125098] [kortex] FTP command: Client "192.168.1.26", "PASS <password>"
Thu Sep 15 14:01:13 2022 [pid 125097] [kortex] OK LOGIN: Client "192.168.1.26"
Thu Sep 15 14:01:13 2022 [pid 125099] [kortex] FTP response: Client "192.168.1.26", "230 Login successful."
Thu Sep 15 14:01:13 2022 [pid 125099] [kortex] FTP command: Client "192.168.1.26", "PWD"
Thu Sep 15 14:01:13 2022 [pid 125099] [kortex] FTP response: Client "192.168.1.26", "257 "/" is the current directory"
Thu Sep 15 14:01:13 2022 [pid 125099] [kortex] FTP command: Client "192.168.1.26", "TYPE I"
Thu Sep 15 14:01:13 2022 [pid 125099] [kortex] FTP response: Client "192.168.1.26", "200 Switching to Binary mode."
Thu Sep 15 14:01:13 2022 [pid 125099] [kortex] FTP command: Client "192.168.1.26", "PASV"
Thu Sep 15 14:01:13 2022 [pid 125099] [kortex] FTP response: Client "192.168.1.26", "227 Entering Passive Mode (192,168,1,16,178,214)."
Thu Sep 15 14:01:13 2022 [pid 125099] [kortex] FTP command: Client "192.168.1.26", "LIST"
Thu Sep 15 14:01:13 2022 [pid 125099] [kortex] FTP response: Client "192.168.1.26", "150 Here comes the directory listing."
Thu Sep 15 14:01:13 2022 [pid 125099] [kortex] FTP response: Client "192.168.1.26", "226 Directory send OK."

Ok jusque là tout roule ;)

Ce que j'ai fait et qui ne fonctionne pas

Maintenant j'ai essayé d'adapter la partie PAM pour basculer sur un script maison et ça se complique un peu :D
Bon si ça fonctionnait je ne serais pas en train d'écrire un roman ;)

Création d'un script Python

J'ai créé un script Python /opt/pam/pamAuthenticationWithKeycloak.py tel que :

#!/usr/bin/python3

import os
import sys

if __name__ == '__main__':
    if 'PAM_TYPE' not in os.environ:
        print('[ERROR] The environment variable \'PAM_TYPE\' is not setted')
        sys.exit(4)

    print('[INFO] Reading the password from stdin...')
    sUserPassword = sys.stdin.read()

    if sUserPassword.strip() != '':
        print('[INFO] OK: %(sUserPassword)s' %{'sUserPassword': sUserPassword})
    else:
        print('[ERROR] Unable to read the password')
        sys.exit(4)

    sys.exit(0)

--> on a dit pas les mamans et pas la tête du code ;) Ce n'est pas la question :-)

L'idée est de voir comment tout ceci se comporte: vous noterez que je ne suis toujours pas connecté à Keycloak ici.

PAM: modification du fichier qui marchait

Bon normalement on dit "ça marche, touche pô".
Mais là je devais modifier le fichier '/etc/pam.d/ftp_keycloak' pour exécuter mon script Python :)
Donc j'ai modifié tel que :

#%PAM-1.0

auth       required     pam_exec.so             expose_authtok log=/var/log/pamAuthenticationWithKeycloak.log       /opt/pam/pamAuthenticationWithKeycloak.py
account    required     pam_exec.so             expose_authtok log=/var/log/pamAuthenticationWithKeycloak.log       /opt/pam/pamAuthenticationWithKeycloak.py
session    required     pam_loginuid.so

Test

J'ai redémarré VSFTPd et j'ai testé :

Maintenant rien ne va plus, faites vos jeux ;)

Côté FileZilla je vois ceci :

Statut :   Connexion à 192.168.1.16:21…
Statut :   Connexion établie, attente du message d’accueil…
Erreur :   Connection interrompue après 20 secondes d’inactivité
Erreur :   Impossible d’établir une connexion au serveur
Statut :   Attente avant nouvel essai…
[...]

Côté vsftpd.log j'ai ceci :

Thu Sep 15 14:06:31 2022 [pid 126244] CONNECT: Client "192.168.1.26"
Thu Sep 15 14:06:31 2022 [pid 126244] FTP response: Client "192.168.1.26", "220 (vsFTPd 3.0.3)"
Thu Sep 15 14:06:33 2022 [pid 126244] FTP command: Client "192.168.1.26", "USER kortex"
Thu Sep 15 14:06:33 2022 [pid 126244] [kortex] FTP response: Client "192.168.1.26", "331 Please specify the password."
Thu Sep 15 14:06:33 2022 [pid 126244] [kortex] FTP command: Client "192.168.1.26", "PASS <password>"

Alors clairement je pense ne rien avoir compris à comment marche un module PAM :D

Je pensais naïvement que le script exécuté par pam_exec.so devait simplement se terminer avec un code retour qui permettait au module PAM de savoir si c'est oui ou non…
Visiblement je me trompe ou alors j'ai quelque chose d'autre qui est mal configuré.

Comme vous l'avez vu, le script Python ne fait rien de fou pour l'instant : il quitte avec un code 0 (j'ai testé en manuel). Je n'ai pas encore écrit le code pour requêter Keycloak.

Quelqu'un aurait une piste à me donner pour résoudre ce problème avec un script aussi simple svp :) ?

Je vous remercie d'avance :)