14 mar. 2011

Configuration d'OpenSSH

Lire la suite...

OpenSSH est un logiciel formidable, tout le monde le sait. Quelque chose que j'aime beaucoup avec ce logiciel, c'est la manière dont son fichier de configuration permet de simplifier certaines opérations. Je vous propose de voir ou de revoir certaines options qu'on peut ajouter à la suite d'un bloc de configuration qu'on stocke généralement dans ~/.ssh/config .

La base

On va configurer l'accès à la machine "testdrive" dont l'adresse IP est 192.168.13.37. Commençons avec les informations de base :

Host testdrive
        HostName 192.168.13.37
        User nils
        Protocol 2
        Port 22
        ServerAliveInterval 5

Lorsque que je taperai la commande "ssh testdrive", OpenSSH me connectera à la machine 192.168.13.37 en tant qu'utilisateur nils, en utilisant la version 2 du protocole SSH, sur le port 22 et vérifiera toutes les 5 secondes si la machine en question est toujours joignable, ce qui peut s'avérer pratique dans certains cas où on peut être déconnecté du réseau pour cause d'inactivité (réseau de téléphonie mobile, proxy...)

Connexion au travers d'un proxy HTTP

ProxyCommand /usr/bin/corkscrew monproxy.lan 3128 %h %p ~/.ssh/proxy_auth

Ici, j'utilise un utilitaire nommé Corkscrew qui me permet de me connecter via un proxy HTTP à mon serveur. Dans mon exemple, le proxy écooute sur le port 3128 et nécessite une authentification, j'ai donc ajouté un fichier proxy_auth contenant les identifiants. Les variables %h et %p désignent l'hôte vers qui se connecter et son port. A noter que la plupart des serveurs proxy qu'on peut trouver sont configurés pour ne pas autoriser les ports autres que les ports HTTP, HTTPS, et éventuellement FTP. Il faudra donc peut-être changer le port d'écoute de notre testdrive, et mettre notre serveur SSH sur le port 80 ou 443. A noter que selon l'organisation qui administre le proxy, cette manière de faire peut être vue comme une violation de la charte informatique du réseau, ou de tout autre règlement intérieur. Ne l'utilisez donc que si vous y êtes autorisés !

Créer un tunnel SOCKS

DynamicForward 1080

Cette option est très pratique si vous ne voulez pas vous casser la tête à créer un tunnel VPN. Une fois cette option ajoutée à la configuration de votre hôte, et la connexion à celui-ci effective, un tunnel SOCKS écoute sur la boucle locale de votre machine, sur le port 1080. Un cas concret d'utilisation est la connexion à vos sites préférés depuis un point d'accès sans fil public, comme une gare : une fois connecté au réseau, on se connecte en SSH à son serveur, puis on modifie les paramètres de proxy de notre navigateur web pour utiliser un proxy SOCKS dont l'adresse est 127.0.0.1 et le port est 1080. Tout le trafic web du navigateur passe ainsi dans la connexion SSH. Si vous faites souvent le va-et-viens dans votre configuration de proxy, Firefox possède une extension nommée FoxyProxy qui vous facilitera l'existence !

Créer un tunnel pour rediriger du trafic

LocalForward 5901 192.168.13.38:5900

Encapsuler un trafic réseau dans SSH est quelque chose de connu, et l'exemple ci-dessus est lui aussi archi-connu : le protocole VNC transite en clair sur le réseau, l'utilisation de SSH permet de chiffrer la transmission entre notre client et notre serveur. On transfère donc le port 5900 de la machine 192.168.13.38 (qui doit être joignable depuis notre machine testdrive) vers le port 5901 local. On lance ensuite notre client VNC en direction la machine localhost sur le port 5901.

Spécifier l'algorithme de chiffrement

Ciphers aes128-cbc

De nombreux algorithmes de chiffrement sont disponibles avec OpenSSH, vous pourrez trouver la liste dans les pages de manuel. Certains processeurs (tels que l'AMD Geode LX ou le VIA C7) savent déchiffrer certains algorithmes, ce qui les rend plus rapide pour ces types d'opérations. Forcer le chiffrement en AES 128 si vous vous connectez à une machine ayant un CPU AMD Geode peut ainsi s'avérer très efficace pour limiter l'utilisation du CPU et alléger la charge.

22 déc. 2009

Utilisation transparente d'une passerelle SSH

Ou comment rebondir sans même le faire exprès !

Lire la suite...

J'aime beaucoup OpenSSH. C'est un très bon logiciel, au-delà des capacités de chiffrement ou de son système de transfert de fichiers. Tunnels et commandes automatisées, authentification par clés, tout est bon dans le poisson ! Comme mon billet en 3 étapes m'a semblé clair, je continue sur l'organisation énoncé - possibilités - mise en œuvre.

C'est quoi ton problème ?

Imaginons une zone réseau (au hasard une DMZ) dans laquelle il y a une ou plusieurs machines, possédant toutes un serveur OpenSSH. Une seule machine peut accéder à ce réseau, cette "passerelle" servant de rebond pour accéder aux autres serveurs en SSH. Au bout d'un certain nombre de fois, il devient rébarbatif d'avoir à se connecter d'abord à la "passerelle" puis à se connecter au serveur pour y faire les manipulations désirées. Il faudrait automatiser le rebond pour qu'il se fasse tout seul, en quelque sorte.

Et t'as quoi comme solution ?

Il en existe plusieurs. Celle que je décris ici est celle qui me convient le mieux, mais peut ne pas vous satisfaire. Ne la considérez donc pas comme LA solution. Le principe est d'utiliser le fichier de configuration "utilisateur" d'OpenSSH (~/.ssh/config)pour automatiser le rebond via la directive "ProxyCommand". Commençons d'abord par lister les logiciels nécessaires : il nous suffit d'une machine avec un client OpenSSH (disponible sur tous les unix normalement, et sous Windows avec Cygwin), et sur la machine "passerelle", en plus du serveur OpenSSH, il nous faut le client et Netcat. Notez que dans mon cas :

  • le client est sous NetBSD 5.0.1
  • la passerelle est sous CentOS 5.4
  • les serveurs accédés sous sous l'un des deux OS mentionnés ci-dessus
  • j'ai reproduit ce système avec des RHEL 4

La commande de l'outil Netcat est "nc", vérifions donc que les commandes sont disponibles, d'abord le client :

nils@client:~$ which ssh
/usr/bin/ssh

Et puis la passerelle :

nils@passerelle:~# which ssh
/usr/bin/ssh
nils@passerelle:~# which nc
/usr/bin/nc

Le chemin n'est pas forcément le même selon l'OS utilisé, l'important c'est que les outils soient installés.

On passe à l'action ?

Rentrons à présent dans le vif du sujet. La configuration ne se fait que depuis la machine cliente, commençons par configurer un accès vers la passerelle. Pour cela, il faut créer un fichier ~/.ssh/config, et l'éditer avec le logiciel qui vous conviendra le mieux : dans mon cas, il s'agit de Vim. N'oublions pas de créer le répertoire .ssh/ s'il n'existe pas :

nils@client:~$ cd ~
nils@client:~$ mkdir .ssh
nils@client:~$ chmod 600 .ssh
nils@client:~$ cd .ssh
nils@tomb:~/.ssh$ touch config
nils@tomb:~/.ssh$ chmod 644 config
nils@tomb:~/.ssh$ vim config

Note : les droits sont très importants ! La configuration pour la passerelle est la suivante :

Host passerelle
        Hostname lenomouladresseipdelapasserelle
        Port 22
        Protocol 2
        User nils
        ProxyCommand none

On remarque que cette configuration n'a pour but que de simplifier les connexions vers la machine passerelle, il devient ainsi aisé de taper ssh passerelle au lieu de ssh nils@lenomouladresseipdelapasserelle (et le numéro de port si votre serveur OpenSSH n'écoute pas sur le port 22). Passons à la configuration pour accéder au serveur nommé serveurdmz1, qu'on ajoute à la suite du fichier config en cours d'édition :

Host serveurdmz1
        Hostname lenomouladresseipduserveurdepuislapasserelle
        Port 22
        Protocol 2
        User nils
        ProxyCommand ssh nils@passerelle "nc %h %p"

On remarque que la directive ProxyCommand utilise directement le nom passerelle, grâce à la configuration précédente. On sauvegarde et on quitte (sous Vi/Vim : Echap puis ZZ). Maintenant on teste le résultat :

nils@client:~$ ssh serveurdmz1
nils@passerelle's password:
nils@serveurdmz1's password:
nils@serveurdmz1:~$

Ce résultat peut différer légèrement, je ne poste pas les acceptations de clés pour les premières connexions. Il suffit maintenant de répéter le deuxième bloc pour chaque serveur de votre "DMZ".

Observations et améliorations possibles

Après ce premier essai, on remarque qu'il y a encore de la place pour l'automatisation, en particulier le mot de passe de la passerelle qui est réclamé. Ceci peut être résolu par l'utilisation de clés de chiffrement, comme l'explique très bien Peck.

Une autre remarque, si on se connecte à deux, trois serveurs : en tapant la commande who sur la passerelle, on voit qu'on est connecté une fois sur la passerelle pour chaque connexion vers un serveur en DMZ. Par exemple, si j'ai un shell sur la passerelle et un shell sur 3 serveurs en DMZ, la commande who sur la passerelle montrera que l'utilisateur nils est connecté 4 fois ! Cela peut s'avérer gênant pour certains. Pour ceux-là, il est préférable de changer de méthode, et de créer un tunnel socks puis d'utiliser ce tunnel pour accéder aux serveurs en DMZ (via la directive ProxyCommand), ou d'essayer de mutualiser les connexions. A noter un inconvénient du tunnel socks : il faut d'abord ouvrir le tunnel (et donc un shell) avant de pouvoir se connecter aux serveurs en DMZ.

13 oct. 2009

Transfert de fichier simple et sécurisé : sftp en chroot

Meurs, FTP, meurs !

Lire la suite...

C'est quoi ton problème ?

Comme beaucoup de gens, pour transférer des fichiers sur un serveur web, j'utilise souvent FTP. Ce protocole possède plusieurs inconvénients :

  • il faut ouvrir plusieurs ports dans le pare-feu, au moins deux (connexion de contrôle et de données)
  • le mot de passe transite en clair sur le réseau, et même si on utilise FTPS, qui chiffre la partie authentification, tous les clients et serveurs ne le supportent pas ou de manière boguée (voir chez FileZilla pour une explication)
  • les données transitent en clair (mince, le fichier config.php de mon appli avec les codes d'accès à la base de données...)
  • gestion du NAT catastrophique (du moins avec Vsftpd)

Du coup, je cherche depuis plusieurs mois à éradiquer FTP de mes machines. Ce qui m'intéresse, c'est de pouvoir enfermer les utilisateurs dans une cage, de sorte qu'ils n'aient accès qu'à leurs données et pas à celles des autres, encore moins les autres fichiers et répertoires du serveurs. On appelle ceci un chroot. Je faisais déjà ceci avec Vsftpd, j'espérais donc le faire avec la solution de remplacement. D'ailleurs, cette solution de remplacement était déjà toute trouvée : je désirais utiliser le serveur SFTP contenu dans le très bon logiciel OpenSSH. Maintenant, il me fallait réussir à créer des utilisateurs en leur empêchant d'avoir accès au shell, et en les confinant dans un chroot.

Et t'as quoi comme solution ?

Pour enlever l'accès au shell, très facile : tout système Unix qui se respecte possède soit un exécutable nommé false, soit un autre nommé nologin. D'ailleurs ce dernier est très simpliste, regardons sur, au hasard, un système NetBSD 5.0.1 :

nils@tomb:~ $cat /sbin/nologin 
#! /bin/sh
echo "This account is currently not available."
exit 1

Il suffit donc de remplacer le shell de l'utilisateur par le chemin vers nologin, et cette question est résolue.

Pour créer et maintenir un chroot, c'est une autre paire de manches. Dans Vsftpd c'était assez simple, et j'espérais trouver aussi simple. De nombreuses pages sur Scponly ou rssh expliquent comment faire un chroot pour un utilisateur n'ayant accès qu'à sftp ou scp, mais le jour où il faut mettre à jour l'OS, voire le migrer vers une version majeure plus récente (ou pourquoi pas en changer, comme passer d'un Linux à un BSD ou inversement, ou tout simplement changer de distribution Linux), le chroot doit être maintenu à jour. Et ça, je trouve que c'est totalement contre-productif, en tous cas du point de vue du sysadmin fainéant que nous avons tous en nous ;)

Et là, la lumière est arrivée, par ici. Depuis la version 4.8, OpenSSH permet de créer des chroot, et n'oblige pas à recréer tout un environnement quand il s'agit de sftp. Exactement ce dont j'ai besoin ! Maintenant, reste à savoir quels systèmes disposent d'au moins OpenSSH 4.8.

Une petite liste non-exhaustive des systèmes chanceux :

  • NetBSD 5.0.1
  • FreeBSD 7.2
  • Debian Lenny
  • Mac OS 10.5.8

Une autre liste, mais de systèmes moins chanceux :

  • CentOS 3,4,5.X
  • RHEL 3,4,5.X
  • Debian Etch

Si votre système unix libre (ou pas, d'ailleurs, puisque j'ai listé Mac OS X) comporte OpenSSH, vous pouvez vérifier sa version par :

nils@darkmoon:~ $ssh -V
OpenSSH_5.1p1, OpenSSL 0.9.7l 28 Sep 2006

(exemple pris sur un mac) En utilisant sshd au lieu de ssh, ça sera sans doute plus représentatif, mais l'option -V n'existe pas sur le serveur. La réponse retournée donnera quand même la version. Exemple, toujours sur le même mac :

nils@darkmoon:~ $sshd -V
sshd: illegal option -- V
OpenSSH_5.1p1, OpenSSL 0.9.7l 28 Sep 2006
usage: sshd [-46DdeiqTt] [-b bits] [-C connection_spec] [-f config_file]
            [-g login_grace_time] [-h host_key_file] [-k key_gen_time]
            [-o option] [-p port] [-u len]

Si votre système ne possède pas un OpenSSH assez récent, plusieurs possibilités s'offrent à nous :

  • changer de système
  • mettre à jour vers la dernière version majeure si celle-ci possède une version assez récente
  • installer sa propre version d'OpenSSH ou récupérer le paquet qu'aurait fait quelqu'un de généreux

La dernière solution est assez documentée pour CentOS et RHEL, pour faire ses propres RPM, mais j'ai décidé de ne pas la suivre, car cela pose le problème des mises à jour : de la même manière que maintenir un chroot ne me satisfait pas, passer mon temps à guetter les nouvelles versions d'OpenSSH pour compiler un paquet ne me plait pas plus. La deuxième solution s'avère sans doute la moins gênante selon les applications en production. De mon côté, j'ai choisi la première : migration de serveur dédié oblige, j'en ai profité pour élargir mes horizons dans le monde des unix libres et depuis quelques mois, ce blog tourne sous NetBSD. C'est donc avec cet OS que je vais décrire la manipulation de création de chroot.

On passe à l'action ?

Je pars du principe dorénavant que nous avons un système avec un OpenSSH 4.8 ou supérieur, que le serveur sshd est activé, que nous avons deux utilisateurs : root, et notre utilisateur habituel avec lequel nous faisons tout ce qui n'a pas besoin d'être fait en root. Le but est d'avoir un ou plusieurs utilisateurs supplémentaires, enfermés dans un répertoire défini, sans shell, et pouvant accéder à ce réperoire en sftp. On pourra, en supplément, faire en sorte que l'utilisateur accède à son compte sftp avec une clé (et éventuellement une phrase de passe) plutôt qu'un mot de passe.

Cela va se faire en modifiant dans un premier temps le fichier de configuration /etc/ssh/sshd_config (en tant que root, et le chemin peut varier selon le système). Cherchons la ligne contenant sftp-server, pour NetBSD elle ressemble à ceci :

Subsystem      sftp    /usr/libexec/sftp-server

On constate que le serveur sftp est un programme externe. Nous allons le remplacer par le sous-système sftp de sshd :

Subsystem       sftp    internal-sftp

J'ai donc remplacé /usr/libexec/sftp-server par internal-sftp. Allons ensuite à la fin du fichier, et ajoutons les directives suivantes :

Match Group wwwusers
        ChrootDirectory %h
        ForceCommand internal-sftp
        AllowTcpForwarding no
        X11Forwarding no

Cela signifie que pour les utilisateurs du groupe wwwusers, je les emprisonne dans leur répertoire home, je les oblige à utiliser le sftp interne, et je les empêche d'utiliser les différentes techniques de forwarding habituellement à disposition avec sshd. j'aurais pu les chrooter ailleurs, d'autres sites indiquent par exemple /chroot/%u, où %u désigne le nom de l'utilisateur. Une fois ces modifications effectuées, il ne reste qu'à redémarrer le serveur ssh et à créer le groupe et les utilisateurs.

Petit aparté concernant NetBSD 5.01 : j'ai remarqué un bug sur cette version, qui doit aussi être présent dans la 5.0; il ne faut surtout rien ajouter au fichier de configuration /etc/ssh/sshd_config après cette directive, pas même un commentaire ! Si cela venait à arriver, la directive que nous venons d'ajouter serait tout simplement ignorée.

Créons le groupe :

root@vhost:~ #groupadd wwwusers

Créons ensuite un utilisateur nommé test :

root@vhost:~ #useradd -m -g wwwusers -s /sbin/nologin test

Attribuons un mot de passe à cet utilisateur :

root@vhost:~ #passwd test
Changing password for test.
New Password:
Retype New Password:

(le mot de passe est tapé en aveugle, bien entendu). Ensuite, assurons-nous que le répertoire home de l'utilisateur appartient non pas à l'utilisateur mais à root, avec des permissions en 755. Si ce n'est pas le cas, on y remédie de cette manière :

root@vhost:~ #chown root:wheel /home/test
root@vhost:~ #chmod 755 /home/test

On notera que pour les OS Linux, on indique root:root par rapport à NetBSD qui n'a pas de groupe root mais un groupe wheel. A ne pas oublier aussi, seul /home/test appartient à root, pas les fichiers et répertoires à l'intérieur (i.e. pas de chmod/chown -R)

Depuis une autre machine, vérifions que nous pouvons nous connecter en sftp :

sftp test@vhost
Connecting to vhost...
Password:
sftp> ls
sftp> pwd
Remote working directory: /

Ici, on remarque que je me suis déjà connecté à cette machine avant, puisqu'on ne me réclame pas d'accepter de clé. On remarque aussi qu'on est directement dans le répertoire / et qu'il n'y a rien, la commande pwd indique / et pas /home/test. Si on crée dans ce répertoire un deuxième /home/test, sftp nous y emmènera directement dedans. De plus, on note qu'on ne peut pas créer ou ajouter de répertoire/fichier (normal, le répertoire appartient à root). Créons donc, sur le serveur, le second home de l'utilisateur :

root@vhost:~ #cd /home/test
root@vhost:/home/test # mkdir -p home/test
root@vhost:/home/test # chown -R test:wwwusers home
root@vhost:/home/test # chmod 755 home

Reconnectons-nous à notre serveur sftp :

sftp test@vhost
Connecting to vhost...
Password:
sftp> ls
sftp> pwd
Remote working directory: /home/test/

Je peux maintenant créer des répertoires, envoyer des fichiers, en rapatrier d'autres. Mission accomplie !

5 mar. 2008

Forcer openssh à ouvrir un terminal

Lire la suite...

Ces jours-ci, j'en apprend des trucs marrants !

L'autre jour, je voulais faire la feignasse : plutôt que de me connecter en ssh, devenir root puis taper une commande (un bête mkdir je crois), et ce sur 5-6 serveurs, je me suis demandé si je ne pouvais pas faire tout ça en une fois, au moins disons une commande par bécane, quitte à juste taper les mots de passe ensuite. Et bien c'est possible !

D'abord, on regarde la page de manuel de ssh, et on voit qu'on peut donner une commande en argument pour juste exécuter cette commande :

nils@darkmoon:~ $ssh www.anotherhomepage.org /bin/uname
nils@www.anotherhomepage.org's password: 
Linux

Ensuite on se dit qu'on rajouterait bien des arguments à notre commande, donc on rajoute des guillemets :

nils@darkmoon:~ $ssh www.anotherhomepage.org "/bin/uname -sp"
nils@www.anotherhomepage.org's password: 
Linux i686

Pour s'amuser, disons qu'on veut faire un truc en tant que root. On peut, si on ne dispose pas de sudo, utiliser "su -c" pour ne taper qu'une commande en tant que root, sous réserve de connaître le mot de passe. Mais si on le fait, on se heurte à un message d'erreur :

nils@darkmoon:~ $ssh www.anotherhomepage.org "su -c whoami"
nils@www.anotherhomepage.org's password: 
standard in must be a tty

Et là, c'est le drame... comment ouvre-t-on un tty? Un retour dans la page de manuel (merci Stéphane !) nous apprend que l'option "-t" force ssh à ouvrir un tty. Allez, on recommence :

nils@darkmoon:~ $ssh -t www.anotherhomepage.org "su -c whoami"
nils@www.anotherhomepage.org's password: 
Password: 
root
Connection to www.anotherhomepage.org closed.

On remarquera que cette fois-ci, on me demande 2 mots de passe : le mot de passe de nils (utilisateur implicite du fait que je suis connecté en tant que nils sur darkmoon), et le mot de passe de root. Le tty est ensuite refermé avec le ssh.

On pourrait bien entendu se passer de taper les mots de passe en utilisant une authentification par clés pour ssh et sudo pour les commandes qui le nécessitent. Ensuite, si on désire faire ceci sur plusieurs machines d'affilée, rien n'empêche d'imbriquer tout ça dans une boucle for. Si la commande lancée après le "su -c" nécessite des arguments, alors on peut utiliser les guillemets simples :

nils@darkmoon:~ $ssh -t www.anotherhomepage.org "su -c 'whoami --help'"
nils@www.anotherhomepage.org's password: 
Password: 
Usage: whoami [OPTION]...
Print the user name associated with the current effective user ID.
Same as id -un.

      --help     display this help and exit
      --version  output version information and exit

Report bugs to <bug-coreutils@gnu.org>.
Connection to www.anotherhomepage.org closed.

Propulsé par Dotclear