Utilisation De SSH
SSH est un outils qui permet d’accéder a un shell distant de façon sécurisé mais pas que.
Installation du serveur
apt install openssh-server
Les fichiers de configuration pour le mode client et serveur sont disponible dans /etc/ssh/
.
La configuration par défaut du serveur fait que le service est en écoute sur le port 22.
Connexion
Selon le moyen d’accès à la machine distante.
ssh user@ip
ssh user@hostname
ssh user@ma.machine.distante
On peut également lancer des applications en mode graphique… si on dispose d’un mode graphique sur le poste client et sur le poste serveur.
L’interface du serveur sera visible sur le post client. Biensur toute les action réalisé sur l’interface, le seront sur le post serveur.
ssh -X user@hostname
C’est l’option -X
qui permet cela.
Configuration client
Dans le répertoire ~/.ssh
on peu creer un fichier de configuration du nom de config
.
Ce fichier va surcharger la configuration par défaut du client présente dans /etc/ssh/ssh_config
.
Définir une configuration pour un host
Dans le fichier ~/.ssh/config
:
host serveur1
hostname 192.168.20.2 # au choix: ip, fqdn,
user mon_user
port 22
compression yes
IdentityFile ~/.ssh/id_ed25519
Maintenir une connexion vers un host pour accélérer les connexions suivante
Dans le fichier ~/.ssh/config
on va ajouter les lignes suivantes :
host *
# Gestion automatique des sessions
ControlMaster auto
# stockage des sessions : Le répertoire qui stockera le 'bus' de données
ControlPath ~/.ssh/mux/%r@%h:%p
# Persitance de session 10 minutes
ControlPersist 10m
En terme de sécurité, cette fonction peu être dangereuse. En effet, il n’est plus necessaire d’entrer sa clef pour se connecter à un bus ouvert…
Utiliser un host comme proxy
On veut se connecter à une machine serveur 2.
- serveur2 n’est pas accessible depuis internet.
- La machine serveur1 est sur le même réseau et peut voir seveur2.
- On va donc utiliser serveur1 pour accéder à serveur2.
La configuration est la suivante :
host serveur2
hostname 192.168.20.6 # au choix: ip, fqdn,
user mon_user
port 22
compression yes
IdentityFile ~/.ssh/id_ed25519
ProxyJump serveur1 # avec cette commande, on précise la machine via laquel on se connecte.
Execution distante
Execution d’un script local sur une machine distante
Le script est disponible sur la machine local dans le ~/script.sh
.
ssh login@machine2 bash < ~/script.sh
Execution d’un script distant sur une machine distante
Le script est disponible sur la machine distance dans le ~/script.sh
.
ssh login@machine2 ~/script.sh
Tunnel ssh
Tunnel Local
Nous souhaitons accéder au port d’une cible
mais nous n’avons pas un accès direct à son réseau.
En revanche, nous avons accès à une machine qui a accès au deux réseau : le pont
.
Nous allons demander au pont
de devenir un proxy pour l’accès au port spécifique de la cible
.
La commande suivante, est à réaliser sur la machine local
.
ssh -NL <port local>:<machine cible>:<port machine cible> user@pont
Le port de la machine local
sera directement relié au port de la cible
via la connexion ssh au pont
.
Donc si nous avons en cible un serveur web (port 80, ip du point de vue du pont 192.168.0.12), un pont accessible
via ssh (ça configuration est dispo dans un fichier ~/.ssh/config
) et nous choisissons le port local 8080,
nous pouvons réaliser un tunnel qui liera le port local 8080 au port de la cible 80 avec la commande suivante :
ssh -NL 8080:192.168.0.12:80 user@pont
Ensuite avec un navigateur, on réalise une connexion sur http://localhost:8080
et nous aurons accès au serveur cible.
Tunnel Distant
La machine à laquelle on veut accéder est placé derrière une box qui fait du NAT.
Cette machine sera le serveur
.
Nous n’avons pas accès à l’interface de la box. Ce qui fait que l’on ne peut pas faire de redirection de port.
Nous avons besoin d’une machine qui sera à la fois accessible depuis le serveur
et le client
.
Cette machine sera le pont
.
Nous allons faire un tunnel ssh entre le serveur
et le pont
.
Le tunnel est initié sur le serveur
avec la commande :
ssh -NR <port pont>:<ip serveur : localhost>:<port serveur> user@pont
par exemple
ssh -NR 8022:localhost:22 user@pont
Donc, ici, nous avons :
- -N, pour une session non interactive
- -R, pour faire un tunnel qui déporte un port local sur une machine distante.
Cette commande va ouvrir un port en écoute sur le pont et redirigé dans un tunnel ssh vers le port du serveur.
Le port ainsi ouvert n’est disponible que sur l’interface 127.0.0.1
donc uniquement en local sur le pont.
Donc il faut se connecter via ssh au pont pour accéder au port.
Cette particularité est du a une option du serveur ssh du pont.
L’option GatewayPorts
est à no
par défaut.
Si on souhaite que le pont devienne un veritable proxy, il faut passer l’option à yes
et le port sera attaché à l’interface 0.0.0.0
.
Ainsi, le port sera exposé à l’exterieur de la machine et accessible sans avoir besoin de posséder un accès au pont.
Contournement
NAT
On crée un tunnel ssh distant depuis la machine serveur
avec la commande :
ssh -NR <port pont>:<ip serveur : localhost>:<port serveur> user@pont
Comme dans l’exemple donnée dans la partie tunnel ssh distant
.
Cette commande positionné sur la machine pont
un port qui permettra de remonter a travers le NAT jusqu’a la machine serveur
.
On peut utiliser autossh
pour que la connexion soit maintenu et reconstruite.
Parefeu
On a une connexion “bridé” par un proxy http, on peu placer sshd sur le port 80/443 du serveur afin que le flux ne soit pas filtré. Lors de la connexion, on précise que l’on passe par un proxy http.
Si on héberge un serveur web, sslh permet de démultiplexer les flux reçus et de l’orienter sur le bon service/port.
Nous avons le schèma suivant:
+------+
|Client|
+---+--+
|
|
v
+--+--+
|Proxy|
|web | +---------+ +-----------+
+--+--+ +-------->+Port 2443+--------->+Serveur web|
| | +---------+ +-----------+
v |
+---+----+ +--------+ +--+-+
|Internet+-------->+port 443+---->+SSLH|
+--------+ |HTTPS | +--+-+
+--------+ |
| +-------+ +----+
+-------->+Port 22+------------>+SSHD|
+-------+ +----+
Il faut pensé à préciser dans la configuration du client les paremetre du proxy.
Sécurisation
Ressource
Connexion par clef
On génère une clef avec la commande suivante :
ssh-keygen
Ce qui va généré par défaut un couple de clefs : id_dsa
la clef privé et id_dsa.pub
la clef publique.
La commande suivante, sert à l’export la clef publique sur une machine distance afin de réaliser à l’avenir une connexion par la clef et plus par mot de passe.
ssh-copy-id user@host
On vous demandera alors le mot de passe lié au login et la clef publique sera copié.
La clef publique est inséré dans le fichier ~/.ssh/authorized_keys
à la suite de celle déjà présente.
Point important :
- Il ne faut jamais partager sa clef privé avec qui que ce soit. La personne qui aurait votre clef, si elle n’est pas protegé par un mot de passe, pourrait usurper vos accès sur les machines où la clef publique est déployé.
- Si possible on protège sa clef privé avec un mot de passe (ssh-agent est un démon qui gère les mots de passe de clef de façon à ne pas les taper 50 fois par session)
Changer le port d’écoute par défaut
ça ne change rien, si l’attaquant prend sont temps pour ses tests, il saura déterminer a quoi sert un port ouvert mais ça aura le mérite de limiter les attaques configuré sur port par défaut. Le port 22 étant très solicité sur le net…
dans le fichier /etc/ssh/sshd_config
, on trouve la ligne #Port 22
qu’il faut décommenter et changer.
On redémarre ensuite le service avec la comande suivante :
systemctl restart sshd
Il faut savoir qu’en redémarrant le service, la connexion en cour ne sera pas interromppu.
Il ne faut pas la couper avant d’avoir tenter une connexion avec la nouvelle configuration… ce serait dommage de se retrouver à la porte de son serveur.
fail2ban
Fail2ban est un outil qui va scruter les logs d’un service afin de detecter les tentatives de connection infructueuse. Souvent elle sont le signe d’attaque par force brute (Brute force) ou l’attaquant tente de se connecter a un service et essayant soit toutes les permutations possible, soit une liste prédéfini de login et de mot de passe.
apt install fail2ban
Plus d’information sur le wiki ubuntu-fr.
sshguard
C’est une alternative a fail2ban que je ne connais pas encore mais qui a le merite d’être légère et avoir un bon retour de la communauté. Le projet est activement maintenu. Quoi qu’il en soit je n’ai aucun sousi avec fail2ban… Comme fail2ban l’outil est en mesure de protéger plusieurs protocol différent. il n’est pas limité à ssh.
Le fichier : authorized_key
La documentation sur ce fichier est disponible dans le man.
man authorized_keys
Le fichier est présent dans le répertoire $HOME/.ssh/
.
Le fichier contient la liste des clefs public autorisé à se connecter au compte.
Une entrée prend une ligne et est de la forme :
OPTIONS ssh-ed25519 sziuqfhligubiusfgbqlirgqer3gb1q3e51bh3etbetb!qetbq# ma_clef@mon_pc
Le champ option n’est pas initialisé lorsque l’on déploie une clef vie l’outils de déploiement ssh-copy-id
.
On va placer dans ce fichier certain paramètre limitant l’utilisation du compte.
Ces paramètre sont séparé par des ,
.
La liste des options est dans le man.
Exemple
On peu construire un shell capable de limiter à des actions précises.
Par exemple, un script qui limite l’accès à l’utilisation de scp
:
#!/bin/bash
if [[ \"$SSH_ORIGINAL_COMMAND\" =~ ^scp.? ]]
then
$SSH_ORIGINAL_COMMAND
exit 0
else
echo Access Denied
exit 1
fi
Ce script doit être appelé lors de la connexion. C’est ce que l’instruction command=
placé dans le champ ‘‘option’’ doit nous permetre.
Il n’y a pas de limitation concernant le langage, un script python peut aussi servir de validateur.
#!/usr/bin/env python3
from os import environ
import logging
from logging.handlers import TimedRotatingFileHandler
#from logging.handlers import RotatingFileHandler
log = logging.getLogger()
log.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(asctime)s :: %(module)s :: %(levelname)s :: %(message)s')
file_handler = TimedRotatingFileHandler(environ['HOME']+'/.ssh/limitation.log',
when='D',
interval=1,
backupCount=7)
#file_handler = RotatingFileHandler(environ['HOME']+'/.ssh/limitation.log', 'a', 1000000, 1)
file_handler.setFormatter(formatter)
log.addHandler(file_handler)
if 'SSH_ORIGINAL_COMMAND' in environ.keys():
log.debug(environ["SSH_ORIGINAL_COMMAND"])
import subprocess
cmd = environ['SSH_ORIGINAL_COMMAND']
cmds = cmd.split(" ")
if 'scp' in cmd or 'tar' in cmd or 'mkdir' in cmd or 'rm' in cmd :
if 'scp' in cmds[0]:
log.debug("Commande de transfert identifié")
if 'tar' in cmds[0]:
log.debug("Commande d'archivage identifié")
if 'mkdir' in cmds[0]:
log.debug("Commande de création de répertoire identifié")
if 'rm' in cmds[0]:
log.debug("Commande de suppression identifié")
subprocess.run(cmds)
exit(0)
else:
log.error("La commande ne contient pas le bon mot clef.")
exit(1)
else:
log.error("L'env ne contient pas la variable 'SSH_ORIGINAL_COMMAND'.")
exit(1)
Debug
Les log du serveur sshd sont disponible dans /var/log/auth.log
on peut également voir des traces sur /var/log/syslog
.
Coté client l’option -vvvvv
passe les log au niveau debug ce qui donnera un déroulé des étapes de négociation d’une connexion ssh.
Droit sur les répertoires
ssh refuse de fonctionner si les droits sur le répertoire parent du répertoire .ssh
donne la fonction o+w soit l’écriture au autres ;).
Donc le plus simple reste d’être le seul a avoir un accès en lecture/écriture sur ses dossiers perso.
nithir [drwx------]
└── .ssh [drwx------]
On peut executer dans l’ordre (source) :
chmod go-w ~/
chmod 700 ~/.ssh
chmod 600 ~/.ssh/*
chmod 644 ~/.ssh/*.pub