diff --git a/k8s/apps/amnezia/configmap-scripts.yaml b/k8s/apps/amnezia/configmap-scripts.yaml index 3b8117f..297ed9f 100644 --- a/k8s/apps/amnezia/configmap-scripts.yaml +++ b/k8s/apps/amnezia/configmap-scripts.yaml @@ -10,12 +10,17 @@ data: PORT="${1:-5847}" VPN_CIDR="${2:-10.8.0.0/16}" + INPUT_CHAIN="AMNEZIAWG-INPUT" + FORWARD_CHAIN="AMNEZIAWG-FORWARD" + IPTABLES=(iptables -w 30) external_interface() { ip route get 1.1.1.1 | awk '{for (i=1;i<=NF;i++) if ($i=="dev") {print $(i+1); exit}}' } - ensure_insert_rule() { + ensure_rule() { + local mode="$1" + shift local table_args=() if [ "${1:-}" = "-t" ]; then table_args=("$1" "$2") @@ -25,8 +30,8 @@ data: local chain="$1" shift - if ! iptables "${table_args[@]}" -C "${chain}" "$@" >/dev/null 2>&1; then - iptables "${table_args[@]}" -I "${chain}" 1 "$@" + if ! "${IPTABLES[@]}" "${table_args[@]}" -C "${chain}" "$@" >/dev/null 2>&1; then + "${IPTABLES[@]}" "${table_args[@]}" "${mode}" "${chain}" "$@" fi } @@ -40,24 +45,15 @@ data: local chain="$1" shift - while iptables "${table_args[@]}" -D "${chain}" "$@" >/dev/null 2>&1; do + while "${IPTABLES[@]}" "${table_args[@]}" -D "${chain}" "$@" >/dev/null 2>&1; do true done } - ensure_append_rule() { - local table_args=() - if [ "${1:-}" = "-t" ]; then - table_args=("$1" "$2") - shift 2 - fi - + reset_chain() { local chain="$1" - shift - - if ! iptables "${table_args[@]}" -C "${chain}" "$@" >/dev/null 2>&1; then - iptables "${table_args[@]}" -A "${chain}" "$@" - fi + "${IPTABLES[@]}" -N "${chain}" >/dev/null 2>&1 || true + "${IPTABLES[@]}" -F "${chain}" } EXT_IF="$(external_interface || true)" @@ -71,13 +67,32 @@ data: sysctl -w net.ipv4.ip_forward=1 + # Remove rules written by older revisions. In particular, the unqualified + # tailscale UDP DROP also blocks Flannel VXLAN (UDP/8472). delete_rule INPUT -i tailscale0 -p udp -m comment --comment amneziawg-block-tailscale -j DROP - ensure_insert_rule INPUT -i "${EXT_IF}" -p udp --dport "${PORT}" -m comment --comment amneziawg-allow-external -j ACCEPT - ensure_insert_rule INPUT -i tailscale0 -p udp --dport "${PORT}" -m comment --comment amneziawg-block-tailscale -j DROP - ensure_append_rule INPUT -i awg0 -m comment --comment amneziawg-awg-input -j ACCEPT - ensure_append_rule FORWARD -i awg0 -m comment --comment amneziawg-forward-in -j ACCEPT - ensure_append_rule FORWARD -o awg0 -m comment --comment amneziawg-forward-out -j ACCEPT - ensure_append_rule -t nat POSTROUTING -s "${VPN_CIDR}" -o "${EXT_IF}" -m comment --comment amneziawg-masquerade -j MASQUERADE + delete_rule INPUT -i "${EXT_IF}" -p udp -m comment --comment amneziawg-allow-external -j ACCEPT + delete_rule INPUT -i "${EXT_IF}" -p udp --dport "${PORT}" -m comment --comment amneziawg-allow-external -j ACCEPT + delete_rule INPUT -i tailscale0 -p udp --dport "${PORT}" -m comment --comment amneziawg-block-tailscale -j DROP + delete_rule INPUT -i awg0 -m comment --comment amneziawg-awg-input -j ACCEPT + delete_rule FORWARD -i awg0 -m comment --comment amneziawg-forward-in -j ACCEPT + delete_rule FORWARD -o awg0 -m comment --comment amneziawg-forward-out -j ACCEPT + + reset_chain "${INPUT_CHAIN}" + "${IPTABLES[@]}" -A "${INPUT_CHAIN}" -i "${EXT_IF}" -p udp --dport "${PORT}" -m comment --comment amneziawg-allow-external -j ACCEPT + "${IPTABLES[@]}" -A "${INPUT_CHAIN}" -i tailscale0 -p udp --dport "${PORT}" -m comment --comment amneziawg-block-tailscale -j DROP + "${IPTABLES[@]}" -A "${INPUT_CHAIN}" -i awg0 -m comment --comment amneziawg-awg-input -j ACCEPT + "${IPTABLES[@]}" -A "${INPUT_CHAIN}" -j RETURN + ensure_rule -I INPUT -m comment --comment amneziawg-input-jump -j "${INPUT_CHAIN}" + + reset_chain "${FORWARD_CHAIN}" + "${IPTABLES[@]}" -A "${FORWARD_CHAIN}" -i awg0 -m comment --comment amneziawg-forward-in -j ACCEPT + "${IPTABLES[@]}" -A "${FORWARD_CHAIN}" -o awg0 -m comment --comment amneziawg-forward-out -j ACCEPT + "${IPTABLES[@]}" -A "${FORWARD_CHAIN}" -j RETURN + ensure_rule -A FORWARD -m comment --comment amneziawg-forward-jump -j "${FORWARD_CHAIN}" + + ensure_rule -A -t nat POSTROUTING -s "${VPN_CIDR}" -o "${EXT_IF}" -m comment --comment amneziawg-masquerade -j MASQUERADE + + /scripts/firewall-check.sh "${PORT}" "${VPN_CIDR}" firewall-down.sh: | #!/usr/bin/env bash @@ -85,6 +100,9 @@ data: PORT="${1:-5847}" VPN_CIDR="${2:-10.8.0.0/16}" + INPUT_CHAIN="AMNEZIAWG-INPUT" + FORWARD_CHAIN="AMNEZIAWG-FORWARD" + IPTABLES=(iptables -w 30) external_interface() { ip route get 1.1.1.1 | awk '{for (i=1;i<=NF;i++) if ($i=="dev") {print $(i+1); exit}}' @@ -100,7 +118,7 @@ data: local chain="$1" shift - while iptables "${table_args[@]}" -D "${chain}" "$@" >/dev/null 2>&1; do + while "${IPTABLES[@]}" "${table_args[@]}" -D "${chain}" "$@" >/dev/null 2>&1; do true done } @@ -111,6 +129,7 @@ data: fi if [ -n "${EXT_IF}" ]; then + delete_rule INPUT -i "${EXT_IF}" -p udp -m comment --comment amneziawg-allow-external -j ACCEPT delete_rule INPUT -i "${EXT_IF}" -p udp --dport "${PORT}" -m comment --comment amneziawg-allow-external -j ACCEPT delete_rule -t nat POSTROUTING -s "${VPN_CIDR}" -o "${EXT_IF}" -m comment --comment amneziawg-masquerade -j MASQUERADE fi @@ -120,6 +139,57 @@ data: delete_rule INPUT -i awg0 -m comment --comment amneziawg-awg-input -j ACCEPT delete_rule FORWARD -i awg0 -m comment --comment amneziawg-forward-in -j ACCEPT delete_rule FORWARD -o awg0 -m comment --comment amneziawg-forward-out -j ACCEPT + delete_rule INPUT -m comment --comment amneziawg-input-jump -j "${INPUT_CHAIN}" + delete_rule FORWARD -m comment --comment amneziawg-forward-jump -j "${FORWARD_CHAIN}" + + "${IPTABLES[@]}" -F "${INPUT_CHAIN}" >/dev/null 2>&1 || true + "${IPTABLES[@]}" -X "${INPUT_CHAIN}" >/dev/null 2>&1 || true + "${IPTABLES[@]}" -F "${FORWARD_CHAIN}" >/dev/null 2>&1 || true + "${IPTABLES[@]}" -X "${FORWARD_CHAIN}" >/dev/null 2>&1 || true + + firewall-check.sh: | + #!/usr/bin/env bash + set -euo pipefail + + PORT="${1:-5847}" + VPN_CIDR="${2:-10.8.0.0/16}" + INPUT_CHAIN="AMNEZIAWG-INPUT" + FORWARD_CHAIN="AMNEZIAWG-FORWARD" + IPTABLES=(iptables -w 5) + + external_interface() { + ip route get 1.1.1.1 | awk '{for (i=1;i<=NF;i++) if ($i=="dev") {print $(i+1); exit}}' + } + + EXT_IF="$(external_interface || true)" + if [ -z "${EXT_IF}" ]; then + EXT_IF="$(ip route show default | awk '{print $5; exit}')" + fi + if [ -z "${EXT_IF}" ]; then + echo "Unable to detect external interface" >&2 + exit 1 + fi + + if "${IPTABLES[@]}" -C INPUT -i tailscale0 -p udp -m comment --comment amneziawg-block-tailscale -j DROP >/dev/null 2>&1; then + echo "Unsafe broad UDP DROP on tailscale0 is present" >&2 + exit 1 + fi + if "${IPTABLES[@]}" -C INPUT -i "${EXT_IF}" -p udp -m comment --comment amneziawg-allow-external -j ACCEPT >/dev/null 2>&1; then + echo "Unsafe broad UDP ACCEPT on ${EXT_IF} is present" >&2 + exit 1 + fi + + "${IPTABLES[@]}" -C INPUT -m comment --comment amneziawg-input-jump -j "${INPUT_CHAIN}" + "${IPTABLES[@]}" -C "${INPUT_CHAIN}" -i "${EXT_IF}" -p udp --dport "${PORT}" -m comment --comment amneziawg-allow-external -j ACCEPT + "${IPTABLES[@]}" -C "${INPUT_CHAIN}" -i tailscale0 -p udp --dport "${PORT}" -m comment --comment amneziawg-block-tailscale -j DROP + "${IPTABLES[@]}" -C "${INPUT_CHAIN}" -i awg0 -m comment --comment amneziawg-awg-input -j ACCEPT + + "${IPTABLES[@]}" -C FORWARD -m comment --comment amneziawg-forward-jump -j "${FORWARD_CHAIN}" + "${IPTABLES[@]}" -C "${FORWARD_CHAIN}" -i awg0 -m comment --comment amneziawg-forward-in -j ACCEPT + "${IPTABLES[@]}" -C "${FORWARD_CHAIN}" -o awg0 -m comment --comment amneziawg-forward-out -j ACCEPT + + "${IPTABLES[@]}" -t nat -C POSTROUTING -s "${VPN_CIDR}" -o "${EXT_IF}" -m comment --comment amneziawg-masquerade -j MASQUERADE + awg show awg0 >/dev/null 2>&1 run.sh: | #!/usr/bin/env bash diff --git a/k8s/apps/amnezia/daemonset.yaml b/k8s/apps/amnezia/daemonset.yaml index a536658..2a6414c 100644 --- a/k8s/apps/amnezia/daemonset.yaml +++ b/k8s/apps/amnezia/daemonset.yaml @@ -123,20 +123,20 @@ spec: command: - /bin/bash - -lc - - awg show awg0 >/dev/null 2>&1 + - /scripts/firewall-check.sh 5847 10.8.0.0/16 initialDelaySeconds: 5 periodSeconds: 10 - timeoutSeconds: 3 - failureThreshold: 3 + timeoutSeconds: 8 + failureThreshold: 2 livenessProbe: exec: command: - /bin/bash - -lc - - awg show awg0 >/dev/null 2>&1 + - /scripts/firewall-check.sh 5847 10.8.0.0/16 initialDelaySeconds: 30 periodSeconds: 30 - timeoutSeconds: 5 + timeoutSeconds: 8 failureThreshold: 3 resources: requests: