Sommaire
- Contexte
- Stack technique
- Ce que j'ai fait et qui fonctionne
- Ce que j'ai fait et qui ne fonctionne pas
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 :)
# linux magazine 259
Posté par eric gerbier (site web personnel) . Évalué à 2.
Dans le dernier linux magazine (259), il y a un article qui pourrait te mettre sur la voie : https://connect.ed-diamond.com/gnu-linux-magazine/glmf-259/jouons-avec-les-linux-pluggable-authentication-modules
L'auteur décrit le fonctionnement de pam, puis code un petit module python d'exemple.
[^] # Re: linux magazine 259
Posté par kortex . Évalué à 2.
Merci beaucoup :)
Je crois que je vais filer chez le marchand de journaux voir si je le trouve car j'en perds mon latin :)
[^] # Re: linux magazine 259
Posté par kortex . Évalué à 1.
J'en ai fait 3 et aucun ne l'avait. Quand tu as la poisse… :)
# boundary project
Posté par Mathieu CLAUDEL (site web personnel) . Évalué à 2.
Ça ne répond pas à la question, mais je suis en train de tester https://www.boundaryproject.io/ (hashicorp) couplé à un keycloak et il doit y avoir tout ce qu'il faut pour faire du ssh sans ouvrir le port sur internet et avec une authentification utilisateur OIDC (donc keycloak !).
Je n'ai pas fait de ssh dans mon cas, mais il est pas mal documenté.
Pour résumer, c'est un service (plusieurs) accessible en https qui après une authentification (local ou OIDC) permet d'ouvrir un tunnel vers une cible. Cela peut être couplé à vault (hashicorp) pour la gestion des secrets pour les authentifications des cibles.
La solution est encore jeune (très) et n'est, je pense, pas encore utilisable pour une grosse production, mais c'est une solution à suivre !
Après ce n'est peut-etre pas possible à installer chez ton prestataire ni assez stable pour votre cible.
[^] # Re: boundary project
Posté par Mathieu CLAUDEL (site web personnel) . Évalué à 1.
Sinon, pour la partie keycloak, pense device flow si c'est possible plutôt que ressource owner password (grant_type=password) ça permettra de basculer sur des méthodes d'authentification utilisateur autre de login password voir même de la déléguer à d'autre IdP,…
[^] # Re: boundary project
Posté par kortex . Évalué à 1.
Merci pour le partage : je ne connaissais pas et ça peut être sympa à suivre effectivement :)
Alors je n'ai pas encore regardé donc je vais sûrement répondre à côté.
Par contre du descriptif que tu en as fait, on est d'accord que des logiciels standards type FileZilla seront de facto incompatibles s'il faut ouvrir une session en https avant ?
Car si c'est bien ça, mon exemple avec FileZilla devient vrai pour tous les utilisateurs qui ont des logiciels / scripts uniquement compatibles avec le vrai protocol SFTP non ?
[^] # Re: boundary project
Posté par Mathieu CLAUDEL (site web personnel) . Évalué à 1.
effectivement, j'ai pas précisé, ton client au lieu de se connecter sur la target (qui n'est de toute façon pas accessible) tu se connecte en local (localhost) ou le client boundary à ouvert le tunnel. (un peut comme on le ferait avec un port forward en k8s si tu connais)
en gros simplifié :
[Application cliente] -localhost:xxx-> [client boundary] ==tunel==> [serveur boundary] --> [serveur cible]
en officiel si tu es au top :
[^] # Re: boundary project
Posté par kortex . Évalué à 1.
Je vais m'intéresser à cette partie dès que j'ai du temps mais plus pour mon accès SSH que pour le serveur SFTP :)
Pour la partie SFTP c'est trop contraignant pour les utilisateurs qui sont dépendants de leur IT au niveau des outils qu'ils ont à disposition :/
Merci encore pour le partage
# Petite progression
Posté par kortex . Évalué à 1.
Avant mes congés j'avais trouvé ceci : https://askubuntu.com/questions/406486/vsftpd-hanging-when-using-pam-exec-or-pam-script
Mais ça m'était sorti de la tête.
Ce matin j'ai creusé cette piste et j'ai une petite progression.
Test 1
J'ai :
Résultat : échec total
Test 2
J'ai :
Résultat : échec total
Test 3
J'ai :
Résultat : échec partiel
Dans les logs de VSFTPd j'ai :
Je n'ai plus d'activité dans le fichier de log /var/log/pamAuthenticationWithKeycloak.log : comme si le module PAM n'était plus appelé.
J'ai pourtant vérifié dans builddefs.h et le support de PAM est activé :
Après peut-être que VSFTPd est une mauvaise idée aussi.
Si je dois commencer à patcher du code C que je ne comprends pas et compiler moi même les sources pour arriver à quelque chose, je me demande si c'est une bonne idée pour déployer en production…
# minio?
Posté par devnewton 🍺 (site web personnel) . Évalué à 3.
Plutôt que FTP, je préfère faire des échanges de fichiers via S3 avec par exemple MinIO.
Le post ci-dessus est une grosse connerie, ne le lisez pas sérieusement.
[^] # Re: minio?
Posté par kortex . Évalué à 1.
Merci pour la suggestion :)
Par contre ça rejoint ce que je disais plus haut à propos de boundaryproject : c'est cool mais pour un autre cas d'usage :/
Ici mon post concerne une plateforme FTP car c'est la partie que je dois revoir pour proposer mieux "rapidement" car la stack SFTP est vraiment vilaine + j'ai les contraintes avec le fournisseur qui ne m'ouvre pas le port…
Mais j'ai aussi suggérer à mon chef de gérer d'autres protocoles.
L'idée proposée serait de proposer à l'utilisateur de pousser ses données dans différents canaux :
Et ces canaux pourraient être soit chez nous soit directement chez eux. Exemple : l'utilisateur a son propre bucket S3 quelque part, il nous donne les credentials et nous on s'y connecte pour pousser les données.
En d'autres termes, l'utilisateur qui lance ses traitements dans notre logiciel choisirait où il veut les envoyer en fonction de ce avec quoi il est compatible / ce qu'il veut en faire / etc.
Du coup dans cette optique clairement une brique comme minio pourrait m'aider dans les étapes d'après (et je te remercie encore pour la proposition car je ne connaissais pas).
Mais malheureusement ici j'ai surtout besoin de voir quelle magie je peux faire en FTP standard. Je ne sais pas si le bon smiley serait " :) " ou " :( " :-D
Alors je peux aussi gérer des utilisateurs FTP sur le côté (donc indépendant de Keycloak) : ça je sais faire. C'est juste que je voulais m'éviter de me faire ***** avec une gestion des utilisateurs si j'arrive à me connecter à Keycloak :D
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.