Sécuriser les alentours
-----------------------

Avant de commencer votre travail, il est important de mettre en place
un minimum de sécurités pour anticiper les menaces potentielles.

### Identifier les menaces

Il y a deux grandes catégories de menaces lorsque l'on rend visible
une machine sur Internet :

- les scans automatiques ;
- les individus/organisations.

Dès qu'une machine est accessible sur Internet, celle-ci est scannée
par des robots de nombreuses entités qui récoltent des informations ou
même tentent des attaques classiques.

Voici des exemples :

- [Shodan](https://www.safetydetectives.com/blog/what-is-shodan-and-how-to-use-it-most-effectively/),
- [Wordpress/phpMyAdmin et autres scanner vulnérabilités](https://cirt.net/Nikto2),
- [installation de site Wordpress avant même que l'administrateur ait connaissance de l'adresse](https://portswigger.net/daily-swig/wordpress-sites-getting-hacked-within-seconds-of-tls-certificates-being-issued).

Généralement, notre machine ne sera pas ciblée directement par un individu ou
une entité, à moins d'avoir fait l'objet d'un scan rapportant des brèches
intéressantes (version de logiciel vulnérable, OS déprécié, port connu ouvert,
mots de passe par défaut, ...). Il est donc très important d'apparaître le plus
neutre possible sur les scans automatiques, en exposant le strict minimum
d'information et de services.

![Capture d'écran des informations relevées par Shodan pour nemunai.re](shodan-nemunai.re.png)

::::: {.warning}

Le site Shodan.io est une source d'information pertinente, mais il ne faut pas
se contenter de ces infections qui ne sont pas exhaustives. D'autres robots
peuvent récolter et tester bien plus en profondeur chaque service/port exposé.

:::::


### Réduire la surface d'attaque

Pour garantir qu'aucun service n'échappe à notre vigilance, nous allons mettre
en place un pare-feu.

Sur un serveur Linux fraîchement installé, aucune règle de filtrage n'est
appliquée. (Sur certaines version Desktop de distribution, un pare-feu est
configuré pour n'accepter aucune connexion entrante).

Avant de commencer notre filtrage, regardons quels programmes sont en écoute
sur notre machine :

```
ss --listen --numeric --processes --tcp
ss --listen --numeric --processes --udp
```

La commande `ss` affiche la liste des programmes qui écoutent (ont `bind(2)`
puis `listen(2)`). Chaque ligne affichée est une porte d'entrée pour de
potentielles vulnérabilités, on s'assure donc que l'on a une confiance absolue
envers chaque programme listé.

::::: {.exercice}

Si à ce stade vous avez plus qu'un serveur SSH, trouvez le fichier qui démarre
les autres daemons pour faire en sorte qu'ils ne soient pas lancés inutilement

:::::

### Atténuer les menaces

Avec `ss`, nous sommes en mesure de savoir précisément quels ports nous avons
besoin d'ouvrir sur notre machine. Cependant, nous faisons face à 2 problèmes :

- on ne peut pas limiter facilement avec `bind(2)` les IP auxquelles on
  voudrait autoriser l'accès du service (par exemple : tout Internet n'a pas
  besoin d'accèder à notre serveur SSH, on en a seulement besoin pour
  administrer notre serveur, on arrivera sans doute d'une IP connue d'avance),
- et si d'autres programmes se mettent à écouter sur des ports pendant le cycle
  de vie d'un autre programme ?

Pour réduire les risques, nous devons mettre en place des règles de pare-feu.

Le pare-feu est un élément du noyau qui vient s'interposer dans les flux réseau
pour individuellement prendre une décision sur chaque paquet ou éventuellement
l'altérer. Il va par exemple être sollicité juste avant de transmettre à
l'espace utilisateur un paquet qui arrive d'une interface réseau (on parle de
paquet entrant).

Nous pourrions donc aisément filtrer le port 22 (utilisé par le serveur SSH)
pour limiter à certaines IP le droit d'accéder à ce port.

En fait, on utilise un pare-feu surtout en liste blanche. C'est-à-dire que l'on
interdit de base tout paquet entrant, SAUF ceux qui nous intéressent. On est
alors assuré que si un programme se met à écouter sur un port en dehors de
notre surveillance, il ne sera pas joignable car les paquets qui lui seront
destinés seront bloqués par le pare-feu du système.


### Mise en place du pare-feu

Le pare-feu du noyau Linux est `netfilter`. On interagit avec lui avec des
appels systèmes, et de nombreux logiciels permettent de gérer plus ou moins
facilement les règles.

Il y a 2 implémentations de référence :

- `iptables` : utilisé depuis 1998, il est aujourd'hui présent et utilisé par
  la majorité des administrateurs système.
- `nftables` : stable depuis 2021, il tend à remplacer `iptables`, aux
  fonctionnalités vieillissantes (séparation IPv4/IPv6, vitesse de traitement,
  ...).

Quelque soit la distribution, vous pourrez installer le paquet au nom de
l'implémentation que vous souhaitez utiliser. Dans la suite, nous allons
utiliser `nftables`, mais libre à vous d'utiliser l'implémentation de votre
choix.

Pour afficher la liste des règles actuellement appliquées, on utilise les
commandes suivantes :

```
nft list ruleset
```

ou avec `iptables` :

```
iptables -t $TABLE --list
ip6tables -t $TABLE --list
```

On remarque qu'avec `iptables` on ne peut pas avoir accès à toutes les règles, on
ne peut les afficher que par TABLE et selon la version IPv4 ou IPv6. La table
`filter` est la table par défaut et celle que l'on uti lisera le plus, mais il
y a aussi `nat`, `mangle`, ...\

::::: {.warning}

Faites attention lorsque vous changez les règles de pare-feu à distance, car
votre connexion passe par ce pare-feu. Si vous bloquez toutes les connexions
entrantes avant d'autoriser votre connexion SSH, vous vous retrouverez à la porte.

Dans le contexte de ce TP, vous avez accès à la console dans votre hyperviseur
pour remédier à la situation, mais parfois vous pourriez n'avoir comme solution
que le redémarrage (les règles ne sont pas persistantes), voire le déplacement
dans le datacenter, si vos règles sont chargées automatiquement au démarrage !

:::::

Avant d'interdire toutes les connexions entrantes, nous allons donc autoriser
notre connexion SSH ! On commence par créer une table :

```
nft add table inet <mytable>
```

Le paramètre `inet` indique que l'on souhaite créer une table qui agira sur le
trafic IPv4 et IPv6 à la fois ([voir les autres types de table
supportés](https://wiki.nftables.org/wiki-nftables/index.php/Nftables_families)).

Au sein de notre table, nous allons maintenant créer une chaîne de règle. C'est
ici que l'on va indiquer à quel `hook` du noyau on souhaite s'accrocher :
plutôt les paquets entrant, sortant, traversant, ...

```
nft add chain inet <mytable> <mychain> '{type filter hook input priority 0; }'
```

On va donc créer ici une chaîne nommée `mychain`, agissant en filtrage
(`filter`) sur tous les paquets entrant (`input`). On crée l'équivalent ici de
la chaîne `INPUT` de la table `filter` d'`iptables` et `ip6tables` mélangés.
Cela permet d'indiquer au noyau à quel niveau on souhaite appliquer ces
règles.

Ajoutons justement notre première règle pour autoriser les connections
SSH :

```
nft add rule inet <mytable> <mychain> tcp dport 22 accept
```

Au sein d'un chaîne, sauf rares exceptions, les règles sont évaluées
séquentiellement et la première décision qui valide les conditions est retenue.
Dans notre exemple ci-dessus, la décision est d'accepter (`accept`) le paquet :
si aucune règle n'existe avant, validant aussi les conditions, cette règle sera
la dernière d'un paquet TCP à destination du port 22, il sera ensuite délivré à
l'espace utilisateur.

Vous devriez prendre connaissance des [conditions possibles sur lesquelles
filtrer les
paquets](https://wiki.nftables.org/wiki-nftables/index.php/Quick_reference-nftables_in_10_minutes#Matches)
et les [décisions possibles pour un
paquet](https://wiki.nftables.org/wiki-nftables/index.php/Quick_reference-nftables_in_10_minutes#Statements).

Enfin, changeons la politique par défaut pour les paquets entrant pour lesquels
aucune décision n'a été prise, qui est d'accepter tous les paquets, vers la
politique `drop`, qui envoie vers un trou noir les paquets qui n'auront pas
été acceptés dans la chaîne.

```
nft add chain inet <mytable> <mychain> '{ policy drop; }'
```

Eh voilà ! vous êtes en sécurité.

::::: {.exercice}

Faites en sorte maintenant de limiter les connexions SSH à votre IP ou à la
plage d'IP susceptible de se connecter, plutôt que d'accepter toutes les IP.

:::::
