création d'un serveur web sur FreeBSD en utilisant des jails
Dans cet article je vais détailler comment créer un serveur web comprenant nginx, php et mariadb.
Pour plus de sécurité je vais utiliser des prisons, une pour emprisonner php et nginx, une autre pour mariadb.
création du réseau pour les jails
Pour plus de sécurité, je crée un réseau spécial pour les jails avec 2 IPv4 : 192.168.1.101 pour webjail et 192.168.1.102 pour sqljail :
| 1
2
3
 | doas sysrc cloned_interfaces="lo1"
doas sysrc ipv4_addrs_lo1="192.168.1.101-102/31"
doas service netif restart
 | 
 
le firewall
Je vais utiliser PF 
avec ces règles écrites dans /etc/pf.conf :
|  1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
 | tcp_services_in = "{ ssh, http, https }" # mes services TCP en entrée
tcp_services_out = "{ http, https }" # mes services TCP en sortie
udp_services_out = "{ domain }" # mes services UDP en sortie
table <bruteforce> persist # la table contenant les floodeurs / bruteforceurs bloqués
# pas de restrictions sur lo0
set skip on lo0
# normalisation des paquets
scrub in all
scrub in all fragment reassemble no-df max-mss 1440
nat on em0 from lo1:network to any -> (em0) # nat pour les jails
rdr on em0 proto tcp from any to any port http -> 192.168.1.101 port http # redirection http sur webjail
rdr on em0 proto tcp from any to any port https -> 192.168.1.101 port https # redirection https sur webjail
# anti spoofing
antispoof for { em0, lo1 }
block in all # bloque tout en entrée par défaut
block out all # bloque tout en sortie par défaut
# bloque les floodeurs bruteforceurs / qui sont dans la table bruteforce
block quick from <bruteforce>
# accepte en sortie tcp_services_out et enregistre l'état
pass out quick on em0 proto tcp from em0:network to any port $tcp_services_out flags S/SA keep state
# accepte en sortie udp_services_out et enregistre l'état
pass out quick on em0 proto udp from em0:network to any port $udp_services_out keep state
# accepte en entrée tcp_services_in ou bloque les floodeurs / bruteforceurs
pass in quick on em0 proto tcp from any to em0:network port $tcp_services_in flags S/SA synproxy state \
    (max-src-conn 100, max-src-conn-rate 15/5, overload <bruteforce> flush global)
pass out quick on lo1 proto tcp from lo1:network to any port mysql keep state
pass in quick on lo1 proto tcp from any to lo1:network port mysql flags S/SA synproxy state
# accepte tout ICMP en entrée et en sortie
pass inet proto icmp from em0:network to any keep state
pass inet proto icmp from any to em0 keep state
 | 
 
| 1
 | doas sysrc pf_enable="YES" && doas sysrc pflog_enable="YES"
 | 
 
Je reboot pour appliquer ces règles :
création des prisons
Pour créer les prisons je vais utiliser l'outil ezjail  :
| 1
 | doas pkg install ezjail
 | 
 
ezjail utilise le protocol FTP par défaut. Le protocole FTP est relou à protéger avec un firewall.
Je paramètre donc ezjail pour qu'il utilise le protocole HTTPS à la place et ainsi me faciliter la vie :
| 1
 | doas nano /usr/local/etc/ezjail.conf
 | 
 
Je modidie la variable ezjail_ftphost pour avoir :
| 1
 | ezjail_ftphost=https://ftp.freebsd.org
 | 
 
Pour séparer le réseau du serveur web avec le reste je vais créer une nouvelle interface et je lui donne 2 ipv4 :
Je démarre ezjail et précise qu'il doit démarrer au boot :
| 1
2
 | doas sysrc ezjail_enable="YES"
doas service ezjail start
 | 
 
J'installe l'environnement ezjail, la "basejail" :
| 1
 | doas ezjail-admin install
 | 
 
prison pour nginx et php
Je crée la prison qui va accueillir les services nginx et php, cette jail a comme IP 192.168.1.101 :
| 1
 | doas ezjail-admin create webjail 'lo1|192.168.1.101'
 | 
 
Pour pouvoir communiquer sur internet depuis la prison webjail je copie le fichier resolv.conf de l'hôte dans la prison :
| 1
 | doas cp /etc/resolv.conf /usr/jails/webjail/etc/
 | 
 
Je démarre webjail :
| 1
 | doas ezjail-admin start webjail
 | 
 
prison pour mariadb
Je crée la prison qui va accueillir le service mariadb, cette jail a comme IP 192.168.1.102 :
| 1
 | doas ezjail-admin create sqljail 'lo1|192.168.1.102'
 | 
 
Pour pouvoir communiquer sur internet depuis la prison sqljail je copie le fichier resolv.conf de l'hôte dans la prison :
| 1
 | doas cp /etc/resolv.conf /usr/jails/sqljail/etc/
 | 
 
Je démarre sqljail :
| 1
 | doas ezjail-admin start sqljail
 | 
 
installation de nginx && php dans webjail
Je me connece à la console de webjail :
| 1
 | doas ezjail-admin console webjail
 | 
 
J'installe la dernière version des services nginx et php :
| 1
 | pkg install nginx php83 php83-mysqli mariadb106-client
 | 
 
Je démarre nginx et le fait démarrer au boot :
| 1
2
 | sysrc nginx_enable="YES"
service nginx start
 | 
 
installation de mariadb dans sqljail
Je me connece à la console de sqljail depuis l'hôte :
| 1
 | doas ezjail-admin console sqljail
 | 
 
J'installe la dernière version du service sql mariadb :
| 1
 | pkg install mariadb106-server
 | 
 
Je démarre mariadb et le fait démarrer au boot :
| 1
2
 | sysrc mysql_enable=YES
service mysql-server start
 | 
 
Je run le script d'installation :
| 1
 | mysql_secure_installation
 | 
 
Pour pouvoir tester la connexion, je crée une base de données avec son user :
| 1
2
3
4
 | CREATE DATABASE testdb;
GRANT ALL ON testdb.* TO test@'%' IDENTIFIED BY 'testpass';
FLUSH PRIVILEGES;
EXIT;
 | 
 
test des services
Pour commencer je reboot le serveur :
Ensuite, depuis un navigateur internet, je me connecte sur le serveur qui chez moi a pour IPv4 : 192.168.1.32
Après, pour tester le service sql, je me connecte à la console de webjail :
| 1
 | doas ezjail-admin console webjail
 | 
 
Et depuis webjail je me connecte au service sql sur sqljail :
| 1
 | mysql -u test -h 192.168.1.102 -p
 | 
 
Pour finir, je test le firewall. Depuis mon poste de travail j'utilise nmap pour tester la config du firewall sur le serveur :
w00t !