J’ai configuré cela. La partie la plus complexe était que — même en tant que root — vous obtiendrez toujours des erreurs « permission denied » en tentant de voir ou de modifier les règles iptables à l’intérieur du conteneur Docker Discourse par défaut.
root@24a1f9f4c038:/# iptables -L
# Warning: iptables-legacy tables present, use iptables-legacy to see them
iptables: Permission denied (you must be root).
root@24a1f9f4c038:/#
Cela est dû au fait que, par défaut, le script launcher de Discourse, qui enveloppe les commandes Docker, exécute le conteneur Docker Discourse sans la capacité « NET_ADMIN ».
La méthode la plus robuste pour ajouter la capacité NET_ADMIN au conteneur Docker Discourse consiste à mettre à jour le fichier YAML de votre conteneur afin d’inclure l’argument nécessaire dans la commande docker run ... /sbin/boot via la chaîne YAML docker_args :
docker_args: "--cap-add NET_ADMIN"
Par exemple :
[root@osestaging1 discourse]# head -n15 containers/app.yml
## this is the all-in-one, standalone Discourse Docker container template
##
## After making changes to this file, you MUST rebuild
## /var/discourse/launcher rebuild app
##
## BE *VERY* CAREFUL WHEN EDITING!
## YAML FILES ARE SUPER SUPER SENSITIVE TO MISTAKES IN WHITESPACE OR ALIGNMENT!
## visit http://www.yamllint.com/ to validate this file as needed
docker_args: "--cap-add NET_ADMIN"
templates:
- "templates/postgres.template.yml"
- "templates/redis.template.yml"
- "templates/web.template.yml"
[root@osestaging1 discourse]#
Ces arguments seront ajoutés à la commande docker run ... /sbin/boot exécutée par launcher via la variable $user_args :
[root@osestaging1 discourse]# grep -A2 -E '^\s*\$docker_path run' launcher
$docker_path run --shm-size=512m $links $attach_on_run $restart_policy "${env[@]}" "${labels[@]}" -h "$hostname" \
-e DOCKER_HOST_IP="$docker_ip" --name $config -t "${ports[@]}" $volumes $mac_address $user_args \
$run_image $boot_command
[root@osestaging1 discourse]#
Comme il est très complexe d’apporter des modifications intégrées à l’image Docker de Discourse après un docker pull et avant l’exécution de docker run ... /sbin/boot, j’ai décidé d’installer et de configurer iptables via un simple script exécuté par runit au démarrage du conteneur.
La commande suivante créera le fichier modèle YAML nécessaire, qui générera le script runit lors du prochain ./launcher rebuild app :
cat << EOF > /var/discourse/templates/iptables.template.yml
run:
- file:
path: /etc/runit/1.d/01-iptables
chmod: "+x"
contents: |
#!/bin/bash
################################################################################
# File: /etc/runit/1.d/01-iptables
# Version: 0.2
# Purpose: installs & locks-down iptables
# Author: Michael Altfield <michael@opensourceecology.org>
# Created: 2019-11-26
# Updated: 2019-12-17
################################################################################
sudo apt-get update
sudo apt-get install -y iptables
sudo iptables -A INPUT -i lo -j ACCEPT
sudo iptables -A INPUT -s 127.0.0.1/32 -j DROP
sudo iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
sudo iptables -A INPUT -j DROP
sudo iptables -A OUTPUT -s 127.0.0.1/32 -d 127.0.0.1/32 -j ACCEPT
sudo iptables -A OUTPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
sudo iptables -A OUTPUT -m owner --uid-owner 0 -j ACCEPT
sudo iptables -A OUTPUT -m owner --uid-owner 100 -j ACCEPT
sudo iptables -A OUTPUT -j DROP
sudo ip6tables -A INPUT -i lo -j ACCEPT
sudo ip6tables -A INPUT -s ::1/128 -j DROP
sudo ip6tables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
sudo ip6tables -A INPUT -j DROP
sudo ip6tables -A OUTPUT -s ::1/128 -d ::1/128 -j ACCEPT
sudo ip6tables -A OUTPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
sudo ip6tables -A OUTPUT -m owner --uid-owner 0 -j ACCEPT
sudo ip6tables -A OUTPUT -m owner --uid-owner 100 -j ACCEPT
sudo ip6tables -A OUTPUT -j DROP
EOF
Notez qu’il s’agit d’une configuration iptables très basique. Avec le fichier web.socketed.template.yml (que j’utilise), le conteneur Docker n’a techniquement pas besoin d’accès à Internet, car le proxy inverse nginx sur l’hôte Docker communique avec le nginx de Discourse dans le conteneur Docker via un socket de domaine Unix. La principale raison pour laquelle j’autorise l’accès à Internet est de permettre au système d’exploitation de base du conteneur Docker de se mettre à jour avec des correctifs de sécurité critiques via unattended-upgrades. D’où l’ouverture pour l’utilisateur 100, qui est l’utilisateur apt.
Enfin, ajoutez le fichier templates/iptables.template.yml ci-dessus au fichier app.yaml de votre conteneur.
[root@osestaging1 discourse]# head -n15 /var/discourse/containers/discourse_ose.yml
## this is the all-in-one, standalone Discourse Docker container template
##
## After making changes to this file, you MUST rebuild
## /var/discourse/launcher rebuild app
##
## BE *VERY* CAREFUL WHEN EDITING!
## YAML FILES ARE SUPER SUPER SENSITIVE TO MISTAKES IN WHITESPACE OR ALIGNMENT!
## visit http://www.yamllint.com/ to validate this file as needed
docker_args: "--cap-add NET_ADMIN"
templates:
- "templates/iptables.template.yml"
- "templates/postgres.template.yml"
- "templates/redis.template.yml"
[root@osestaging1 discourse]#
Vous devriez maintenant pouvoir exécuter :
./launcher rebuild app
Après environ 10 minutes d’attente, votre conteneur Docker Discourse aura iptables pleinement fonctionnel 