From dc9d9d2202d0b98ce5f5bcc8e1bb41bc439288ed Mon Sep 17 00:00:00 2001 From: Florian Eckert Date: Tue, 10 Nov 2020 11:20:14 +0100 Subject: [PATCH 1/7] docker-ce: add arguments call to uciadd and ucidel Up to now only the docker0 interface and bridge is created by default. In order to create other interfaces and to integrate them into the openwrt these functions can now be called with arguments. Signed-off-by: Florian Eckert --- utils/docker-ce/files/dockerd.init | 88 +++++++++++++++++++----------- 1 file changed, 57 insertions(+), 31 deletions(-) diff --git a/utils/docker-ce/files/dockerd.init b/utils/docker-ce/files/dockerd.init index 549b060d9..aae396695 100755 --- a/utils/docker-ce/files/dockerd.init +++ b/utils/docker-ce/files/dockerd.init @@ -3,8 +3,8 @@ USE_PROCD=1 START=25 -extra_command "uciadd" "Add default bridge configuration to network and firewall uci config" -extra_command "ucidel" "Delete default bridge configuration from network and firewall uci config" +extra_command "uciadd" " Add docker bridge configuration to network and firewall uci config" +extra_command "ucidel" " Delete docker bridge configuration from network and firewall uci config" DOCKER_CONF_DIR="/tmp/dockerd" DOCKERD_CONF="${DOCKER_CONF_DIR}/daemon.json" @@ -46,43 +46,53 @@ uciupdate() { } uciadd() { + local iface="$1" + local device="$2" + local zone="$3" + + [ -z "$iface" ] && { + iface="docker" + device="docker0" + zone="docker" + } + /etc/init.d/dockerd running && { echo "Please stop dockerd service first" exit 0 } # Add network interface - if ! uci_quiet get network.docker; then - logger -t "dockerd-init" -p notice "Adding docker default interface to network uci config (docker)" + if ! uci_quiet get network.${iface}; then + logger -t "dockerd-init" -p notice "Adding docker default interface to network uci config (${iface})" uci_quiet add network interface - uci_quiet rename network.@interface[-1]="docker" - uci_quiet set network.docker.ifname="docker0" - uci_quiet set network.docker.proto="static" - uci_quiet set network.docker.auto="0" + uci_quiet rename network.@interface[-1]="${iface}" + uci_quiet set network.@interface[-1].ifname="${device}" + uci_quiet set network.@interface[-1].proto="static" + uci_quiet set network.@interface[-1].auto="0" uci_quiet commit network fi # Add docker bridge device - if ! uci_quiet get network.docker0; then - logger -t "dockerd-init" -p notice "Adding docker default bridge device to network uci config (docker0)" + if ! uci_quiet get network.${device}; then + logger -t "dockerd-init" -p notice "Adding docker default bridge device to network uci config (${device})" uci_quiet add network device - uci_quiet rename network.@device[-1]="docker0" - uci_quiet set network.docker0.type="bridge" - uci_quiet set network.docker0.name="docker0" - uci_quiet add_list network.docker0.ifname="docker0" + uci_quiet rename network.@device[-1]="${device}" + uci_quiet set network.@device[-1].type="bridge" + uci_quiet set network.@device[-1].name="${device}" + uci_quiet add_list network.@device[-1].ifname="${device}" uci_quiet commit network fi # Add firewall zone - if ! uci_quiet get firewall.docker; then - logger -t "dockerd-init" -p notice "Adding docker default firewall zone to firewall uci config (docker)" + if ! uci_quiet get firewall.${zone}; then + logger -t "dockerd-init" -p notice "Adding docker default firewall zone to firewall uci config (${zone})" uci_quiet add firewall zone - uci_quiet rename firewall.@zone[-1]="docker" - uci_quiet set firewall.docker.network="docker" - uci_quiet set firewall.docker.input="REJECT" - uci_quiet set firewall.docker.output="ACCEPT" - uci_quiet set firewall.docker.forward="REJECT" - uci_quiet set firewall.docker.name="docker" + uci_quiet rename firewall.@zone[-1]="${zone}" + uci_quiet set firewall.@zone[-1].network="${iface}" + uci_quiet set firewall.@zone[-1].input="REJECT" + uci_quiet set firewall.@zone[-1].output="ACCEPT" + uci_quiet set firewall.@zone[-1].forward="REJECT" + uci_quiet set firewall.@zone[-1].name="${zone}" uci_quiet commit firewall fi @@ -90,22 +100,38 @@ uciadd() { } ucidel() { + local iface="$1" + local device="$2" + local zone="$3" + + [ -z "$iface" ] && { + iface="docker" + device="docker0" + zone="docker" + } + /etc/init.d/dockerd running && { echo "Please stop dockerd service first" exit 0 } - logger -t "dockerd-init" -p notice "Deleting docker default bridge device from network uci config (docker0)" - uci_quiet delete network.docker0 - uci_quiet commit network + if uci_quiet get network.${device}; then + logger -t "dockerd-init" -p notice "Deleting docker default bridge device from network uci config (${device})" + uci_quiet delete network.${device} + uci_quiet commit network + fi - logger -t "dockerd-init" -p notice "Deleting docker default interface from network uci config (docker)" - uci_quiet delete network.docker - uci_quiet commit network + if uci_quiet get network.${iface}; then + logger -t "dockerd-init" -p notice "Deleting docker default interface from network uci config (${iface})" + uci_quiet delete network.${iface} + uci_quiet commit network + fi - logger -t "dockerd-init" -p notice "Deleting docker firewall zone from firewall uci config (docker)" - uci_quiet delete firewall.docker - uci_quiet commit firewall + if uci_quiet get firewall.${zone}; then + logger -t "dockerd-init" -p notice "Deleting docker firewall zone from firewall uci config (${zone})" + uci_quiet delete firewall.${zone} + uci_quiet commit firewall + fi reload_config } From 1af559356829cad1ff0977900f7de459ae50a3a6 Mon Sep 17 00:00:00 2001 From: Florian Eckert Date: Wed, 11 Nov 2020 13:34:39 +0100 Subject: [PATCH 2/7] docker-ce: make docker-ce firewall handling configurable Openwrt has a own firewall service called fw3, that supports firewall zones. Docker can bypass the handling of the zone rules in openwrt via custom tables. These are "always" processed before the openwrt firewall. Which is prone to errors! Since not everyone is aware that the firewall of openwrt will not be passed. And this is a security problem because a mapped port is visible on all interfaces and so also on the WAN side. If the firewall handling in docker is switched off, then the port in fw3 must be explicitly released and it cannot happen that the port is accidentally exported to the outside world via the interfaces on the WAN zone. So all rules for the containers should and so must be made in fw3. Signed-off-by: Florian Eckert --- utils/docker-ce/files/dockerd.init | 9 +++++---- utils/docker-ce/files/etc/config/dockerd | 1 + 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/utils/docker-ce/files/dockerd.init b/utils/docker-ce/files/dockerd.init index aae396695..b0878a472 100755 --- a/utils/docker-ce/files/dockerd.init +++ b/utils/docker-ce/files/dockerd.init @@ -137,7 +137,7 @@ ucidel() { } process_config() { - local alt_config_file data_root log_level bip + local alt_config_file data_root log_level iptables bip [ -f /etc/config/dockerd ] || { # Use the daemon default configuration @@ -150,9 +150,6 @@ process_config() { mkdir -p "${DOCKER_CONF_DIR}" config_load 'dockerd' - - config_list_foreach firewall blocked_interfaces add_docker_firewall_rules - config_get alt_config_file globals alt_config_file [ -n "${alt_config_file}" ] && [ -f "${alt_config_file}" ] && { ln -s "${alt_config_file}" "${DOCKERD_CONF}" @@ -161,6 +158,7 @@ process_config() { config_get data_root globals data_root "/opt/docker/" config_get log_level globals log_level "warn" + config_get_bool iptables globals iptables "1" config_get bip globals bip "" . /usr/share/libubox/jshn.sh @@ -175,6 +173,9 @@ process_config() { config_list_foreach globals hosts json_add_array_string json_close_array + json_add_boolean iptables "${iptables}" + [ "${iptables}" -ne "0" ] && config_foreach iptables_add_blocking_rule firewall + json_dump > "${DOCKERD_CONF}" uciupdate "${bip}" diff --git a/utils/docker-ce/files/etc/config/dockerd b/utils/docker-ce/files/etc/config/dockerd index 13d9845c6..d0e39cc9a 100644 --- a/utils/docker-ce/files/etc/config/dockerd +++ b/utils/docker-ce/files/etc/config/dockerd @@ -9,6 +9,7 @@ config globals 'globals' option log_level "warn" list hosts "unix:///var/run/docker.sock" option bip "172.18.0.1/24" +# option iptables "0" # list registry_mirrors "https://" # list registry_mirrors "https://hub.docker.com" From f12071add992c8b76b1b065257ac306f83957653 Mon Sep 17 00:00:00 2001 From: Florian Eckert Date: Wed, 11 Nov 2020 15:52:20 +0100 Subject: [PATCH 3/7] docker-ce: set proto for docker bridge device to none Set proto from `static` to `none`. This makes it clear that this interface is not handled by the netifd. Signed-off-by: Florian Eckert --- utils/docker-ce/files/dockerd.init | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/docker-ce/files/dockerd.init b/utils/docker-ce/files/dockerd.init index b0878a472..d769b5b4d 100755 --- a/utils/docker-ce/files/dockerd.init +++ b/utils/docker-ce/files/dockerd.init @@ -67,7 +67,7 @@ uciadd() { uci_quiet add network interface uci_quiet rename network.@interface[-1]="${iface}" uci_quiet set network.@interface[-1].ifname="${device}" - uci_quiet set network.@interface[-1].proto="static" + uci_quiet set network.@interface[-1].proto="none" uci_quiet set network.@interface[-1].auto="0" uci_quiet commit network fi From 7c9ed12fa17f0c1fc2b013718de1c2a899a9518f Mon Sep 17 00:00:00 2001 From: Florian Eckert Date: Wed, 11 Nov 2020 14:20:49 +0100 Subject: [PATCH 4/7] docker-ce: remove not applicable uciupdate As the protocol is set to none, this makes no sense here, as it cannot be controlled and thus processed by the netifd. Signed-off-by: Florian Eckert --- utils/docker-ce/files/dockerd.init | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/utils/docker-ce/files/dockerd.init b/utils/docker-ce/files/dockerd.init index d769b5b4d..ce65b012a 100755 --- a/utils/docker-ce/files/dockerd.init +++ b/utils/docker-ce/files/dockerd.init @@ -22,29 +22,6 @@ boot() { rc_procd start_service } -uciupdate() { - local net="${1}" - - uci_quiet get network.docker || { - logger -t "dockerd-init" -p warn "No network uci config section for docker default bridge (docker0) found" - return - } - - [ -z "${net}" ] && { - logger -t "dockerd-init" -p notice "Removing network uci config options for docker default bridge (docker0)" - uci_quiet delete network.docker.netmask - uci_quiet delete network.docker.ipaddr - uci_quiet commit network - return - } - - eval "$(ipcalc.sh "${net}")" - logger -t "dockerd-init" -p notice "Updating network uci config option \"${net}\" for docker default bridge (docker0)" - uci_quiet set network.docker.netmask="${NETMASK}" - uci_quiet set network.docker.ipaddr="${IP}" - uci_quiet commit network -} - uciadd() { local iface="$1" local device="$2" @@ -177,8 +154,6 @@ process_config() { [ "${iptables}" -ne "0" ] && config_foreach iptables_add_blocking_rule firewall json_dump > "${DOCKERD_CONF}" - - uciupdate "${bip}" } start_service() { From 19fc9333303f742434cdb0ec8e922e2c01eb0cbe Mon Sep 17 00:00:00 2001 From: Florian Eckert Date: Wed, 11 Nov 2020 15:05:38 +0100 Subject: [PATCH 5/7] docker-ce: add device option to expand interface blocking If docker-ce handles the firewall and fw3 is not envolved because the rules get not proceed, then not only docker0 should be handled but also other interfaces and therefore other docker networks. This commit extends the handling and introduces a new uci option `device` in the docker config firewall section. This can be used to specify which device is allowed to access the container. Up to now only docker0 is covert. Signed-off-by: Florian Eckert --- utils/docker-ce/files/dockerd.init | 41 ++++++++++++++++++------ utils/docker-ce/files/etc/config/dockerd | 1 + 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/utils/docker-ce/files/dockerd.init b/utils/docker-ce/files/dockerd.init index ce65b012a..1ca5e5420 100755 --- a/utils/docker-ce/files/dockerd.init +++ b/utils/docker-ce/files/dockerd.init @@ -181,16 +181,39 @@ service_triggers() { procd_add_reload_trigger 'dockerd' } -add_docker_firewall_rules() { - . /lib/functions/network.sh - local device interface="${1}" +iptables_add_blocking_rule() { + local cfg="$1" - # Ignore errors as it might already be present - iptables --table filter --new DOCKER-USER 2>/dev/null - network_get_physdev device "${interface}" - if ! iptables --table filter --check DOCKER-USER --in-interface "${device}" --out-interface docker0 --jump DROP 2>/dev/null; then - iptables --table filter --insert DOCKER-USER --in-interface "${device}" --out-interface docker0 --jump DROP - fi + local device="" + + handle_iptables_rule() { + local interface="$1" + local outbound="$2" + + local inbound="" + + . /lib/functions/network.sh + network_get_physdev inbound "${interface}" + + [ -z "$inbound" ] && { + logger -t "dockerd-init" -p notice "Unable to get physical device for interface ${interface}" + return + } + + if ! iptables --table filter --check DOCKER-USER --in-interface "${inbound}" --out-interface "${outbound}" --jump DROP 2>/dev/null; then + logger -t "dockerd-init" -p notice "Drop traffic from ${inbound} to ${outbound}" + iptables --table filter --insert DOCKER-USER --in-interface "${inbound}" --out-interface "${outbound}" --jump DROP + fi + } + + config_get device "$cfg" device + + [ -z "$device" ] && { + logger -t "dockerd-init" -p notice "No device configured for ${cfg}" + return + } + + config_list_foreach "$cfg" blocked_interfaces handle_iptables_rule "$device" } ip4tables_remove_nat() { diff --git a/utils/docker-ce/files/etc/config/dockerd b/utils/docker-ce/files/etc/config/dockerd index d0e39cc9a..3a1f80278 100644 --- a/utils/docker-ce/files/etc/config/dockerd +++ b/utils/docker-ce/files/etc/config/dockerd @@ -16,4 +16,5 @@ config globals 'globals' # Docker ignores fw3 rules and by default all external source IPs are allowed # to connect to the Docker host. See https://docs.docker.com/network/iptables/ config firewall 'firewall' + option device 'docker0' list blocked_interfaces 'wan' From 96a11a9c023f673e05e882a10b5ae3c3eefd8cec Mon Sep 17 00:00:00 2001 From: Florian Eckert Date: Mon, 16 Nov 2020 10:28:03 +0100 Subject: [PATCH 6/7] docker-ce: do not delete generated iptables by docker-ce Deleting rules that docker has created is error-prone, because with every update docker we have to check if anything has changed. Cleaning up the firewall rules is part of the docker and should and must be cleaned up and handeled by them when the service is terminated. Signed-off-by: Florian Eckert --- utils/docker-ce/files/dockerd.init | 33 ------------------------------ 1 file changed, 33 deletions(-) diff --git a/utils/docker-ce/files/dockerd.init b/utils/docker-ce/files/dockerd.init index 1ca5e5420..f5388c083 100755 --- a/utils/docker-ce/files/dockerd.init +++ b/utils/docker-ce/files/dockerd.init @@ -216,41 +216,8 @@ iptables_add_blocking_rule() { config_list_foreach "$cfg" blocked_interfaces handle_iptables_rule "$device" } -ip4tables_remove_nat() { - iptables --table nat --delete OUTPUT ! --destination 127.0.0.0/8 --match addrtype --dst-type LOCAL --jump DOCKER - iptables --table nat --delete PREROUTING --match addrtype --dst-type LOCAL --jump DOCKER - - iptables --table nat --flush DOCKER - iptables --table nat --delete-chain DOCKER -} - -ip4tables_remove_filter() { - iptables --table filter --delete FORWARD --jump DOCKER-USER - iptables --table filter --delete FORWARD --jump DOCKER-ISOLATION-STAGE-1 - iptables --table filter --delete FORWARD --out-interface docker0 --jump DOCKER - iptables --table filter --delete FORWARD --out-interface docker0 --match conntrack --ctstate RELATED,ESTABLISHED --jump ACCEPT - iptables --table filter --delete FORWARD --in-interface docker0 --out-interface docker0 --jump ACCEPT - iptables --table filter --delete FORWARD --in-interface docker0 ! --out-interface docker0 --jump ACCEPT - - iptables --table filter --flush DOCKER - iptables --table filter --flush DOCKER-ISOLATION-STAGE-1 - iptables --table filter --flush DOCKER-ISOLATION-STAGE-2 - iptables --table filter --flush DOCKER-USER - - iptables --table filter --delete-chain DOCKER - iptables --table filter --delete-chain DOCKER-ISOLATION-STAGE-1 - iptables --table filter --delete-chain DOCKER-ISOLATION-STAGE-2 - iptables --table filter --delete-chain DOCKER-USER -} - -ip4tables_remove() { - ip4tables_remove_nat - ip4tables_remove_filter -} - stop_service() { if /etc/init.d/dockerd running; then service_stop "/usr/bin/dockerd" - ip4tables_remove fi } From 6df16e50fbd27581e02f5018712668e870df5a44 Mon Sep 17 00:00:00 2001 From: Florian Eckert Date: Thu, 19 Nov 2020 14:19:27 +0100 Subject: [PATCH 7/7] docker-ce: update PKG_RELEASE version Signed-off-by: Florian Eckert --- utils/docker-ce/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/docker-ce/Makefile b/utils/docker-ce/Makefile index 5b111c269..e648bbc1e 100644 --- a/utils/docker-ce/Makefile +++ b/utils/docker-ce/Makefile @@ -2,7 +2,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=docker-ce PKG_VERSION:=19.03.13 -PKG_RELEASE:=3 +PKG_RELEASE:=4 PKG_LICENSE:=Apache-2.0 PKG_LICENSE_FILES:=components/cli/LICENSE components/engine/LICENSE