Firewall.md 27 KB

Le pare-feux

Il nous faut installer un pare-feux sur notre raspi pour éviter les intrusions.

Nous allons limiter les machines susceptibles de se connecter à celles de notre réseau local, et également limiter les ports accessibles sur notre réseau.

Nous allons utiliser NFTables et Firewalld.

Note: je n'ai jamais utilisé ces programmes. Ce sera l'occasion de les découvrir!

Installation de nftables

pi@piras:~ $ sudo apt install nftables

Test

pi@piras:~ $ sudo nft list ruleset ip
table ip filter {
    chain INPUT {
        type filter hook input priority 0; policy accept;
    }

    chain FORWARD {
        type filter hook forward priority 0; policy accept;
    }

    chain OUTPUT {
        type filter hook output priority 0; policy accept;
    }
}
pi@piras:~ $ 

ça marche ...

Installation de Firewalld

pi@piras:~ $ sudo apt install firewalld

Test du fonctionnement:

pi@piras:~ $ sudo systemctl status firewalld
● firewalld.service - firewalld - dynamic firewall daemon
Loaded: loaded (/lib/systemd/system/firewalld.service; enabled; vendor preset: enabled)
Active: active (running) since Sat 2020-12-12 18:28:00 CET; 19min ago
    Docs: man:firewalld(1)
Main PID: 3552 (firewalld)
CGroup: /system.slice/firewalld.service
        └─3552 /usr/bin/python3 /usr/sbin/firewalld --nofork --nopid

déc. 12 18:27:47 piras systemd[1]: Starting firewalld - dynamic firewall daemon...
déc. 12 18:28:00 piras systemd[1]: Started firewalld - dynamic firewall daemon.
pi@piras:~ $ sudo firewall-cmd --state
running
pi@piras:~ $ 

Tout marche.

Configuration de Firewalld

D'abord, il faut comprendre comment fonctionne Firewalld. Je me suis basé sur les sites suivants:

La documentation de Fedora est la plus compréhensible.

La notion de zones

Firewalld défnit 9 zones qui sont en fait des règles de pare-feux par défaut. Une zone va par exemple bloquer toute entrée sauf SSH, une autre permettre l'accès en HTTP et HTTPS. Ces zones correspondent à des utilisations types, comme un serveur dans une DMZ, ou un serveur chez soi, un serveur public etc.

On peut imaginer une zone émail qui ne laisserait passer que les ports spécifiques à l'émail et DNS bien sûr.

Il est possible de créer des zones personnelles.

Un certain nombre de zones sont prédéfinies. Voyons leur contenu.

Les différentes zones

Les différentes zones sont:

  • trusted: non modifiable
  • home: modifiable
  • work: modifiable
  • internal: modifiable
  • dmz: modifiable
  • public: modifiable
  • external: modifiable
  • block: non modifiable
  • drop: non modifiable

Une très bonne présentation des zones est ici: it connect

Les fichiers de configuration

Ils ont situés à 2 endroits:

  • /usr/lib/firewalld/ : il ne faut pas toucher au contenu de ce répertoire
  • /etc/firewalld/: c'est là que nous mettrons notre configuration, en copiant les fichiers de /usr/lib/firewalld si besoin est.

Dans le répertoire /etc/firewalld, le fichier firewalld.conf permet de configurer la zone par défaut, ainsi que le backtend à ipfilter.

Tout à la fin du fichier de configuration, le FirewallBackend est mis à iptables. Comme nous utiliserons nftables, il faudra modifier cette option. Cela est explicite dans le fichier.

FirewallBackend=nftables

La zone par défaut est public: pas de confiance, mais possibilité d'ajuster au cas par cas les règles.

Quelques commandes

  • Démarrer Firewalld:$ sudo systemctl start firewalld
  • Stopper Fireawalld:$ sudo systemctl stop firewalld
  • Tester le fonctionnement de Firewalld:$ sudo firewall-cmd --state
  • Connaître les zones prédéfinies: $ sudo firewall-cmd --get-zones
  • Connaître la zone par défaut:$ sudo firewall-cmd --get-default-zone
  • Connaître la zone active:$ sudo firewall-cmd --get-active-zones

Exemples:

pi@piras:~ $ sudo firewall-cmd --state
running
pi@piras:~ $

Le service tourne.

pi@piras:~ $ sudo firewall-cmd --get-default-zone
public
pi@piras:~ $

La zone par défaut est: public

pi@piras:~ $ sudo firewall-cmd --get-zones
block dmz drop external home internal public trusted work
pi@piras:~ $

Les zones prédéfinies sont: block dmz drop external home internal public trusted work

Quelle est la zone active: aucune!

pi@piras:~ $ sudo firewall-cmd --get-active-zones
pi@piras:~ $

Nous pouvons vérifier la zone en fonctionnement et l'interface réseau qui y est attachée:

pi@piras:~ $ sudo firewall-cmd --list-all
public
target: default
icmp-block-inversion: no
interfaces: 
sources: 
services: dhcpv6-client ssh
ports: 
protocols: 
masquerade: no
forward-ports: 
source-ports: 
icmp-blocks: 
rich rules: 

pi@piras:~ $ 

Aucune interface n'est attachée. Les seuls services autorisé sont: dhcp et ssh.

Première étape de configuration

Nous allons utiliser les commandes en ligne de commande pour configurer Firewalld, mais il existe une GUI pour le faire graphiquement. Référez-vous aux liens que j'ai indiqués au-dessus.

  • Définition de la zone par défaut: (public)

    pi@piras:~ $ sudo firewall-cmd --set-default-zone=public
    Warning: ZONE_ALREADY_SET: public
    success
    pi@piras:~ $
    
  • Attribution de l'interface réseau à cette zone:

    pi@piras:~ $ sudo firewall-cmd --zone=public --change-interface=eth0
    success
    pi@piras:~ $
    

    Attention, ce changement n'est pas permanent! (voir ci-dessous)

  • Test:

    pi@piras:~ $ sudo firewall-cmd --list-all
    public (active)
    target: default
    icmp-block-inversion: no
    interfaces: eth0
    sources:
    services: dhcpv6-client ssh
    ports:
    protocols:
    masquerade: no
    forward-ports:
    source-ports:
    icmp-blocks:
    rich rules:
    
    pi@piras:~ $
    

Nous voyons que l'interface eth0 a bien été attribuée à la zone public.

Les services

Il est possible de configurer les serviecs accessibles (ou pas) attribués à la zone active.

Pour connaître les différents services disponibles, tapez la commande suivante:

pi@piras:~ $ sudo firewall-cmd --get-services
RH-Satellite-6 amanda-client amanda-k5-client amqp amqps apcupsd audit bacula bacula-client bgp bitcoin bitcoin-rpc bitcoin-testnet bitcoin-testnet-rpc ceph ceph-mon cfengine cockpit condor-collector ctdb dhcp dhcpv6 dhcpv6-client distcc dns docker-registry docker-swarm dropbox-lansync elasticsearch etcd-client etcd-server finger freeipa-ldap freeipa-ldaps freeipa-replication freeipa-trust ftp ganglia-client ganglia-master git gre high-availability http https imap imaps ipp ipp-client ipsec irc ircs iscsi-target isns jenkins kadmin kerberos kibana klogin kpasswd kprop kshell ldap ldaps libvirt libvirt-tls lightning-network llmnr managesieve matrix mdns minidlna mongodb mosh mountd mqtt mqtt-tls ms-wbt mssql murmur mysql nfs nfs3 nmea-0183 nrpe ntp nut openvpn ovirt-imageio ovirt-storageconsole ovirt-vmconsole plex pmcd pmproxy pmwebapi pmwebapis pop3 pop3s postgresql privoxy proxy-dhcp ptp pulseaudio puppetmaster quassel radius redis rpc-bind rsh rsyncd rtsp salt-master samba samba-client samba-dc sane sip sips slp smtp smtp-submission smtps snmp snmptrap spideroak-lansync squid ssh steam-streaming svdrp svn syncthing syncthing-gui synergy syslog syslog-tls telnet tftp tftp-client tinc tor-socks transmission-client upnp-client vdsm vnc-server wbem-http wbem-https wsman wsmans xdmcp xmpp-bosh xmpp-client xmpp-local xmpp-server zabbix-agent zabbix-server
pi@piras:~ $

Chaque détail des services est détaillé dans un fichier xml dans /usr/lib/firewalld.

Voyons quels services sont acuellemnt activés sur notre raspi:

pi@piras:~ $ ss -t -u -l -a
Netid          State           Recv-Q          Send-Q                     Local Address:Port                          Peer Address:Port           
udp            UNCONN          0               0                                0.0.0.0:55853                              0.0.0.0:*              
udp            UNCONN          0               0                              127.0.0.1:domain                             0.0.0.0:*              
udp            UNCONN          0               0                                0.0.0.0:bootpc                             0.0.0.0:*              
udp            UNCONN          0               0                                0.0.0.0:mdns                               0.0.0.0:*              
udp            UNCONN          0               0                                  [::1]:domain                                   *:*              
udp            UNCONN          0               0                                      *:59578                                    *:*              
udp            UNCONN          0               0                                      *:mdns                                     *:*              
tcp            LISTEN          0               511                            127.0.0.1:domain-s                           0.0.0.0:*              
tcp            LISTEN          0               511                            127.0.0.1:domain                             0.0.0.0:*              
tcp            LISTEN          0               128                              0.0.0.0:ssh                                0.0.0.0:*              
tcp            ESTAB           0               0                        192.168.111.170:ssh                        192.168.111.150:59092          
tcp            LISTEN          0               511                                [::1]:domain-s                              [::]:*              
tcp            LISTEN          0               511                                [::1]:domain                                [::]:*              
tcp            LISTEN          0               128                                 [::]:ssh                                   [::]:*              
pi@piras:~ $ 

Nous voyons notre connexion ssh établie entre mon desktop en ip 192.168.111.150 et piras 192.168.111.170.

Notre raspi écoute également le port 22 sur toutes les interfaces présentes.

Liste des ports en écoute (TCP):

pi@piras:~ $ ss -ltn
State              Recv-Q             Send-Q                           Local Address:Port                           Peer Address:Port             
LISTEN             0                  511                                  127.0.0.1:853                                 0.0.0.0:*                
LISTEN             0                  511                                  127.0.0.1:53                                  0.0.0.0:*                
LISTEN             0                  128                                    0.0.0.0:22                                  0.0.0.0:*                
LISTEN             0                  511                                      [::1]:853                                    [::]:*                
LISTEN             0                  511                                      [::1]:53                                     [::]:*                
LISTEN             0                  128                                       [::]:22                                     [::]:*                
pi@piras:~ $ 

les ports 22 (ssh) , 53 (dns) , 853 (dns) sont à l'écoute en IPV4 et IPV6.

Liste des ports en écoute (UDP):

pi@piras:~ $ ss -lun
State              Recv-Q             Send-Q                          Local Address:Port                            Peer Address:Port             
UNCONN             0                  0                                     0.0.0.0:55853                                0.0.0.0:*                
UNCONN             0                  0                                   127.0.0.1:53                                   0.0.0.0:*                
UNCONN             0                  0                                     0.0.0.0:68                                   0.0.0.0:*                
UNCONN             0                  0                                     0.0.0.0:5353                                 0.0.0.0:*                
UNCONN             0                  0                                       [::1]:53                                         *:*                
UNCONN             0                  0                                           *:59578                                      *:*                
UNCONN             0                  0                                           *:5353                                       *:*                
pi@piras:~ $ 

Etat des lieux

Vérifions le fonctionnement de Firewalld. Souvenez-vous qu'il était configuré pour fonctionner avec Iptables.

Vérifions les règles établies:

pi@piras:~ $ sudo iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination         
ACCEPT     all  --  anywhere             anywhere             ctstate RELATED,ESTABLISHED
ACCEPT     all  --  anywhere             anywhere            
INPUT_direct  all  --  anywhere             anywhere            
INPUT_ZONES_SOURCE  all  --  anywhere             anywhere            
INPUT_ZONES  all  --  anywhere             anywhere            
DROP       all  --  anywhere             anywhere             ctstate INVALID
REJECT     all  --  anywhere             anywhere             reject-with icmp-host-prohibited

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         
ACCEPT     all  --  anywhere             anywhere             ctstate RELATED,ESTABLISHED
ACCEPT     all  --  anywhere             anywhere            
FORWARD_direct  all  --  anywhere             anywhere            
FORWARD_IN_ZONES_SOURCE  all  --  anywhere             anywhere            
FORWARD_IN_ZONES  all  --  anywhere             anywhere            
FORWARD_OUT_ZONES_SOURCE  all  --  anywhere             anywhere            
FORWARD_OUT_ZONES  all  --  anywhere             anywhere            
DROP       all  --  anywhere             anywhere             ctstate INVALID
REJECT     all  --  anywhere             anywhere             reject-with icmp-host-prohibited

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         
OUTPUT_direct  all  --  anywhere             anywhere            

Chain INPUT_direct (1 references)
target     prot opt source               destination         

Chain INPUT_ZONES_SOURCE (1 references)
target     prot opt source               destination         

Chain INPUT_ZONES (1 references)
target     prot opt source               destination         
IN_public  all  --  anywhere             anywhere            [goto] 
IN_public  all  --  anywhere             anywhere            [goto] 

Chain FORWARD_direct (1 references)
target     prot opt source               destination         

Chain FORWARD_IN_ZONES_SOURCE (1 references)
target     prot opt source               destination         

Chain FORWARD_IN_ZONES (1 references)
target     prot opt source               destination         
FWDI_public  all  --  anywhere             anywhere            [goto] 
FWDI_public  all  --  anywhere             anywhere            [goto] 

Chain FORWARD_OUT_ZONES_SOURCE (1 references)
target     prot opt source               destination         

Chain FORWARD_OUT_ZONES (1 references)
target     prot opt source               destination         
FWDO_public  all  --  anywhere             anywhere            [goto] 
FWDO_public  all  --  anywhere             anywhere            [goto] 

Chain OUTPUT_direct (1 references)
target     prot opt source               destination         

Chain IN_public (2 references)
target     prot opt source               destination         
IN_public_log  all  --  anywhere             anywhere            
IN_public_deny  all  --  anywhere             anywhere            
IN_public_allow  all  --  anywhere             anywhere            
ACCEPT     icmp --  anywhere             anywhere            

Chain IN_public_log (1 references)
target     prot opt source               destination         

Chain IN_public_deny (1 references)
target     prot opt source               destination         

Chain IN_public_allow (1 references)
target     prot opt source               destination         
ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:ssh ctstate NEW,UNTRACKED

Chain FWDI_public (2 references)
target     prot opt source               destination         
FWDI_public_log  all  --  anywhere             anywhere            
FWDI_public_deny  all  --  anywhere             anywhere            
FWDI_public_allow  all  --  anywhere             anywhere            
ACCEPT     icmp --  anywhere             anywhere            

Chain FWDI_public_log (1 references)
target     prot opt source               destination         

Chain FWDI_public_deny (1 references)
target     prot opt source               destination         

Chain FWDI_public_allow (1 references)
target     prot opt source               destination         

Chain FWDO_public (2 references)
target     prot opt source               destination         
FWDO_public_log  all  --  anywhere             anywhere            
FWDO_public_deny  all  --  anywhere             anywhere            
FWDO_public_allow  all  --  anywhere             anywhere            

Chain FWDO_public_log (1 references)
target     prot opt source               destination         

Chain FWDO_public_deny (1 references)
target     prot opt source               destination         

Chain FWDO_public_allow (1 references)
target     prot opt source               destination         
pi@piras:~ $ 

Les règles Iptables ont bien été configurées par Firewalld.

Modifions le fichier de configuration pour l'utilisation de nftables (fichier /etc/firewalld/firewalld.conf, tout à la fin)

Et rebootons notre raspi.

  • Test de iptables: les tables doivent être vides maintenant.

    pi@piras:~ $ sudo iptables -L
    Chain INPUT (policy ACCEPT)
    target     prot opt source               destination
    
    Chain FORWARD (policy ACCEPT)
    target     prot opt source               destination
    
    Chain OUTPUT (policy ACCEPT)
    target     prot opt source               destination
    pi@piras:~ $
    
  • Test de nftables: les tables doivent être configurées.

    pi@piras:~ $ sudo nft list table filter
    table ip filter {
        chain INPUT {
            type filter hook input priority 0; policy accept;
        }
    
        chain FORWARD {
            type filter hook forward priority 0; policy accept;
        }
    
        chain OUTPUT {
            type filter hook output priority 0; policy accept;
        }
    }
    pi@piras:~ $ sudo firewall-cmd --list-all
    public
    target: default
    icmp-block-inversion: no
    interfaces:
    sources:
    services: dhcpv6-client ssh
    ports:
    protocols:
    masquerade: no
    forward-ports:
    source-ports:
    icmp-blocks:
    rich rules:
    
    pi@piras:~ $
    

Nous voyons que rien n'a été conservé, et que les tables nftables sont vides ... ça marchait bien avec iptables ... peut-être est-ce pour ça qu'ils ont configuré le backend à iptables?

Il va falloir investiguer ...

Bien: voilà la procédure à suivre:

  1. sudo firewall-cmd --permanent --zone=public --change-interface=eth0

    Permet de changer de façon permanente l'interface associée à la zone public.

    Test:
    pi@piras:~ $ sudo firewall-cmd --permanent --zone=public --change-interface=eth0
    success
    pi@piras:~ $ ls -l /etc/firewalld/
    ls: impossible d'ouvrir le répertoire '/etc/firewalld/': Permission non accordée
    pi@piras:~ $ sudo ls -l /etc/firewalld/
    total 28
    -rw-r--r-- 1 root root 2190 déc.  13 12:45 firewalld.conf
    drwxr-xr-x 2 root root 4096 févr.  1  2019 helpers
    drwxr-xr-x 2 root root 4096 févr.  1  2019 icmptypes
    drwxr-xr-x 2 root root 4096 févr.  1  2019 ipsets
    -rw-r--r-- 1 root root  272 févr.  1  2019 lockdown-whitelist.xml
    drwxr-xr-x 2 root root 4096 févr.  1  2019 services
    drwxr-xr-x 2 root root 4096 déc.  13 15:43 zones
    pi@piras:~ $ sudo ls -l /etc/firewalld/zones
    total 4
    -rw-r--r-- 1 root root 342 déc.  13 15:43 public.xml
    pi@piras:~ $ sudo cat /etc/firewalld/zones/public.xml
    <?xml version="1.0" encoding="utf-8"?>
    <zone>
    <short>Public</short>
    <description>For use in public areas. You do not trust the other computers on networks to not harm your computer. Only selected incoming connections are accepted.</description>
    <interface name="eth0"/>
    <service name="ssh"/>
    <service name="dhcpv6-client"/>
    </zone>
    pi@piras:~ $
    

    Nous voyons que firewalld a créé des répertoires et un fichier dans le répertoire zones dont le contenu correspond à ce que nous avons demandé.

    Le fichier a été créé, mais si on teste, on voit que l'option n'est pas active.

    pi@piras:~ $ sudo firewall-cmd --get-active-zones
    pi@piras:~ $ sudo firewall-cmd --list-all
    public
    target: default
    icmp-block-inversion: no
    interfaces: 
    sources: 
    services: dhcpv6-client ssh
    ports: 
    protocols: 
    masquerade: no
    forward-ports: 
    source-ports: 
    icmp-blocks: 
    rich rules: 
    
    pi@piras:~ $
    
  2. sudo firewall-cmd --zone=public --change-interface=eth0

    Permet de changer l'interface de la zone public d'une façon non-permanente.

    pi@piras:~ $ sudo firewall-cmd --zone=public --change-interface=eth0
    success
    pi@piras:~ $ sudo firewall-cmd --list-all
    public (active)
    target: default
    icmp-block-inversion: no
    interfaces: eth0
    sources: 
    services: dhcpv6-client ssh
    ports: 
    protocols: 
    masquerade: no
    forward-ports: 
    source-ports: 
    icmp-blocks: 
    rich rules: 
    
    pi@piras:~ $
    
  3. Test après reboot

    Cette fois-ci, ça marche! (Yes!)

    pi@piras:~ $ sudo firewall-cmd --list-all
    public (active)
    target: default
    icmp-block-inversion: no
    interfaces: eth0
    sources: 
    services: dhcpv6-client ssh
    ports: 
    protocols: 
    masquerade: no
    forward-ports: 
    source-ports: 
    icmp-blocks: 
    rich rules: 
    
    pi@piras:~ $
    

Ajout d'un protocole

Nous allons ajouter le service http à notre zone. Pour commencer, Ajoutons le serveur web apache.

Tout d'abord, mise à jour du système, suppression des archives des paquets, installation de apache2 et reboot.

sudo apt update && sudo apt upgrade && sudo apt clean && sudo apt install apache2 && sudo systemctl reboot
  • Nous allons tester à partir du raspi le fonctionnement de apache:

    pi@piras:~ $ ps aux | grep apache
    root       424  0.0  2.1   7284  3900 ?        Ss   17:18   0:00 /usr/sbin/apache2 -k start
    www-data   426  0.0  2.0 230832  3712 ?        Sl   17:18   0:00 /usr/sbin/apache2 -k start
    www-data   427  0.0  2.0 230832  3712 ?        Sl   17:18   0:00 /usr/sbin/apache2 -k start
    pi         750  0.0  1.1   7352  2028 pts/0    S+   17:19   0:00 grep --color=auto apache
    pi@piras:~ $ 
    

    Apache tourne.

    pi@piras:~ $ wget 127.0.0.1:80
    --2020-12-13 17:21:01--  http://127.0.0.1/
    Connexion à 127.0.0.1:80… connecté.
    requête HTTP transmise, en attente de la réponse… 200 OK
    Taille : 10701 (10K) [text/html]
    Sauvegarde en : « index.html »
    
    index.html                           100%[====================================================================>]  10,45K  --.-KB/s    ds 0,001s  
    
    2020-12-13 17:21:01 (14,6 MB/s) — « index.html » sauvegardé [10701/10701]
    
    pi@piras:~ $ 
    

    On accède à la page d'accueil.

  • Puis essayer de se connecter à partir du desktop au raspi (en http):

    Firefox ne peut établir de connexion avec le serveur à l’adresse piras.yojik.net.
    

    Evidemment, on ne peut pas accéder au serveur http du raspi:

  • Entrons les commandes qui permettent d'ouvrir les ports http et https en IPV4 et IPV6 et de rendre ces règles permanentes:

    pi@piras:~ $ sudo firewall-cmd --permanent --zone=public --add-service={http,https}
    success
    pi@piras:~ $
    pi@piras:~ $ sudo firewall-cmd --zone=public --add-service={http,https}
    success
    pi@piras:~ $
    

    Vérifions que nos nouvelles règles ont bien été enregistrées.

    pi@piras:~ $ sudo firewall-cmd --list-all
    public (active)
    target: default
    icmp-block-inversion: no
    interfaces: eth0
    sources: 
    services: dhcpv6-client http https ssh
    ports: 
    protocols: 
    masquerade: no
    forward-ports: 
    source-ports: 
    icmp-blocks: 
    rich rules: 
    
    pi@piras:~ $ 
    

    Elles ont bien été prises en compte.

  • Testons à nouveau: cette fois-ci nous devrions pouvoir accéder au serveur apache à partir du desktop (machine cliente):

    La page d'accueil de Débian s'affiche (notez l'adresse du raspi comme on l'a configurée dans une étape précédente!)

    Page d'acceuil de Debian