Redesign of the nft firewall based on an existing Ansible playbook for the same purpose.
This commit is contained in:
155
bin/fw-apply
155
bin/fw-apply
@@ -1,155 +0,0 @@
|
|||||||
#!/usr//bin/env bash
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
########################
|
|
||||||
# Args
|
|
||||||
########################
|
|
||||||
DO_APPLY=true
|
|
||||||
if [[ "${1:-}" == "--check" ]]; then
|
|
||||||
DO_APPLY=false
|
|
||||||
elif [[ "${1:-}" != "" ]]; then
|
|
||||||
echo "Usage: $0 [--check]" >&2
|
|
||||||
exit 2
|
|
||||||
fi
|
|
||||||
|
|
||||||
########################
|
|
||||||
# Defaults
|
|
||||||
########################
|
|
||||||
EXT_IF="eth0"
|
|
||||||
PRIV_IF="enp7s0"
|
|
||||||
PRIV_NET="172.20.0.0/21"
|
|
||||||
|
|
||||||
ALLOW_SSH_PUBLIC_IN=false
|
|
||||||
ALLOW_APT_PUBLIC_OUT=false
|
|
||||||
|
|
||||||
ALLOW_ICMP4_PUBLIC=true
|
|
||||||
ALLOW_ICMP6_PUBLIC=true
|
|
||||||
|
|
||||||
########################
|
|
||||||
# Optional config file
|
|
||||||
########################
|
|
||||||
CFG="/etc/default/nft-fw"
|
|
||||||
if [[ -r "$CFG" ]]; then
|
|
||||||
# shellcheck disable=SC1090
|
|
||||||
source "$CFG"
|
|
||||||
fi
|
|
||||||
|
|
||||||
########################
|
|
||||||
# Normalize booleans
|
|
||||||
########################
|
|
||||||
normalize_bool() {
|
|
||||||
# trim whitespace + remove CR (Windows line endings)
|
|
||||||
local v
|
|
||||||
v="$(printf '%s' "${1:-}" | tr -d '\r' | xargs)"
|
|
||||||
case "${v,,}" in
|
|
||||||
true|yes|1) echo true ;;
|
|
||||||
false|no|0|"") echo false ;;
|
|
||||||
*) echo false ;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
|
|
||||||
ALLOW_ICMP4_PUBLIC="$(normalize_bool "${ALLOW_ICMP4_PUBLIC:-true}")"
|
|
||||||
ALLOW_ICMP6_PUBLIC="$(normalize_bool "${ALLOW_ICMP6_PUBLIC:-true}")"
|
|
||||||
ALLOW_SSH_PUBLIC_IN="$(normalize_bool "${ALLOW_SSH_PUBLIC_IN:-false}")"
|
|
||||||
ALLOW_APT_PUBLIC_OUT="$(normalize_bool "${ALLOW_APT_PUBLIC_OUT:-false}")"
|
|
||||||
|
|
||||||
|
|
||||||
NEED_EXT=false
|
|
||||||
if [[ "$ALLOW_SSH_PUBLIC_IN" == "true" || "$ALLOW_APT_PUBLIC_OUT" == "true" || "$ALLOW_ICMP4_PUBLIC" == "true" || "$ALLOW_ICMP6_PUBLIC" == "true" ]]; then
|
|
||||||
NEED_EXT=true
|
|
||||||
fi
|
|
||||||
|
|
||||||
EFFECTIVE_ALLOW_ICMP6_PUBLIC="$ALLOW_ICMP6_PUBLIC"
|
|
||||||
if [[ "$NEED_EXT" == "true" ]]; then
|
|
||||||
EFFECTIVE_ALLOW_ICMP6_PUBLIC=true
|
|
||||||
fi
|
|
||||||
|
|
||||||
########################
|
|
||||||
# Build optional rule blocks
|
|
||||||
########################
|
|
||||||
ICMP_PUBLIC_IN_RULES=""
|
|
||||||
ICMP_PUBLIC_OUT_RULES=""
|
|
||||||
SSH_PUBLIC_IN_RULE=""
|
|
||||||
APT_PUBLIC_OUT_RULES=""
|
|
||||||
|
|
||||||
|
|
||||||
# ICMPv4 optional
|
|
||||||
if [[ "$ALLOW_ICMP4_PUBLIC" == "true" ]]; then
|
|
||||||
ICMP_PUBLIC_IN_RULES="$(cat <<EOF
|
|
||||||
iif "$EXT_IF" ip protocol icmp accept
|
|
||||||
EOF
|
|
||||||
)"
|
|
||||||
ICMP_PUBLIC_OUT_RULES="$(cat <<EOF
|
|
||||||
oif "$EXT_IF" ip protocol icmp accept
|
|
||||||
EOF
|
|
||||||
)"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ICMPv6 optional (oder erzwungen über EFFECTIVE_ALLOW_ICMP6_PUBLIC)
|
|
||||||
if [[ "$EFFECTIVE_ALLOW_ICMP6_PUBLIC" == "true" ]]; then
|
|
||||||
# Falls schon was drin ist, füge sauber eine Leerzeile/Zeilenumbruch hinzu
|
|
||||||
[[ -n "$ICMP_PUBLIC_IN_RULES" ]] && ICMP_PUBLIC_IN_RULES+=$'\n'
|
|
||||||
[[ -n "$ICMP_PUBLIC_OUT_RULES" ]] && ICMP_PUBLIC_OUT_RULES+=$'\n'
|
|
||||||
|
|
||||||
ICMP_PUBLIC_IN_RULES+=$(cat <<EOF
|
|
||||||
iif "$EXT_IF" ip6 nexthdr icmpv6 accept
|
|
||||||
EOF
|
|
||||||
)
|
|
||||||
ICMP_PUBLIC_OUT_RULES+=$(cat <<EOF
|
|
||||||
oif "$EXT_IF" ip6 nexthdr icmpv6 accept
|
|
||||||
EOF
|
|
||||||
)
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
if [[ "$ALLOW_SSH_PUBLIC_IN" == "true" ]]; then
|
|
||||||
SSH_PUBLIC_IN_RULE="$(cat <<EOF
|
|
||||||
iif "$EXT_IF" tcp dport 22 accept
|
|
||||||
EOF
|
|
||||||
)"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ "$ALLOW_APT_PUBLIC_OUT" == "true" ]]; then
|
|
||||||
APT_PUBLIC_OUT_RULES="$(cat <<EOF
|
|
||||||
oif "$EXT_IF" udp dport 53 accept
|
|
||||||
oif "$EXT_IF" tcp dport 53 accept
|
|
||||||
oif "$EXT_IF" tcp dport { 80, 443 } accept
|
|
||||||
EOF
|
|
||||||
)"
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
export EXT_IF PRIV_IF PRIV_NET
|
|
||||||
export ICMP_PUBLIC_IN_RULES ICMP_PUBLIC_OUT_RULES
|
|
||||||
export SSH_PUBLIC_IN_RULE APT_PUBLIC_OUT_RULES
|
|
||||||
|
|
||||||
########################
|
|
||||||
# Render
|
|
||||||
########################
|
|
||||||
TMP="$(mktemp -p /run nft-fw.XXXXXX)"
|
|
||||||
trap 'rm -f "$TMP"' EXIT
|
|
||||||
|
|
||||||
envsubst < /etc/nftables.conf.in > "$TMP"
|
|
||||||
|
|
||||||
########################
|
|
||||||
# Remove only our table (do NOT touch fail2ban)
|
|
||||||
########################
|
|
||||||
nft delete table inet fw_static 2>/dev/null || true
|
|
||||||
|
|
||||||
########################
|
|
||||||
# Validate + apply
|
|
||||||
########################
|
|
||||||
nft -c -f "$TMP"
|
|
||||||
|
|
||||||
if [[ "$DO_APPLY" == "true" ]]; then
|
|
||||||
nft -f "$TMP"
|
|
||||||
install -m 600 "$TMP" /etc/nftables.conf
|
|
||||||
else
|
|
||||||
echo ""
|
|
||||||
echo " fw-apply: check mode"
|
|
||||||
[[ -r "$CFG" ]] && echo " - config loaded: $CFG" || echo " - config loaded: defaults only"
|
|
||||||
echo " - rendered nftables ruleset: OK"
|
|
||||||
echo " - syntax check (nft -c): OK"
|
|
||||||
echo " - no changes applied"
|
|
||||||
echo ""
|
|
||||||
fi
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
# Enstferne
|
|
||||||
nft delete table inet fw_static 2>/dev/null || true
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
# Öffentliches Interface
|
|
||||||
EXT_IF=eth0
|
|
||||||
|
|
||||||
# Privates Interface
|
|
||||||
PRIV_IF=enp7s0
|
|
||||||
|
|
||||||
# Privates Netz
|
|
||||||
PRIV_NET=172.20.0.0/21
|
|
||||||
|
|
||||||
# Public access toggles
|
|
||||||
ALLOW_SSH_PUBLIC_IN=true
|
|
||||||
ALLOW_APT_PUBLIC_OUT=true
|
|
||||||
|
|
||||||
# ICMP toggles (separat)
|
|
||||||
ALLOW_ICMP4_PUBLIC=true
|
|
||||||
ALLOW_ICMP6_PUBLIC=true
|
|
||||||
22
etc-nftables.conf.d/nft-fw.conf
Normal file
22
etc-nftables.conf.d/nft-fw.conf
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
# Host-specific configuration for nft-fw.
|
||||||
|
# This file is read by /usr/local/sbin/fw-apply.
|
||||||
|
#
|
||||||
|
# Syntax: shell KEY=VALUE
|
||||||
|
# Values "true/false" are parsed case-insensitively.
|
||||||
|
|
||||||
|
# Interfaces / networks
|
||||||
|
EXT_IF=eth0
|
||||||
|
PRIV_IF=enp7s0
|
||||||
|
PRIV_NET=172.20.0.0/21
|
||||||
|
|
||||||
|
# Feature toggles
|
||||||
|
ALLOW_SSH_PUBLIC_IN=true
|
||||||
|
ALLOW_APT_PUBLIC_OUT=true
|
||||||
|
|
||||||
|
# ICMP toggles
|
||||||
|
ALLOW_ICMP4_PUBLIC=true
|
||||||
|
ALLOW_ICMP6_PUBLIC=true
|
||||||
|
|
||||||
|
# Force ICMPv6 essential types when EXT_IF is "in use" (SSH or APT enabled)
|
||||||
|
FORCE_ICMP6_ESSENTIAL=true
|
||||||
|
|
||||||
11
install.sh
11
install.sh
@@ -7,18 +7,19 @@ say(){ echo "[nft-fw-nd-priv] $*"; }
|
|||||||
|
|
||||||
say "Creating directories..."
|
say "Creating directories..."
|
||||||
install -d -m 0755 /usr/local/sbin
|
install -d -m 0755 /usr/local/sbin
|
||||||
|
install -d -m 0755 /etc/nftables.conf.d
|
||||||
|
|
||||||
say "Installing template..."
|
say "Installing template..."
|
||||||
install -m 0644 "$REPO_DIR/templates/nftables.conf.in" /etc/nftables.conf.in
|
install -m 0644 "$REPO_DIR/templates/nftables.conf.in" /etc/nftables.conf.in
|
||||||
|
|
||||||
say "Installing scripts..."
|
say "Installing scripts..."
|
||||||
install -m 0755 "$REPO_DIR/bin/fw-apply" /usr/local/sbin/fw-apply
|
install -m 0755 "$REPO_DIR/sbin/fw-apply" /usr/local/sbin/fw-apply
|
||||||
install -m 0755 "$REPO_DIR/bin/fw-stop" /usr/local/sbin/fw-stop
|
install -m 0755 "$REPO_DIR/sbin/fw-stop" /usr/local/sbin/fw-stop
|
||||||
|
|
||||||
|
|
||||||
say "Installing default config (won't overwrite existing)..."
|
say "Installing default config (won't overwrite existing)..."
|
||||||
if [[ ! -f /etc/default/nft-fw ]]; then
|
if [[ ! -f /etc/nftables.conf.d/nft-fw.conf ]]; then
|
||||||
install -m 0644 "$REPO_DIR/etc-default/nft-fw" /etc/default/nft-fw
|
install -m 0644 "$REPO_DIR/etc-nftables.conf.d/nft-fw.conf" /etc/nftables.conf.d/nft-fw.conf
|
||||||
else
|
else
|
||||||
say "Config already exists at /etc/default/nft-fw (leaving as-is)."
|
say "Config already exists at /etc/default/nft-fw (leaving as-is)."
|
||||||
fi
|
fi
|
||||||
@@ -66,6 +67,6 @@ fi
|
|||||||
say "Applying firewall now..."
|
say "Applying firewall now..."
|
||||||
/usr/local/sbin/fw-apply
|
/usr/local/sbin/fw-apply
|
||||||
|
|
||||||
say "Done. Edit /etc/default/nft-fw-nd-priv and re-run: fw-apply"
|
say "Done. Edit /etc/nftables.conf.d/nft-fw.conf and re-run: fw-apply"
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -73,8 +73,13 @@ backup_then_remove /usr/local/sbin/fw-stop
|
|||||||
say "Removing template..."
|
say "Removing template..."
|
||||||
backup_then_remove /etc/nftables.conf.in
|
backup_then_remove /etc/nftables.conf.in
|
||||||
|
|
||||||
say "Removing default config..."
|
say "Removing config..."
|
||||||
backup_then_remove /etc/default/nft-fw
|
backup_then_remove /etc/nftables.conf.d/nft-fw.conf
|
||||||
|
backup_then_remove /etc/nftables.conf
|
||||||
|
|
||||||
|
if ! rmdir /etc/nftables.conf.d 2>/dev/null; then
|
||||||
|
say "Directory '/etc/nftables.conf.d' could not be deleted because it is not empty."
|
||||||
|
fi
|
||||||
|
|
||||||
say "Removing systemd unit file..."
|
say "Removing systemd unit file..."
|
||||||
backup_then_remove /etc/systemd/system/nft-fw.service
|
backup_then_remove /etc/systemd/system/nft-fw.service
|
||||||
|
|||||||
193
sbin/fw-apply
Executable file
193
sbin/fw-apply
Executable file
@@ -0,0 +1,193 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# *** [ Ansible managed file: DO NOT EDIT DIRECTLY ] ***
|
||||||
|
|
||||||
|
#
|
||||||
|
# fw-apply
|
||||||
|
#
|
||||||
|
# Generic firewall loader (Ansible-independent):
|
||||||
|
# - Reads config from /etc/nftables.conf.d/nft-fw.conf (optional)
|
||||||
|
# - Renders /etc/nftables.conf.in using envsubst
|
||||||
|
# - Validates with: nft -c -f <rendered>
|
||||||
|
# - Applies by deleting ONLY table inet fw_static and loading the new definition
|
||||||
|
# (keeps fail2ban tables intact)
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# fw-apply -> validate + apply
|
||||||
|
# fw-apply --check -> validate only (no changes)
|
||||||
|
#
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
############################
|
||||||
|
# Argument handling
|
||||||
|
############################
|
||||||
|
DO_APPLY=true
|
||||||
|
if [[ "${1:-}" == "--check" ]]; then
|
||||||
|
DO_APPLY=false
|
||||||
|
elif [[ "${1:-}" != "" ]]; then
|
||||||
|
echo "Usage: $0 [--check]" >&2
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
############################
|
||||||
|
# Config location
|
||||||
|
############################
|
||||||
|
CFG_DIR="/etc/nftables.conf.d"
|
||||||
|
CFG_FILE="$CFG_DIR/nft-fw.conf"
|
||||||
|
|
||||||
|
############################
|
||||||
|
# Defaults (used if config missing/partial)
|
||||||
|
############################
|
||||||
|
EXT_IF="eth0"
|
||||||
|
PRIV_IF="enp7s0"
|
||||||
|
PRIV_NET="172.20.0.0/21"
|
||||||
|
|
||||||
|
ALLOW_SSH_PUBLIC_IN="true"
|
||||||
|
ALLOW_APT_PUBLIC_OUT="true"
|
||||||
|
|
||||||
|
ALLOW_ICMP4_PUBLIC="true"
|
||||||
|
ALLOW_ICMP6_PUBLIC="true"
|
||||||
|
FORCE_ICMP6_ESSENTIAL="true"
|
||||||
|
|
||||||
|
############################
|
||||||
|
# Load config if present
|
||||||
|
############################
|
||||||
|
if [[ -r "$CFG_FILE" ]]; then
|
||||||
|
# shellcheck disable=SC1090
|
||||||
|
source "$CFG_FILE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
############################
|
||||||
|
# Helpers
|
||||||
|
############################
|
||||||
|
normalize_bool() {
|
||||||
|
# Robust against CRLF and leading/trailing whitespace.
|
||||||
|
local v
|
||||||
|
v="$(printf '%s' "${1:-}" | tr -d '\r' | xargs)"
|
||||||
|
case "${v,,}" in
|
||||||
|
true|yes|1) echo true ;;
|
||||||
|
false|no|0|"") echo false ;;
|
||||||
|
*) echo false ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
ALLOW_SSH_PUBLIC_IN="$(normalize_bool "$ALLOW_SSH_PUBLIC_IN")"
|
||||||
|
ALLOW_APT_PUBLIC_OUT="$(normalize_bool "$ALLOW_APT_PUBLIC_OUT")"
|
||||||
|
ALLOW_ICMP4_PUBLIC="$(normalize_bool "$ALLOW_ICMP4_PUBLIC")"
|
||||||
|
ALLOW_ICMP6_PUBLIC="$(normalize_bool "$ALLOW_ICMP6_PUBLIC")"
|
||||||
|
FORCE_ICMP6_ESSENTIAL="$(normalize_bool "$FORCE_ICMP6_ESSENTIAL")"
|
||||||
|
|
||||||
|
############################
|
||||||
|
# Determine external usage
|
||||||
|
############################
|
||||||
|
# EXT_IF is considered "in use" if any externally-relevant feature is enabled.
|
||||||
|
NEED_EXT=false
|
||||||
|
if [[ "$ALLOW_SSH_PUBLIC_IN" == "true" || "$ALLOW_APT_PUBLIC_OUT" == "true" ]]; then
|
||||||
|
NEED_EXT=true
|
||||||
|
fi
|
||||||
|
|
||||||
|
############################
|
||||||
|
# Build envsubst blocks (must contain REAL newlines)
|
||||||
|
############################
|
||||||
|
SSH_PUBLIC_IN_RULE=""
|
||||||
|
APT_PUBLIC_OUT_RULES=""
|
||||||
|
ICMP_PUBLIC_IN_RULES=""
|
||||||
|
ICMP_PUBLIC_OUT_RULES=""
|
||||||
|
|
||||||
|
# SSH IN (public)
|
||||||
|
if [[ "$ALLOW_SSH_PUBLIC_IN" == "true" ]]; then
|
||||||
|
SSH_PUBLIC_IN_RULE="$(cat <<EOF
|
||||||
|
iif "$EXT_IF" tcp dport 22 accept
|
||||||
|
EOF
|
||||||
|
)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# APT OUT (public) - DNS + HTTP/HTTPS
|
||||||
|
if [[ "$ALLOW_APT_PUBLIC_OUT" == "true" ]]; then
|
||||||
|
APT_PUBLIC_OUT_RULES="$(cat <<EOF
|
||||||
|
oif "$EXT_IF" udp dport 53 accept
|
||||||
|
oif "$EXT_IF" tcp dport 53 accept
|
||||||
|
oif "$EXT_IF" tcp dport { 80, 443 } accept
|
||||||
|
EOF
|
||||||
|
)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ICMPv4 echo
|
||||||
|
if [[ "$ALLOW_ICMP4_PUBLIC" == "true" ]]; then
|
||||||
|
ICMP_PUBLIC_IN_RULES="$(cat <<EOF
|
||||||
|
iif "$EXT_IF" ip protocol icmp accept
|
||||||
|
EOF
|
||||||
|
)"
|
||||||
|
ICMP_PUBLIC_OUT_RULES="$(cat <<EOF
|
||||||
|
oif "$EXT_IF" ip protocol icmp accept
|
||||||
|
EOF
|
||||||
|
)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ICMPv6 essential (no echo) if EXT used and forcing enabled
|
||||||
|
ALLOW_ICMP6_ESSENTIAL=false
|
||||||
|
if [[ "$FORCE_ICMP6_ESSENTIAL" == "true" && "$NEED_EXT" == "true" ]]; then
|
||||||
|
ALLOW_ICMP6_ESSENTIAL=true
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$ALLOW_ICMP6_ESSENTIAL" == "true" ]]; then
|
||||||
|
[[ -n "$ICMP_PUBLIC_IN_RULES" ]] && ICMP_PUBLIC_IN_RULES+=$'\n'
|
||||||
|
[[ -n "$ICMP_PUBLIC_OUT_RULES" ]] && ICMP_PUBLIC_OUT_RULES+=$'\n'
|
||||||
|
|
||||||
|
ICMP_PUBLIC_IN_RULES+=$(cat <<EOF
|
||||||
|
iif "$EXT_IF" icmpv6 type { nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, nd-redirect, packet-too-big, time-exceeded, parameter-problem, destination-unreachable } accept
|
||||||
|
EOF
|
||||||
|
)
|
||||||
|
ICMP_PUBLIC_OUT_RULES+=$(cat <<EOF
|
||||||
|
oif "$EXT_IF" icmpv6 type { nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, nd-redirect, packet-too-big, time-exceeded, parameter-problem, destination-unreachable } accept
|
||||||
|
EOF
|
||||||
|
)
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ICMPv6 echo (ping6)
|
||||||
|
if [[ "$ALLOW_ICMP6_PUBLIC" == "true" ]]; then
|
||||||
|
[[ -n "$ICMP_PUBLIC_IN_RULES" ]] && ICMP_PUBLIC_IN_RULES+=$'\n'
|
||||||
|
[[ -n "$ICMP_PUBLIC_OUT_RULES" ]] && ICMP_PUBLIC_OUT_RULES+=$'\n'
|
||||||
|
|
||||||
|
ICMP_PUBLIC_IN_RULES+=$(cat <<EOF
|
||||||
|
iif "$EXT_IF" icmpv6 type { echo-request, echo-reply } accept
|
||||||
|
EOF
|
||||||
|
)
|
||||||
|
ICMP_PUBLIC_OUT_RULES+=$(cat <<EOF
|
||||||
|
oif "$EXT_IF" icmpv6 type { echo-request, echo-reply } accept
|
||||||
|
EOF
|
||||||
|
)
|
||||||
|
fi
|
||||||
|
|
||||||
|
############################
|
||||||
|
# Export for envsubst
|
||||||
|
############################
|
||||||
|
export EXT_IF PRIV_IF PRIV_NET
|
||||||
|
export SSH_PUBLIC_IN_RULE APT_PUBLIC_OUT_RULES
|
||||||
|
export ICMP_PUBLIC_IN_RULES ICMP_PUBLIC_OUT_RULES
|
||||||
|
|
||||||
|
############################
|
||||||
|
# Render + validate + apply
|
||||||
|
############################
|
||||||
|
TMP="$(mktemp -p /run nft-fw.XXXXXX)"
|
||||||
|
trap 'rm -f "$TMP"' EXIT
|
||||||
|
|
||||||
|
envsubst < /etc/nftables.conf.in > "$TMP"
|
||||||
|
|
||||||
|
# Replace only our table (keep fail2ban intact)
|
||||||
|
nft delete table inet fw_static 2>/dev/null || true
|
||||||
|
|
||||||
|
# Validate syntax
|
||||||
|
nft -c -f "$TMP"
|
||||||
|
|
||||||
|
if [[ "$DO_APPLY" == "true" ]]; then
|
||||||
|
nft -f "$TMP"
|
||||||
|
install -m 600 "$TMP" /etc/nftables.conf
|
||||||
|
else
|
||||||
|
echo "fw-apply: check mode"
|
||||||
|
[[ -r "$CFG_FILE" ]] && echo "- config loaded: $CFG_FILE" || echo "- config loaded: defaults only"
|
||||||
|
echo "- rendered nftables ruleset: OK"
|
||||||
|
echo "- syntax check (nft -c): OK"
|
||||||
|
echo "- no changes applied"
|
||||||
|
fi
|
||||||
|
|
||||||
8
sbin/fw-stop
Executable file
8
sbin/fw-stop
Executable file
@@ -0,0 +1,8 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# *** [ Ansible managed file: DO NOT EDIT DIRECTLY ] ***
|
||||||
|
|
||||||
|
|
||||||
|
nft delete table inet fw_static 2>/dev/null || true
|
||||||
|
|
||||||
@@ -2,7 +2,6 @@
|
|||||||
Description=Apply nftables firewall (parameterized)
|
Description=Apply nftables firewall (parameterized)
|
||||||
Documentation=man:nft(8)
|
Documentation=man:nft(8)
|
||||||
After=local-fs.target
|
After=local-fs.target
|
||||||
Wants=network-pre.target
|
|
||||||
Before=network-pre.target
|
Before=network-pre.target
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
@@ -14,3 +13,4 @@ PrivateTmp=yes
|
|||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=multi-user.target
|
WantedBy=multi-user.target
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,13 @@
|
|||||||
#!/usr/sbin/nft -f
|
#!/usr/sbin/nft -f
|
||||||
|
|
||||||
|
#
|
||||||
|
# Static firewall template.
|
||||||
|
# This file contains shell-style placeholders ($VARS) that are replaced by fw-apply via envsubst.
|
||||||
|
#
|
||||||
|
# Important:
|
||||||
|
# - We only manage table inet fw_static.
|
||||||
|
# - We do NOT flush the entire ruleset (fail2ban rules remain intact).
|
||||||
|
|
||||||
table inet fw_static {
|
table inet fw_static {
|
||||||
|
|
||||||
chain input {
|
chain input {
|
||||||
@@ -11,10 +19,8 @@ table inet fw_static {
|
|||||||
|
|
||||||
# Public: ICMP (optional)
|
# Public: ICMP (optional)
|
||||||
$ICMP_PUBLIC_IN_RULES
|
$ICMP_PUBLIC_IN_RULES
|
||||||
|
|
||||||
# Public: SSH IN (optional)
|
# Public: SSH IN (optional)
|
||||||
$SSH_PUBLIC_IN_RULE
|
$SSH_PUBLIC_IN_RULE
|
||||||
|
|
||||||
# Private network (in)
|
# Private network (in)
|
||||||
iif "$PRIV_IF" ip saddr $PRIV_NET accept
|
iif "$PRIV_IF" ip saddr $PRIV_NET accept
|
||||||
}
|
}
|
||||||
@@ -26,12 +32,10 @@ $SSH_PUBLIC_IN_RULE
|
|||||||
oif "lo" accept
|
oif "lo" accept
|
||||||
ct state established,related accept
|
ct state established,related accept
|
||||||
|
|
||||||
# Public: ICMP (optional)
|
# Public: ICMP (optional)
|
||||||
$ICMP_PUBLIC_OUT_RULES
|
$ICMP_PUBLIC_OUT_RULES
|
||||||
|
|
||||||
# Public: APT OUT (optional) - includes DNS + HTTP/HTTPS
|
# Public: APT OUT (optional) - includes DNS + HTTP/HTTPS
|
||||||
$APT_PUBLIC_OUT_RULES
|
$APT_PUBLIC_OUT_RULES
|
||||||
|
|
||||||
# Private network (out)
|
# Private network (out)
|
||||||
oif "$PRIV_IF" ip daddr $PRIV_NET accept
|
oif "$PRIV_IF" ip daddr $PRIV_NET accept
|
||||||
}
|
}
|
||||||
@@ -41,3 +45,4 @@ $APT_PUBLIC_OUT_RULES
|
|||||||
policy drop;
|
policy drop;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user