Comment créer un utilisateur SSH restreint pour le transfert de port?

106

ændrük a suggéré une connexion inverse pour obtenir une connexion SSH facile avec quelqu'un d'autre (pour l'aide à distance). Pour que cela fonctionne, un utilisateur supplémentaire est nécessaire pour accepter la connexion. Cet utilisateur doit pouvoir transférer son port via le serveur (le serveur agit en tant que proxy).

Comment créer un utilisateur restreint qui ne peut rien faire de plus que ce qui est décrit ci-dessus?

Le nouvel utilisateur ne doit pas pouvoir:

  • exécuter des commandes shell
  • accéder à des fichiers ou télécharger des fichiers sur le serveur
  • utiliser le serveur en tant que proxy (par exemple webproxy)
  • accéder à des services locaux qui n'étaient autrement pas accessibles au public en raison d'un pare-feu
  • tuer le serveur

En résumé, comment créer un utilisateur SSH restreint pouvant uniquement se connecter au serveur SSH sans privilèges, afin de pouvoir me connecter via cette connexion à son ordinateur?

Lekensteyn
la source

Réponses:

166

TL; DR - aller au bas de la réponse, "Appliquer les restrictions"

L'ajout d'un utilisateur restreint se compose de deux parties: 1. Création de l'utilisateur 2. Configuration du démon SSH (sshd)

Configuration de sshd

Le meilleur endroit pour connaître les possibilités de SSH consiste à lire les pages de manuel correspondantes:

Où le client SSH peut-il effectuer des actions?

Avant de pouvoir limiter quelque chose, vous devez connaître les fonctionnalités de SSH. En parcourant les pages de manuel, vous obtenez:

  • Exécution des commandes shell
  • Téléchargement de fichier via sftp
  • Redirection de port
    • Le client transmet un port (non) utilisé au serveur
    • Le serveur transmet son port au client
    • Le serveur transmet le port d'un autre hôte au client (proxy-ish)
  • X11 forwarding (transfert d'affichage)
  • Transfert d'agent d'authentification
  • Transfert d'un appareil tunnel

Dans la section Authentification de la page de manuel de sshd (8) :

Si le client s’authentifie avec succès, une boîte de dialogue permettant de préparer la session est ouverte. À ce stade, le client peut demander des choses telles que l’ allocation d’un pseudo-tty, le transfert de connexions X11, le transfert de connexions TCP ou le transfert de la connexion d’agent d’authentification sur le canal sécurisé.

Après cela, le client demande un shell ou l'exécution d'une commande . Les côtés entrent ensuite en mode session. Dans ce mode, chaque côté peut envoyer des données à tout moment, et ces données sont transférées vers / depuis le shell ou la commande côté serveur et le terminal utilisateur côté client.

Options pour restreindre les fonctionnalités SSH

Les fichiers et leurs options qui modifient le comportement sont les suivants:

  • ~/.ssh/authorized_keys - contient des clés autorisées à se connecter auxquelles peuvent être attribuées des options:
    • command="command"- La commande fournie par l'utilisateur (le cas échéant) est ignorée. Notez que le client peut spécifier un transfert TCP et / ou X11 à moins que cela ne soit explicitement interdit . Notez que cette option s'applique à l'exécution du shell, de la commande ou du sous-système.
    • no-agent-forwarding - Interdit le transfert de l'agent d'authentification lorsque cette clé est utilisée pour l'authentification.
    • no-port-forwarding - Interdit le transfert TCP lorsque cette clé est utilisée pour l'authentification
    • no-X11-forwarding - "Interdit le transfert X11 lorsque cette clé est utilisée pour l'authentification."
    • permitopen="host:port" - Limitez le transfert de port local 'ssh -L' de sorte qu'il ne puisse se connecter qu'à l'hôte et au port spécifiés.
  • ~/.ssh/environment- Ce fichier est lu dans l'environnement lors de la connexion (s'il existe). Le traitement de l'environnement est désactivé par défaut et est contrôlé via l'option PermitUserEnvironment.
  • ~/.ssh/rc - Contient les routines d'initialisation à exécuter avant que le répertoire de base de l'utilisateur ne soit accessible.
  • /etc/ssh/sshd_config - le fichier de configuration du système
    • AllowAgentForwarding - Spécifie si le transfert ssh-agent (1) est autorisé.
    • AllowTcpForwarding
    • ForceCommand - "Force l'exécution de la commande spécifiée par ForceCommand, en ignorant toute commande fournie par le client et ~ / .ssh / rc s'il est présent. La commande est appelée à l'aide du shell de connexion de l'utilisateur avec l'option -c."
    • GatewayPorts - "Spécifie si les hôtes distants sont autorisés à se connecter aux ports transférés pour le client. Par défaut, sshd (8) lie les transferts de port distants à l'adresse de bouclage. Ceci empêche les autres hôtes distants de se connecter aux ports transférés. GatewayPorts peut être utilisé pour spécifier sshd devrait permettre aux redirections de ports distants de se lier à des adresses autres que des bouclages, permettant ainsi à d'autres hôtes de se connecter. "
    • PermitOpen:

      Spécifie les destinations vers lesquelles le transfert de port TCP est autorisé. La spécification de transmission doit être l’une des formes suivantes:

      PermitOpen host:port
      PermitOpen IPv4_addr:port
      PermitOpen [IPv6_addr]:port
      

      Plusieurs transferts peuvent être spécifiés en les séparant par des espaces. Un argument de 'tout' peut être utilisé pour supprimer toutes les restrictions et permettre toute demande de transfert. Par défaut, toutes les demandes de transfert de port sont autorisées.

    • PermitTunnel- Spécifie si le transfert de périphérique tun (4) est autorisé. La valeur par défaut est "non"
    • X11Forwarding- Spécifie si le transfert X11 est autorisé. La valeur par défaut est "non"

Appliquer les restrictions

La modification du fichier de configuration à l'échelle du système /etc/ssh/sshd_configpermet d'appliquer la configuration même si l'authentification par mot de passe est appliquée ou si les restrictions spécifiées ~/.ssh/authorized_keyssont supprimées par inadvertance. Si vous avez modifié les paramètres globaux par défaut, vous devez supprimer les commentaires en conséquence.

Match User limited-user
   #AllowTcpForwarding yes
   #X11Forwarding no
   #PermitTunnel no
   #GatewayPorts no
   AllowAgentForwarding no
   PermitOpen localhost:62222
   ForceCommand echo 'This account can only be used for [reason]'

Maintenant, ajoutez un utilisateur:

sudo useradd -m limited-user

L'option ForceCommandpeut être omise si le shell est défini sur un non-shell comme /bin/false(ou /bin/true), /bin/false -c [command]cela ne fera rien.

Désormais, le client ne peut se connecter qu'au port 62222 sur l'adresse de bouclage du serveur via SSH (il n'écoutera pas l'adresse IP publique).

Désactiver AllowTcpForwardingempêcherait également l'utilisation de -R, ce qui empêcherait l'utilisation d' un tel compte restreint pour le transfert d'un seul port. PermitOpen localhost:62222suppose que le port 62222 sur le serveur n'est jamais utilisé, car le client peut se connecter à celui-ci et l'écouter également.

Si le transfert TCP est autorisé dans la configuration à l'échelle du système et que l'authentification par mot de passe est désactivée, vous pouvez également utiliser les paramètres par clé. Éditez ~/.ssh/authorized_keyset ajoutez les options suivantes avant le ssh-(avec un espace entre les options et ssh-):

command="echo 'This account can only be used for [reason]'",no-agent-forwarding,no-X11-forwarding,permitopen="localhost:62222"

Vérifier

Pour être sûr que cela fonctionne comme prévu, certains cas de test doivent être exécutés. Dans les commandes ci-dessous, hostdoit être remplacé par l'identifiant actuel s'il n'est pas défini dans ~/.ssh/config. Derrière la commande, une commande est affichée et doit être exécutée soit sur le client, soit sur le serveur (comme spécifié).

# connection closed:
ssh host
# connection closed (/bin/date is not executed):
ssh host /bin/date
# administratively prohibited (2x):
ssh host -N -D 62222 # client: curl -I --socks5 localhost:62222 example.com
ssh host -N -L 8080:example.com:80 # client: curl -I localhost:8080
sftp host
# should be possible because the client should forward his SSH server
ssh host -N -R 8080:example.com:80 # server: curl -I localhost:8080
# This works, it forwards the client SSH to the server
ssh host -N -R 62222:localhost:22
# unfortunately, the client can listen on that port too. Not a big issue
ssh host -N -L 1234:localhost:62222

Conclusion

Liste de contrôle: L'utilisateur SSH ne doit pas pouvoir:

  • exécuter des commandes shell - terminé
  • accéder aux fichiers ou télécharger des fichiers sur le serveur - terminé
  • utiliser le serveur en tant que proxy (par exemple, webproxy) - terminé
  • accéder aux services locaux qui n'étaient autrement pas accessibles publiquement à cause d'un pare-feu - en partie , le client ne peut pas accéder à d'autres ports que 62222, mais peut écouter et se connecter au port 62222 sur le serveur
  • tuer le serveur - terminé (ces vérifications sont limitées au serveur SSH. Si vous disposez d'un autre service vulnérable sur la machine, un attaquant éventuel pourrait exécuter des commandes, tuer le serveur, etc.).
Lekensteyn
la source
3
Pour que cela fonctionne, le compte ajouté par useradddoit être déverrouillé. Cela peut être fait en remplaçant le mot de passe /etc/shadowpar un asteric ( *) ou en définissant un mot de passe avec sudo passwd limited-user.
Lekensteyn le
2
SFTP fonctionne parce que le serveur SSH exécute la sftp-servercommande. Avec ForceCommand, cette commande ne sera plus exécutée.
Lekensteyn
2
L’ from=option de authorized_keys. Cela vous permet de limiter l'utilisation de la clé aux sources avec une adresse IP ou un nom d'hôte particulier. Exemple, from="1.1.1.1"ou from="10.0.0.?,*.example.com". Reportez-vous à la section "FORMAT DE FICHIER AUTHORIZED_KEYS" dans la page de manuel ( linux.die.net/man/8/sshd ) pour connaître toutes les options allowed_keys .
Donn Lee
2
"AllowTcpForwarding local" interdit le transfert à distance. (Je ne sais pas si elle existait au moment de la rédaction de cette réponse.)
Simon Sapin Le
1
Notez que ceci est cassé par les connexions ssh persistantes, vous ne devriez donc pas avoir quelque chose de similaire Host * ControlMaster autodans votre ~/.ssh/configfichier lorsque vous vous connectez avec ssh -N. Si vous en avez besoin, utilisezssh -N -o ControlMaster=no
nh2
3

Je suis sûr qu'il existe de nombreuses solutions à ce problème, et beaucoup plus robustes que celle que je propose. Cependant, cela peut suffire à vos besoins. Pour ce faire, je suppose que l'utilisateur est capable de faire une authentification basée sur une clé ssh (le mastic ou n'importe quel six unix devrait le supporter).

  • Ajouter un utilisateur comme vous le feriez normalement ('adduser' ou tout autre outil)

  • Créez les répertoires .ssh et .ssh / registered_keys des utilisateurs

your_user $ sudo -Hu ssh_forwarder /bin/bash

ssh_forwarder $ cd ~
ssh_forwarder $ mkdir .ssh
ssh_forwarder $ ( umask 066 && cat > .ssh/authorized_keys ) <<EOF
no-agent-forwarding,no-X11-forwarding,command="read a; exit" ssh-rsa AAAB3NzaC1y....2cD/VN3NtHw== smoser@brickies
EOF
  • Désactiver l'accès par mot de passe à ce compte.
your_user $ sudo usermod --lock ssh_forwarder

Désormais, le seul moyen pour l'utilisateur d'accéder à votre système consiste à accéder à la clé ssh appropriée. Ssh exécutera "/ bin / bash -c" en lisant un "", quel que soit le type de tentative d'exécution. 'read a' lira simplement jusqu'à une nouvelle ligne, puis le shell se fermera, l'utilisateur n'aura donc qu'à appuyer sur 'entrée' pour tuer la connexion.

Il y a beaucoup d'autres choses que vous pourriez faire dans 'command ='. Voir man authorized_keyset rechercher 'commande' pour plus d'informations.

Si vous n'aimez pas le fait que frapper entrée tue la connexion, vous pouvez utiliser quelque chose comme ceci pour l'entrée 'commande =':

command="f=./.fifo.$$ && mkfifo $f && trap \"rm -f $f\" EXIT && read a <$f && echo $a; exit;"

Cela crée simplement un fifo temporaire dans le répertoire de base des utilisateurs, puis tente de le lire. Rien ne sera écrit dans ce fichier, donc ce sera suspendu indéfiniment. De plus, si vous souhaitez mettre fin de manière forcée à cette connexion, vous pouvez procéder comme suit:

 your_user$ echo GOODBYE | sudo tee ~ssh_forwarder/.fifo.*

Cela devrait utiliser très peu de ressources et rien ne devrait se passer de ce script qui ne se termine pas par la fermeture du shell.

sleep 1h; echo You have been here too long. Good bye.

Je n'ai pas vu d'emblée comment vous pouvez autoriser l'utilisateur à transférer à distance ( ssh -R) mais à limiter ( ssh -L). Peut-être que «permitopen» pourrait être utilisé. Googler n'était pas très utile. Il semblerait que quelque chose comme 'no-port-forwarding, permitremoteopen = 10001' serait utile à permettre ssh -R 6901:localhost:6901.

C'est une solution. Cela peut certainement être amélioré et toute ouverture de ports distants devrait être examinée attentivement. Si mon objectif était de permettre à ma grand-mère de se connecter à mon réseau local afin que je puisse utiliser vnc pour afficher son écran, et que l'accès à ces clés lui était réservé, je me sentirais raisonnablement en sécurité. S'il s'agissait d'une entreprise, une enquête plus approfondie serait nécessaire. Une chose à prendre en compte est de ssh -Nne pas demander un shell du tout, donc le code 'command =' ne s'exécute pas.

D'autres mécanismes, peut-être plus sécurisés, peuvent inclure la création d'un shell personnalisé pour l'utilisateur, et même le verrouiller avec apparmour.

smoser
la source
3
Cela a l'air très bidon, il n'est même pas nécessaire d'avoir un shell car aucune commande ne doit être exécutée. Voir la page de manuel dessh pour l' -Noption. Il doit y avoir un moyen plus propre d’y parvenir.
Lekensteyn
C'est vrai. J'espère voir une solution plus propre également. Je pense en tout cas qu'autorisé_keys, associé à l'absence de redirection de port, constituerait une très bonne solution s'il existait l'option 'autoriser à distance'.
smoser
J'ai fait quelques recherches (voir ci-dessus). Puisque ssh -Nn'exécute pas du tout une commande, ce n'est pas un problème pour command="something"fermer la session.
Lekensteyn
Est-ce que je manque quelque chose? Il semblait que chsh ssh_forwarder -s /bin/false c'est tout ce qu'il faut.
Typelogic