« Web-ssh » : différence entre les versions
mAucun résumé des modifications |
|||
| Ligne 82 : | Ligne 82 : | ||
== Prérequis == | == Prérequis == | ||
* WebSSH installé et fonctionnel | * WebSSH installé et fonctionnel | ||
* Python 3.11+ avec les modules | * Python 3.11+ avec les modules pyotp, qrcode, argparse | ||
* Accès au fichier | * Accès au fichier totp_secrets.json dans le bon répertoire | ||
* Serveur SSH distant accessible et configuré avec shell interactif | * Serveur SSH distant accessible et configuré avec shell interactif | ||
== Provisioning OTP == | == Provisioning OTP == | ||
=== Script de génération === | === Script de génération === | ||
Utiliser un script Python nommé | Utiliser un script Python nommé build-otp-key.py : | ||
* Génère une clé TOTP unique | * Génère une clé TOTP unique | ||
| Ligne 95 : | Ligne 95 : | ||
Exemple d’appel : | Exemple d’appel : | ||
<syntaxhighlight lang="bash"> | |||
python3 build-otp-key.py --host main-host --user admin --write | python3 build-otp-key.py --host main-host --user admin --write | ||
</syntaxhighlight> | |||
=== Format du fichier JSON === | |||
<syntaxhighlight lang="json"> | |||
{ | |||
"main-host": { | |||
"admin": "JBSWY3DPEHPK3PXP" | |||
}, | |||
"database": { | |||
"admin": "KRSW4ZDFEHPK3ABC" | |||
} | |||
} | |||
</syntaxhighlight> | |||
== Intégration dans WebSSH == | |||
=== Chemin du fichier secret === | |||
Corriger le chemin dans handler.py : | |||
<syntaxhighlight lang="python"> | |||
with open('/home/admin/sources/webssh-env/totp_secrets.json') as f: | |||
</syntaxhighlight> | |||
=== Vérification TOTP dans post() === | |||
Déballer les arguments : | |||
<syntaxhighlight lang="python"> | |||
hostname, port, username, password, pkey = self.get_args() | |||
</syntaxhighlight> | |||
Récupérer le code : | |||
<syntaxhighlight lang="python"> | |||
totp_code = self.get_argument('totp', default=None) | |||
</syntaxhighlight> | |||
Vérifier : | |||
<syntaxhighlight lang="python"> | |||
host_secrets = secrets.get(hostname, {}) | |||
user_secret = host_secrets.get(username) | |||
if user_secret: | |||
if not pyotp.TOTP(user_secret).verify(totp_code): | |||
raise tornado.web.HTTPError(403, "Invalid TOTP code") | |||
</syntaxhighlight> | |||
== Débogage == | |||
=== Logs utiles === | |||
* journalctl -u webssh -n 50 | |||
* Activer logging.DEBUG dans main.py | |||
=== Erreurs fréquentes === | |||
* AttributeError: 'tuple' object has no attribute 'get' → mauvais déballage de get_args() | |||
* NameError: name 'pyotp' is not defined → import manquant | |||
* Internal Server Error → fichier JSON introuvable ou mal formé | |||
* Oops, unhandled type 3 ('unimplemented') → bruit non bloquant de Paramiko | |||
== Alternatives == | |||
Si WebSSH échoue sur un hôte, utiliser un rebond : | |||
<syntaxhighlight lang="bash"> | |||
ssh admin@main-host | |||
ssh admin@database | |||
</syntaxhighlight> | |||
== Notes == | |||
* Le fichier sshd_config par défaut sur Raspberry Pi ne limite pas les algos. | |||
* Pour compatibilité maximale avec Paramiko, éviter les algos post-quantiques comme sntrup761. | |||
Version du 27 septembre 2025 à 21:48
Installer WebSSH avec reverse proxy Apache
Cette page décrit comment installer WebSSH dans un environnement isolé, le lancer en tant que service systemd, et le rendre accessible via Apache en HTTPS avec prise en charge des WebSocket.
1. Installation dans un environnement virtuel
EN général je travaille avec un user dédié, ici ce serait webssh ou un user d'administration admin. Dans la suite on considère admin.
Créer un environnement Python dédié :
python3 -m venv ~/sources/webssh-env
source ~/sources/webssh-env/bin/activate
pip install webssh
2. Script de lancement
Créer un script start-webssh.sh :
#!/bin/bash
source /home/admin/sources/webssh-env/bin/activate
exec wssh --address=127.0.0.1 --port=8888
Rendre le script exécutable :
chmod +x ~/sources/webssh-env/start-webssh.sh
3. Lancer WebSSH en tant que service
Voir créer un service systemd personnalisé pour créer un fichier webssh.service et activer le démarrage automatique.
4. Configuration Apache en reverse proxy
Dans la section HTTPS du VirtualHost :
Define WebSshURL "/webssh/"
<Location ${WebSshURL}>
ProxyPreserveHost On
ProxyPass http://localhost:8888/
ProxyPassReverse http://localhost:8888/
</Location>
# Support WebSocket
ProxyPassMatch ^/webssh/ws$ ws://localhost:8888/ws
# Support WebSocket via mod_rewrite
RewriteEngine On
RewriteCond %{REQUEST_URI} ^/webssh/ws$
RewriteCond %{QUERY_STRING} (.*)
RewriteRule ^/webssh/ws$ ws://localhost:8888/ws?%1 [P,L]
Modules requis :
sudo a2enmod proxy
sudo a2enmod proxy_http
sudo a2enmod proxy_wstunnel
Redémarrer Apache :
sudo systemctl restart apache2
5. Accès sécurisé
L’interface WebSSH est maintenant accessible via https://monserveur/webssh/. L’authentification SSH reste gérée par WebSSH. Une protection Apache (BasicAuth, IP, etc.) peut être ajoutée en amont si nécessaire.
Configuration OTP sur WebSSH
Objectif
Configurer une authentification TOTP (Time-based One-Time Password) sur WebSSH, par couple hôte/utilisateur, avec provisioning via QR code et vérification côté serveur.
Prérequis
- WebSSH installé et fonctionnel
- Python 3.11+ avec les modules pyotp, qrcode, argparse
- Accès au fichier totp_secrets.json dans le bon répertoire
- Serveur SSH distant accessible et configuré avec shell interactif
Provisioning OTP
Script de génération
Utiliser un script Python nommé build-otp-key.py :
- Génère une clé TOTP unique
- Affiche le QR code dans le terminal
- Enregistre la clé dans un fichier JSON structuré par hôte/utilisateur
Exemple d’appel :
python3 build-otp-key.py --host main-host --user admin --write
Format du fichier JSON
{
"main-host": {
"admin": "JBSWY3DPEHPK3PXP"
},
"database": {
"admin": "KRSW4ZDFEHPK3ABC"
}
}
Intégration dans WebSSH
Chemin du fichier secret
Corriger le chemin dans handler.py :
with open('/home/admin/sources/webssh-env/totp_secrets.json') as f:
Vérification TOTP dans post()
Déballer les arguments :
hostname, port, username, password, pkey = self.get_args()
Récupérer le code :
totp_code = self.get_argument('totp', default=None)
Vérifier :
host_secrets = secrets.get(hostname, {})
user_secret = host_secrets.get(username)
if user_secret:
if not pyotp.TOTP(user_secret).verify(totp_code):
raise tornado.web.HTTPError(403, "Invalid TOTP code")
Débogage
Logs utiles
- journalctl -u webssh -n 50
- Activer logging.DEBUG dans main.py
Erreurs fréquentes
- AttributeError: 'tuple' object has no attribute 'get' → mauvais déballage de get_args()
- NameError: name 'pyotp' is not defined → import manquant
- Internal Server Error → fichier JSON introuvable ou mal formé
- Oops, unhandled type 3 ('unimplemented') → bruit non bloquant de Paramiko
Alternatives
Si WebSSH échoue sur un hôte, utiliser un rebond :
ssh admin@main-host
ssh admin@database
Notes
- Le fichier sshd_config par défaut sur Raspberry Pi ne limite pas les algos.
- Pour compatibilité maximale avec Paramiko, éviter les algos post-quantiques comme sntrup761.