So verwenden Sie `iptables` innerhalb eines Discourse Docker-Containers

Wie kann ich iptables im Discourse-Docker-Container konfigurieren?

Ich benötige speziell die Firewall-Steuerung innerhalb des Docker-Containers, da ich bedingte Regeln basierend auf der Benutzer-ID hinzufügen möchte.

Anfangs habe ich jeglichen Internetzugriff für den Docker-Container komplett blockiert (dies ist möglich, wenn Sie web.socketed.template.yml verwenden, da Nginx über Unix-Domain-Sockets anstelle des Netzwerks kommuniziert) mittels dockerd ... --iptables=false.

[root@osestaging1 templates]# grep ExecStart /usr/lib/systemd/system/docker.service
#ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --iptables=false
[root@osestaging1 templates]# 

…aber mir ist aufgefallen, dass der Docker-Container zumindest Internetzugriff haben sollte, damit er sein Basis-Betriebssystem (derzeit Debian 10) mit kritischen Sicherheitsupdates über unattended-upgrades aktualisieren kann. Daher möchte ich lieber nur root und apt Internetzugriff gewähren und alles andere über iptables blockieren, das innerhalb des Discourse-Docker-Containers ausgeführt wird.

I set this up. The most complicated part was that–even if you’re root–you’ll still get “permission denied” errors when attempting to view or edit iptables rules inside of the default Discourse docker container.

root@24a1f9f4c038:/# iptables -L
# Warning: iptables-legacy tables present, use iptables-legacy to see them
iptables: Permission denied (you must be root).
root@24a1f9f4c038:/# 

This is because–out of the box–the Discourse launcher script that wraps the docker commands runs the Discourse docker container without the “NET_ADMIN” capability.

The most robust way to add the NET_ADMIN capability to the Discourse docker container is to update your container’s yaml file to include the necessary argument to the docker run ... /sbin/boot command via the docker_args yaml string:

docker_args: "--cap-add NET_ADMIN"

For example:

[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]# 

These will get added to the docker run ... /sbin/boot command executed by launcher via the $user_args variable:

[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]# 

Because it’s super complex to make changes baked-into the discourse docker image after a docker pull and before the docker run ... /sbin/boot, I decided to have iptables installed & configured via a simple script executed by runit when the container boots.

The following command will create the necessary template yaml file which will create the runit script on the next ./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

Note that this is a very basic iptables config. With the web.socketed.template.yml file (which I use), the docker container technically doesn’t need Internet access at all since the nginx reverse proxy on the docker host communicates through to the Discourse nginx on the docker container via a unix domain socket. The main reason I permit Internet access is so that the docker container’s base OS can update itself with critical security patches via unattended-upgrades. Hence opening for user 100, which is the apt user.

Finally, add the above templates/iptables.template.yml file to your container’s app.yaml file.

[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]# 

Now you should be able to

./launcher rebuild app

And after waiting about 10 minutes, your Discourse docker container will have iptables fully functioning :slight_smile:

1 „Gefällt mir“

:warning: Whoever you are, whatever you do, please don’t try this at home, school or anywhere!

I’m quite sure that you are crippling your Discourse instance by disallowing the unicorn and sidekiq processes (owned by the discourse user) to access the internet. But yeah, I’m sure you know what you are doing.

15 „Gefällt mir“

What problem is this solving?

4 „Gefällt mir“