Votre serveur tournant sous Container Linux by CoreOS se trouve certainement sur un réseau public et est donc exposé à des attaques.

Si le côté minimaliste de CoreOS et son système de mises à jour automatiques tendent à le rendre robuste, il est important de contrôler les connexions entrantes et sortantes et à les limiter au maximum.

Cet article va montrer comment gérer le pare-feu avec Iptables sous CoreOS.

Vous ne passerez pas !

Activation des règles du pare-feu

Nous allons découvrir comment activer le pare-feu dès l'installation de CoreOS via le fichier ignition.yml, mais aussi sur une installation existante. Dans les deux cas, le service iptables-restore.service qui est mis en oeuvre, va permettre aux règles du pare-feu d'être persistantes, c'est à dire d'être automatiquement mises en place lors du démarrage du serveur.

CoreOS n'est pas encore installé

Si CoreOS n'est pas encore installé, il est possible d'intégrer la configuration d'Iptables dans le fichier ignition.yml. Pour ce faire, il faut rajouter dans le fichier de configuration Container Linux container_linux_config.yml :

systemd:
  units:
    - name: iptables-restore.service
      enable: true

ainsi que :

storage:
  files:
    - path: /var/lib/iptables/rules-save
      filesystem: root
      mode: 0644
      contents:
        inline: |
          *filter
          :INPUT DROP [0:0]
          :FORWARD DROP [0:0]
          :OUTPUT DROP [0:0]
          -A INPUT -i lo -j ACCEPT
          -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
          -A OUTPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
          -A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
          -A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
          -A INPUT -p tcp -m tcp --dport 443 -j ACCEPT
          -A INPUT -p icmp -m icmp --icmp-type 0 -j ACCEPT
          -A INPUT -p icmp -m icmp --icmp-type 3 -j ACCEPT
          -A INPUT -p icmp -m icmp --icmp-type 11 -j ACCEPT
          -A OUTPUT -p tcp -m tcp --dport 22 -j ACCEPT
          -A OUTPUT -p tcp -m tcp --dport 80 -j ACCEPT
          -A OUTPUT -p tcp -m tcp --dport 443 -j ACCEPT
          -A OUTPUT -p tcp -m tcp --dport 53 -j ACCEPT
          -A OUTPUT -p udp -m udp --dport 53 -j ACCEPT
          -A OUTPUT -p udp -m udp --dport 123 -j ACCEPT
          -A OUTPUT -p tcp -m tcp --dport 587 -j ACCEPT
          COMMIT
          #

Ensuite il restera à transpiler le fichier de configuration et à passer le fichier ignition.json résultant au script d'installation de CoreOS (voir https://www.latechniquedelours.xyz/coreos-creer-le-fichier-ignition-json).

Remarque : dans l'exemple (basique) ci-dessus le pare-feu est configuré comme suit :

  • connections entrantes sur localhost autorisées,
  • connections entrantes et sortantes déjà établies autorisées, cela évite d'avoir sa connexion SSH coupée lors de l'activation des règles du pare-feu,
  • connections entrantes autorisées en TCP sur les ports 22 (SSH), 80 (HTTP), et 443 (HTTPS),
  • messages ICMP réponse echo (type 0), destinataire inaccessible (type 3) et temps dépassé (type 11) autorisés,
  • toutes les autres connections entrantes interdites,
  • forward interdit,
  • connections sortantes autorisées en TCP sur les ports 22 (SSH), 80 (HTTP), 443 (HTTPS), 53 (DNS) et 587 (SUBMISSION),
  • connections sortantes autorisées en UDP sur les ports 53 (DNS) et 123 (NTP),
  • toutes les autres connections sortantes interdites.

N'hésitez pas à adapter ces règles selon vos besoins.

CoreOS est déjà installé

Par défaut le pare-feu autorise toutes les connections. Ceci est vérifiable via la commande suivante :

sudo iptables -S

qui retourne :

-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
... plus toute une ribambelle de règles créées par Docker

Pour activer nos règles de pare-feu, il faut procéder comme suit :

En tant que root, créez un fichier /var/lib/iptables/rules-save.

sudo vi /var/lib/iptables/rules-save

Rajoutez dans le fichier les règles du pare-feu suivantes et enregistrez le.

*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT DROP [0:0]
-A INPUT -i lo -j ACCEPT
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A OUTPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 443 -j ACCEPT
-A INPUT -p icmp -m icmp --icmp-type 0 -j ACCEPT
-A INPUT -p icmp -m icmp --icmp-type 3 -j ACCEPT
-A INPUT -p icmp -m icmp --icmp-type 11 -j ACCEPT
-A OUTPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A OUTPUT -p tcp -m tcp --dport 80 -j ACCEPT
-A OUTPUT -p tcp -m tcp --dport 443 -j ACCEPT
-A OUTPUT -p tcp -m tcp --dport 53 -j ACCEPT
-A OUTPUT -p udp -m udp --dport 53 -j ACCEPT
-A OUTPUT -p udp -m udp --dport 123 -j ACCEPT
-A OUTPUT -p tcp -m tcp --dport 587 -j ACCEPT
COMMIT

Activez et démarrez le service iptables-restore.service.

sudo systemctl enable iptables-restore.service
sudo systemctl start iptables-restore.service

Redémarrez le service docker.service pour que Docker puisse recréer ses propres règles de pare-feu.

sudo systemctl restart docker.service

Vérifiez que les règles du pare-feu soient bien prises en compte.

La commande

sudo iptables -S

doit retourner :

-P INPUT DROP
-P FORWARD DROP
-P OUTPUT DROP
... règles créées par Docker
-A INPUT -i lo -j ACCEPT
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 443 -j ACCEPT
-A INPUT -p icmp -m icmp --icmp-type 0 -j ACCEPT
-A INPUT -p icmp -m icmp --icmp-type 3 -j ACCEPT
-A INPUT -p icmp -m icmp --icmp-type 11 -j ACCEPT
... règles créées par Docker
-A OUTPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A OUTPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A OUTPUT -p tcp -m tcp --dport 80 -j ACCEPT
-A OUTPUT -p tcp -m tcp --dport 443 -j ACCEPT
-A OUTPUT -p tcp -m tcp --dport 53 -j ACCEPT
-A OUTPUT -p udp -m udp --dport 53 -j ACCEPT
-A OUTPUT -p udp -m udp --dport 123 -j ACCEPT
-A OUTPUT -p tcp -m tcp --dport 587 -j ACCEPT
... règles créées par Docker

Modification des règles du pare-feu

Pour modifier les règles du pare-feu, pour par exemple autoriser les connections entrantes sur un nouveau port, il faut procéder comme suit :

Modifiez le fichier /var/lib/iptables/rules-save.

sudo vi /var/lib/iptables/rules-save

Dans notre exemple nous allons autoriser les connexions entrantes sur le port 8443 :

*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT DROP [0:0]
-A INPUT -i lo -j ACCEPT
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A OUTPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 443 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 8443 -j ACCEPT
-A INPUT -p icmp -m icmp --icmp-type 0 -j ACCEPT
-A INPUT -p icmp -m icmp --icmp-type 3 -j ACCEPT
-A INPUT -p icmp -m icmp --icmp-type 11 -j ACCEPT
-A OUTPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A OUTPUT -p tcp -m tcp --dport 80 -j ACCEPT
-A OUTPUT -p tcp -m tcp --dport 443 -j ACCEPT
-A OUTPUT -p tcp -m tcp --dport 53 -j ACCEPT
-A OUTPUT -p udp -m udp --dport 53 -j ACCEPT
-A OUTPUT -p udp -m udp --dport 123 -j ACCEPT
-A OUTPUT -p tcp -m tcp --dport 587 -j ACCEPT
COMMIT

Redémarrez les services iptables-restore.service et docker.service.

sudo systemctl restart iptables-restore.service
sudo systemctl restart docker.service

Enfin vérifiez que les nouvelles règles du pare-feu sont bien prises en compte.

sudo iptables -S

Dans notre exemple la règle suivante doit apparaître :

...
-A INPUT -p tcp -m tcp --dport 8443 -j ACCEPT
...

Suppression des règles du pare-feu

Pour remettre à zéro les règles du pare-feu, il faut :

Modifier le fichier /var/lib/iptables/rules-save

sudo vi /var/lib/iptables/rules-save

comme suit :

*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
COMMIT

Redémarrer les services iptables-restore.service et docker.service.

sudo systemctl restart iptables-restore.service
sudo systemctl restart docker.service

Vérifier que le pare-feu accepte bien toutes les connections.

La commande

sudo iptables -S

doit retourner :

-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
... plus les règles créées par Docker

Enfermé dehors ?

Une boulette dans le fichier /var/lib/iptables/rules-save et votre accès en ssh à votre serveur est coupé, oui cela peut arriver mais vous pouvez reprendre la main.

Le principe est simple.

Démarrez votre serveur depuis une clé usb bootable Linux ou en mode Rescue.

Identifiez la partition ROOT de CoreOS. Dans notre exemple CoreOS est installé sur /dev/sda, donc sa partition ROOT est /dev/sda9.
Voir https://coreos.com/os/docs/latest/sdk-disk-partitions.html.

lsblk

Montez la partition ROOT.

sudo mkdir /mnt/coreos
sudo mount /dev/sda9 /mnt/coreos

Modifiez le fichier rules-save

sudo vi /mnt/coreos/var/lib/iptables/rules-save

comme suit :

*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
COMMIT

Enfin redémarrez votre serveur normalement.

Remarque : si vous avez un accès physique (ou via KVM IP ou équivalent) à votre serveur, il suffit par précaution et AVANT de configurer le pare-feu de rajouter un mot de passe à l'utilisateur core pour pouvoir se loguer directement en cas de souci.

À bientôt !