J'ai plusieurs raspberry pi exécutant Arch Linux (pas d'interface graphique) auxquels j'ai besoin d'accéder. Ces pi sont derrière des pare-feu dans chaque emplacement unique. Actuellement, j'utilise openvpn pour me connecter à ceux-ci, mais les coûts de ce système sont élevés par licence. J'utilise le serveur d'accès d'eux.
En conséquence, j'essaie de concevoir et de configurer un système qui me permet de me connecter à mon serveur VPN (vps) et d'exécuter une commande pour rechercher un nom spécifique (OfficeDevice1991) tel que :customcommandsearch "OfficeDevice1991"
puis il renvoie ensuite l'adresse IP de la machine ou quelque chose que je peux utiliser pour SSH avec. Je recherche également la possibilité d'exécuter une commande pour répertorier tous les appareils connectés actifs. Il répertorie l'adresse IP, le nom et peut-être depuis combien de temps il est actif.
Pour cet objectif, j'ai bien sûr besoin de créer quelque chose qui inclut le nom de l'appareil (dans ce cas OfficeDevice1991) et ensuite ce pi pourra se connecter à mon serveur public vps. À partir du serveur public, je peux me connecter et effectuer une recherche sur tous les appareils qui y sont connectés et renvoyer les informations requises pour ssh.
J'ai étudié le SSH inversé et jusqu'à présent, j'ai connecté l'un de mes pi de test et accessible depuis mon vps en utilisant les commandes suivantes :
PI :
ssh -fN -R 12345:localhost:22 -i /publickeyfile [email protected] //Pi's command to connect to vpn
VPS :
ssh -p 12345 [email protected] //command for vpn to connect to pi
Cela fonctionne très bien, mais en utilisant cette méthode, si je devais l'implémenter, je rencontrerais quelques problèmes :
- Je devrais configurer des ports inutilisés uniques
- Un moyen de garder ces ports/tunnels ouverts
- Je dois trouver un système pour identifier chaque appareil. Je peux connecter chaque port à un nom comme un fichier texte localement ? Il serait avantageux de pouvoir l'inclure dans la configuration ssh de chaque appareil si possible. Je devrais quand même m'assurer que les ports que j'utilise ne sont pas utilisés par d'autres programmes ou par un appareil déjà présent.
Ce que je ne veux pas avoir à faire
-
Vérifiez quels ports sont libres d'utiliser pour chaque RPI
-
Doit modifier manuellement
.ssh/config
pour ajouter un nom pour représenter chaque port attribué à RPI de la partie 1 ci-dessus.
J'écris ceci pour obtenir des informations / de l'aide sur ce qu'il faut faire pour atteindre mon objectif.
Quelqu'un pourrait-il me fournir une solution appropriée ?
Réponse acceptée :
Voici une solution utilisant OpenSSH>=6.7 + socat :
-
OpenSSH>=6.7 peut utiliser le transfert de socket de domaine Unix
Cela signifie que le point de terminaison du tunnel inverse sera un socket d'écoute UNIX au lieu d'un socket d'écoute TCP traditionnel. Vous pouvez alors gérer plus facilement la flottille de RPI avec un schéma de nommage simple :le nom du socket sera le nom choisi (et fixe) du RPI, comme
OfficeDevice1991
. Il pourrait même s'agir d'une propriété unique du RPI tant qu'il s'agit d'un nom de fichier valide (puisque les noms de socket unix adhèrent aux conventions de nom de fichier). Par exemple son hostname, l'adresse MAC de sa carte ethernet ou wifi…SSH peut gérer les sockets Unix pour les tunnels, pas pour se connecter. Il aura besoin de l'aide d'un
ProxyCommand
pour pouvoir travailler en tant que client unix-socket. socat peut gérer de nombreux types de connexions, y compris les sockets unix.MISE À JOUR :
Il y a aussi un problème spécifique à gérer :le fichier de socket unix n'est pas supprimé lors d'une sortie propre, et il n'aurait pas été supprimé de toute façon, par exemple après un crash. Cela nécessite l'optionStreamLocalBindUnlink=yes
. Je n'ai pas trouvé initialement que, comme son nom l'indique peut-être, cette option doit être définie sur le nœud créant le socket unix. Donc, à la fin, il est défini sur le client avec un transfert local (-L
) ou bien sur le serveur (danssshd_config
) avec un renvoi à distance (-R
). OP l'a trouvé là-bas. Cette solution utilise un renvoi à distance.Paramétrage sur VPS :
mkdir /rpi-access
(en tant que root) modifiez le
sshd_config
fichier (/etc/ssh/sshd_config
). Il nécessite cette option supplémentaire :StreamLocalBindUnlink yes
Selon les options par défaut, il peut également nécessiter
AllowStreamLocalForwarding yes
UPDATE2 :
Également défini danssshd_config
les paramètresClientAliveInterval
etClientAliveCountMax
, permettant ainsi de détecter une déconnexion dans un délai raisonnable, par exemple :ClientAliveInterval 300 ClientAliveCountMax 2
Les connexions ssh obsolètes devraient alors être détectées plus tôt sur le VPS (~10mn avec l'exemple), et le processus sshd correspondant se terminera alors.
Utilisation sur RPI :
ssh -fN -R /rpi-access/OfficeDevice1991:localhost:22 -i /privatekeyfile [email protected]
Dans un fichier de configuration, cela ressemblerait à ceci :
Host ip User useraccount RemoteForward /rpi-access/OfficeDevice1991:localhost:22 IdentityFile /privatekeyfile
En le répétant à nouveau :le
StreamLocalBindUnlink yes
défini sursshd
côté VPS est importante :la socket qui vient d'être créée n'est pas supprimée, même lors d'une sortie normale. Cette option garantit que la prise est retirée si elle existe avant utilisation, permettant ainsi d'être réutilisée pour d'autres reconnexions. Cela signifie également qu'on ne peut pas considérer la simple présence de la prise comme signifiant que le RPI est connecté (mais voir plus tard).Maintenant cela permet de faire sur VPS :
ssh -o 'ProxyCommand=socat UNIX:/rpi-access/%h -' [email protected]
En tant que fichier de configuration, en considérant par exemple que les RPI ont tous un nom commençant par OfficeDevice :
Host OfficeDevice* User rpiuseraccount ProxyCommand socat UNIX:/rpi-access/%h -
-
Pour conserver le lien, il suffit d'utiliser une boucle
Le RPI peut exécuter une boucle reconnectant ssh au VPS chaque fois que les connexions se terminent. Pour cela, il ne doit pas utiliser le mode arrière-plan (pas de
-f
). Un mécanisme keepalive devrait également être utilisé. TCPKeepAlive (niveau système) ou ServerAliveInterval (niveau application) sont disponibles. Je pense que TCPKeepAlive n'est utile que sur le serveur (côté recevant la connexion), alors utilisons plutôt ServerAliveInterval.Sa valeur (ainsi que ServerAliveCountMax) est probablement à adapter en fonction de différents critères :un firewall abandonnant les connexions inactives après un certain temps, le délai de récupération souhaité, ne générant pas de trafic inutile, … disons 300s ici.
OfficeDevice1991 RPI :
#!/bin/sh while : ; do ssh -N -o ConnectTimeout=30 -o ServerAliveInterval=300 -R /rpi-access/OfficeDevice1991:localhost:22 -i /privatekeyfile [email protected] sleep 5 # avoid flood/DDoS in case of really unexpected issues done
Même si le côté distant n'a pas encore détecté l'échec de connectivité précédent et que l'ancienne connexion ssh est toujours en cours d'exécution,
StreamLocalBindUnlink yes
rafraîchira de toute façon avec force le socket unix avec la nouvelle connexion. -
il est déjà géré par 1.
Il n'y a pas de
customcommandsearch
avait besoin. Avec les bons paramètres définis dans 1. en utilisant simplementssh OfficeDevice1991
se connectera à OfficeDevice1991.Si besoin sur le VPS, en tant que
root
utilisateur uniquement, cette commande :fuser /rpi-access/*
peut montrer quels RPI sont actuellement connectés (sauf bien sûr ceux qui ont récemment perdu la connexion avant la détection). Il n'affichera pas les fichiers de socket Unix obsolètes car aucun processus ne leur est lié.