fix(gateway): always masquerade for docker-deployed gateways (#6169)

Without masquerading, packets sent by the gateway through the TUN
interface use the wrong source address (the TUN device's address)
instead of the gateway's actual network interface.

We set this env variable in all our uses of the gateway, thus we might
as well remove it and always perform unconditionally.

---------

Signed-off-by: Thomas Eizinger <thomas@eizinger.io>
Co-authored-by: Reactor Scram <ReactorScram@users.noreply.github.com>
This commit is contained in:
Thomas Eizinger
2024-08-07 04:00:50 +01:00
committed by GitHub
parent 0cb96d5e37
commit 94527f9fa1
9 changed files with 87 additions and 54 deletions

View File

@@ -344,7 +344,7 @@ services:
environment:
FIREZONE_TOKEN: ".SFMyNTY.g2gDaANtAAAAJGM4OWJjYzhjLTkzOTItNGRhZS1hNDBkLTg4OGFlZjZkMjhlMG0AAAAkMjI3NDU2MGItZTk3Yi00NWU0LThiMzQtNjc5Yzc2MTdlOThkbQAAADhPMDJMN1VTMkozVklOT01QUjlKNklMODhRSVFQNlVPOEFRVk82VTVJUEwwVkpDMjJKR0gwPT09PW4GAI0Qi02QAWIAAVGA.emd2izXZdGngSMDruiTNgwRYbNtsVLYf_fouNyoKv8Q"
RUST_LOG: ${RUST_LOG:-phoenix_channel=trace,firezone_gateway=trace,wire=trace,connlib_gateway_shared=trace,firezone_tunnel=trace,connlib_shared=trace,phoenix_channel=debug,boringtun=debug,snownet=debug,str0m=debug,info}
FIREZONE_ENABLE_MASQUERADE: 1
FIREZONE_ENABLE_MASQUERADE: 1 # FIXME: NOOP in latest version. Remove after next release.
FIREZONE_API_URL: ws://api:8081
FIREZONE_ID: 4694E56C-7643-4A15-9DF3-638E5B05F570
build:

View File

@@ -310,7 +310,7 @@ defmodule Web.Sites.NewToken do
"--sysctl net.ipv6.conf.all.forwarding=1",
"--sysctl net.ipv6.conf.default.forwarding=1",
"--device=\"/dev/net/tun:/dev/net/tun\"",
Enum.map(env ++ [{"FIREZONE_ENABLE_MASQUERADE", "1"}], fn {key, value} ->
Enum.map(env, fn {key, value} ->
"--env #{key}=\"#{value}\""
end),
"--env FIREZONE_NAME=$(hostname)",

View File

@@ -3,9 +3,11 @@ ARG RUST_VERSION="1.80"
ARG ALPINE_VERSION="3.20"
ARG CARGO_CHEF_VERSION="0.1.67"
ARG PACKAGE
# This image is used to prepare Cargo Chef which is used to cache dependencies
# Keep the Rust version synced with `rust-toolchain.toml`
FROM rust:${RUST_VERSION}-alpine${ALPINE_VERSION} as chef
FROM rust:${RUST_VERSION}-alpine${ALPINE_VERSION} AS chef
ARG CARGO_CHEF_VERSION
RUN set -xe \
@@ -23,29 +25,27 @@ WORKDIR /build
# Create a cache recipe for dependencies, which allows
# to leverage Docker layer caching in a later build stage
FROM chef as planner
FROM chef AS planner
COPY . .
RUN cargo chef prepare --recipe-path recipe.json
# Build dependencies and application application
FROM chef as builder
FROM chef AS builder
COPY --from=planner /build/recipe.json .
ARG PACKAGE
RUN set -xe \
&& cargo chef cook --recipe-path recipe.json --bin ${PACKAGE}
COPY . .
ARG TARGET
ARG PACKAGE
RUN cargo build -p ${PACKAGE} $([ -n "${TARGET}" ] && "--target ${TARGET}")
# Image which is used to run the application binary
FROM alpine:${ALPINE_VERSION} AS runtime
# Base image which is used to run the application binary
FROM alpine:${ALPINE_VERSION} AS runtime_base
# Important! Update this no-op ENV variable when this Dockerfile
# is updated with the current date. It will force refresh of all
@@ -59,28 +59,47 @@ ENV REFRESHED_AT=2023-10-23 \
WORKDIR /bin
## curl is needed by the entrypoint script
# Gateway specific runtime base image
FROM runtime_base AS runtime_firezone-gateway
## iptables are needed only by gateway for masquerading
RUN apk add --no-cache iptables ip6tables
COPY ./docker-init-gateway.sh ./docker-init.sh
# Relay specific runtime base image
FROM runtime_base AS runtime_firezone-relay
## curl is needed by the entrypoint script for the relay
RUN set -xe \
&& apk add --no-cache curl
COPY ./docker-init-relay.sh ./docker-init.sh
COPY ./docker-init.sh .
# Headless-client specific runtime base image
FROM runtime_base AS runtime_firezone-headless-client
COPY ./docker-init.sh ./docker-init.sh
## iptables are needed only by gateway for masquerading
ARG PACKAGE
# HTTP test server specific runtime base image
FROM runtime_base AS runtime_http-test-server
COPY ./docker-init.sh ./docker-init.sh
# snownet-tests specific runtime base image
FROM runtime_base AS runtime_snownet-tests
RUN set -xe \
&& \[ "${PACKAGE}" = "firezone-gateway" ] && apk add --no-cache iptables ip6tables || true
&& apk add --no-cache curl
COPY ./docker-init.sh ./docker-init.sh
# Funnel package specific base image back into `runtime`
FROM runtime_${PACKAGE} AS runtime
ARG PACKAGE
ENTRYPOINT ["docker-init.sh"]
ENV PACKAGE=${PACKAGE}
CMD $PACKAGE
# used as a base for dev and test
FROM runtime as test
FROM runtime AS test
RUN set -xe \
&& apk add --no-cache iperf3 bind-tools iproute2 jq procps
&& apk add --no-cache curl iperf3 bind-tools iproute2 jq procps
# used for local development
FROM test AS dev

19
rust/docker-init-gateway.sh Executable file
View File

@@ -0,0 +1,19 @@
#!/bin/sh
if [ -f "${FIREZONE_TOKEN}" ]; then
FIREZONE_TOKEN="$(cat "${FIREZONE_TOKEN}")"
export FIREZONE_TOKEN
fi
IFACE="tun-firezone"
# Enable masquerading for our TUN interface
iptables -C FORWARD -i $IFACE -j ACCEPT >/dev/null 2>&1 || iptables -A FORWARD -i $IFACE -j ACCEPT
iptables -C FORWARD -o $IFACE -j ACCEPT >/dev/null 2>&1 || iptables -A FORWARD -o $IFACE -j ACCEPT
iptables -t nat -C POSTROUTING -o e+ -j MASQUERADE >/dev/null 2>&1 || iptables -t nat -A POSTROUTING -o e+ -j MASQUERADE
iptables -t nat -C POSTROUTING -o w+ -j MASQUERADE >/dev/null 2>&1 || iptables -t nat -A POSTROUTING -o w+ -j MASQUERADE
ip6tables -C FORWARD -i $IFACE -j ACCEPT >/dev/null 2>&1 || ip6tables -A FORWARD -i $IFACE -j ACCEPT
ip6tables -C FORWARD -o $IFACE -j ACCEPT >/dev/null 2>&1 || ip6tables -A FORWARD -o $IFACE -j ACCEPT
ip6tables -t nat -C POSTROUTING -o e+ -j MASQUERADE >/dev/null 2>&1 || ip6tables -t nat -A POSTROUTING -o e+ -j MASQUERADE
ip6tables -t nat -C POSTROUTING -o w+ -j MASQUERADE >/dev/null 2>&1 || ip6tables -t nat -A POSTROUTING -o w+ -j MASQUERADE
exec "$@"

24
rust/docker-init-relay.sh Executable file
View File

@@ -0,0 +1,24 @@
#!/bin/sh
if [ -f "${FIREZONE_TOKEN}" ]; then
FIREZONE_TOKEN="$(cat "${FIREZONE_TOKEN}")"
export FIREZONE_TOKEN
fi
if [ "${LISTEN_ADDRESS_DISCOVERY_METHOD}" = "gce_metadata" ]; then
echo "Using GCE metadata to discover listen address"
if [ "${PUBLIC_IP4_ADDR}" = "" ]; then
public_ip4=$(curl "http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/0/access-configs/0/external-ip" -H "Metadata-Flavor: Google" -s)
export PUBLIC_IP4_ADDR="${public_ip4}"
echo "Discovered PUBLIC_IP4_ADDR: ${PUBLIC_IP4_ADDR}"
fi
if [ "${PUBLIC_IP6_ADDR}" = "" ]; then
public_ip6=$(curl "http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/0/ipv6s" -H "Metadata-Flavor: Google" -s)
export PUBLIC_IP6_ADDR="${public_ip6}"
echo "Discovered PUBLIC_IP6_ADDR: ${PUBLIC_IP6_ADDR}"
fi
fi
exec "$@"

View File

@@ -5,33 +5,4 @@ if [ -f "${FIREZONE_TOKEN}" ]; then
export FIREZONE_TOKEN
fi
if [ "${FIREZONE_ENABLE_MASQUERADE}" = "1" ]; then
IFACE="tun-firezone"
# Enable masquerading for ethernet and wireless interfaces
iptables -C FORWARD -i $IFACE -j ACCEPT >/dev/null 2>&1 || iptables -A FORWARD -i $IFACE -j ACCEPT
iptables -C FORWARD -o $IFACE -j ACCEPT >/dev/null 2>&1 || iptables -A FORWARD -o $IFACE -j ACCEPT
iptables -t nat -C POSTROUTING -o e+ -j MASQUERADE >/dev/null 2>&1 || iptables -t nat -A POSTROUTING -o e+ -j MASQUERADE
iptables -t nat -C POSTROUTING -o w+ -j MASQUERADE >/dev/null 2>&1 || iptables -t nat -A POSTROUTING -o w+ -j MASQUERADE
ip6tables -C FORWARD -i $IFACE -j ACCEPT >/dev/null 2>&1 || ip6tables -A FORWARD -i $IFACE -j ACCEPT
ip6tables -C FORWARD -o $IFACE -j ACCEPT >/dev/null 2>&1 || ip6tables -A FORWARD -o $IFACE -j ACCEPT
ip6tables -t nat -C POSTROUTING -o e+ -j MASQUERADE >/dev/null 2>&1 || ip6tables -t nat -A POSTROUTING -o e+ -j MASQUERADE
ip6tables -t nat -C POSTROUTING -o w+ -j MASQUERADE >/dev/null 2>&1 || ip6tables -t nat -A POSTROUTING -o w+ -j MASQUERADE
fi
if [ "${LISTEN_ADDRESS_DISCOVERY_METHOD}" = "gce_metadata" ]; then
echo "Using GCE metadata to discover listen address"
if [ "${PUBLIC_IP4_ADDR}" = "" ]; then
public_ip4=$(curl "http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/0/access-configs/0/external-ip" -H "Metadata-Flavor: Google" -s)
export PUBLIC_IP4_ADDR="${public_ip4}"
echo "Discovered PUBLIC_IP4_ADDR: ${PUBLIC_IP4_ADDR}"
fi
if [ "${PUBLIC_IP6_ADDR}" = "" ]; then
public_ip6=$(curl "http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/0/ipv6s" -H "Metadata-Flavor: Google" -s)
export PUBLIC_IP6_ADDR="${public_ip6}"
echo "Discovered PUBLIC_IP6_ADDR: ${PUBLIC_IP6_ADDR}"
fi
fi
exec "$@"

View File

@@ -18,10 +18,6 @@ locals {
{
name = "FIREZONE_API_URL"
value = var.api_url
},
{
name = "FIREZONE_ENABLE_MASQUERADE"
value = "1"
}
], var.application_environment_variables)
}

View File

@@ -34,10 +34,6 @@ services:
# See https://docs.rs/env_logger/latest/env_logger/ for more information.
- RUST_LOG=str0m=warn,info
# Enable or disable masquerading. Default enabled. Disabling this can prevent
# the Gateway from reaching other hosts in your subnet or the internet.
# - FIREZONE_ENABLE_MASQUERADE=1
# Human-friendly name to use for this Gateway in the admin portal.
# $(hostname) is used by default if not set.
# - FIREZONE_NAME=<name-of-gateway>

View File

@@ -8,6 +8,14 @@ export default function Gateway() {
return (
<Entries href={href} arches={arches} title="Gateway">
<Entry version="1.1.X" date={new Date("2024-XX-XX")}>
<ul className="list-disc space-y-2 pl-4 mb-4">
<li className="pl-2">
Removes `FIREZONE_ENABLE_MASQUERADE` env variable.
Masquerading is now always enabled unconditionally.
</li>
</ul>
</Entry>
<Entry version="1.1.3" date={new Date("2024-08-02")}>
<ul className="list-disc space-y-2 pl-4 mb-4">
<li className="pl-2">