Skip to content

feat: add initial iptables rules via NetworkManager dispatcher#1213

Open
mingshuoqiu wants to merge 3 commits intoharvester:masterfrom
mingshuoqiu:issue_5681_v2
Open

feat: add initial iptables rules via NetworkManager dispatcher#1213
mingshuoqiu wants to merge 3 commits intoharvester:masterfrom
mingshuoqiu:issue_5681_v2

Conversation

@mingshuoqiu
Copy link
Copy Markdown
Contributor

Problem:

There should be a way to blacklist external network or whitelist the Harvester node network only to protection from malicious scan and access.

Solution:

This commit introduces a NetworkManager dispatcher script to apply initial iptables rules when network interfaces are brought up.

This commit introduces a NetworkManager dispatcher script to apply initial iptables rules when network interfaces are brought up. Creating two custom chains:

  • HARVESTER_ESSENTIAL: Contains core rules required for Harvester and RKE2 functionality (SSH, K8s API, VXLAN, etc.).
  • HARVESTER_DYNAMIC: A placeholder chain for users or external components

Related Issue(s):

harvester/harvester#5681

Test plan:

Should include all feature as follows which should be broken into details

  • Core Cluster Functionalities
  • Storage Network Tests
  • VM Operation Tests
  • External Integration Tests
    • Rancher management and other Cloud Providers
  • Security Tests
    • Use checkmk or nmap scan against nodes

Additional documentation or context

Copilot AI review requested due to automatic review settings January 2, 2026 06:37
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a NetworkManager dispatcher script to automatically apply iptables firewall rules when network interfaces come up, implementing network security controls for Harvester nodes. The solution creates custom iptables chains to manage both essential system rules and user-extensible rules.

Key changes:

  • Adds a dispatcher script that runs on interface up events to configure iptables rules
  • Creates two custom chains: HARVESTER_ESSENTIAL (core Harvester/RKE2 rules) and HARVESTER_DYNAMIC (placeholder for external use)
  • Implements role-based firewall rules that differentiate between server and agent nodes, with default DROP policies for INPUT and FORWARD chains

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +17 to +18
add_rule INPUT -j HARVESTER_ESSENTIAL
add_rule INPUT -j HARVESTER_DYNAMIC
Copy link

Copilot AI Jan 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The jump rules to HARVESTER_ESSENTIAL and HARVESTER_DYNAMIC are added to INPUT chain before the HARVESTER_ESSENTIAL chain is populated with rules. Since add_rule uses iptables -A (append), if this script runs multiple times, the jump rules will be added again at the end of the INPUT chain, even though earlier jumps exist. This creates redundant chain jumps that will process the same packets multiple times unnecessarily.

Copilot uses AI. Check for mistakes.
Comment on lines +77 to +79
# Set default policies
iptables -P INPUT DROP
iptables -P FORWARD DROP
Copy link

Copilot AI Jan 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Setting default policies to DROP at the end of the script creates a critical race condition. If the script fails or is interrupted after line 78 but before completing, or if there's any error in rule application, the system will have DROP policies in place without the necessary ACCEPT rules, potentially locking out all network access including SSH. The default policies should only be set after confirming all rules are successfully applied, or should be set conditionally.

Suggested change
# Set default policies
iptables -P INPUT DROP
iptables -P FORWARD DROP
# Set default policies only if essential rules (e.g., SSH) are present
if iptables -C HARVESTER_ESSENTIAL -p tcp --dport 22 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT 2>/dev/null; then
iptables -P INPUT DROP
iptables -P FORWARD DROP
fi

Copilot uses AI. Check for mistakes.

# Create custom chains
iptables -N HARVESTER_ESSENTIAL 2>/dev/null
iptables -N HARVESTER_DYNAMIC 2>/dev/null
Copy link

Copilot AI Jan 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The HARVESTER_DYNAMIC chain is created and referenced but never populated with any rules in this script. While the description mentions it's a "placeholder chain for users or external components," there's no documentation in the script itself explaining its purpose, how external components should use it, or any guarantees about its persistence. Add comments explaining the intended usage pattern for this chain.

Copilot uses AI. Check for mistakes.

# Set default policies
iptables -P INPUT DROP
iptables -P FORWARD DROP
Copy link

Copilot AI Jan 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The default DROP policy for the FORWARD chain at line 79 may break container networking and VM traffic that relies on forwarding. Kubernetes and KVM virtual machines typically require packet forwarding to function. While there's a RELATED,ESTABLISHED rule at line 75, there's no rule to allow NEW connections for forwarded traffic, which could break legitimate traffic between containers/VMs and external networks.

Copilot uses AI. Check for mistakes.
Comment on lines +12 to +14
add_rule() {
iptables -C "$@" 2>/dev/null || iptables -A "$@"
}
Copy link

Copilot AI Jan 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The add_rule helper function adds rules using iptables -A (append), but after flushing HARVESTER_ESSENTIAL at line 21, all subsequent add_rule calls for this chain will succeed because the chain is empty. The check 'iptables -C' will never find existing rules in a just-flushed chain, making the check redundant for HARVESTER_ESSENTIAL. This pattern only provides protection for rules added to INPUT, FORWARD, and HARVESTER_DYNAMIC chains.

Copilot uses AI. Check for mistakes.
Comment on lines +39 to +41
add_rule HARVESTER_ESSENTIAL -p tcp --dport 80 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
add_rule HARVESTER_ESSENTIAL -p tcp --dport 443 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
add_rule HARVESTER_ESSENTIAL -p tcp --dport 22 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
Copy link

Copilot AI Jan 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rules for ports 80 and 443 include explicit conntrack state matching with NEW,ESTABLISHED, while most other rules only use ACCEPT without state matching (or rely on the earlier ESTABLISHED,RELATED rule at line 35). This inconsistency is confusing - either all NEW connection rules should explicitly check state, or the redundant state checking for ports 80 and 443 should be removed since line 35 already handles ESTABLISHED connections.

Suggested change
add_rule HARVESTER_ESSENTIAL -p tcp --dport 80 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
add_rule HARVESTER_ESSENTIAL -p tcp --dport 443 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
add_rule HARVESTER_ESSENTIAL -p tcp --dport 22 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
add_rule HARVESTER_ESSENTIAL -p tcp --dport 80 -j ACCEPT
add_rule HARVESTER_ESSENTIAL -p tcp --dport 443 -j ACCEPT
add_rule HARVESTER_ESSENTIAL -p tcp --dport 22 -j ACCEPT

Copilot uses AI. Check for mistakes.
Comment on lines +7 to +15
# Create custom chains
iptables -N HARVESTER_ESSENTIAL 2>/dev/null
iptables -N HARVESTER_DYNAMIC 2>/dev/null

# Helper to add rule if missing
add_rule() {
iptables -C "$@" 2>/dev/null || iptables -A "$@"
}

Copy link

Copilot AI Jan 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The script creates custom chains with 'iptables -N' and redirects errors to /dev/null, which suppresses the error when chains already exist. However, there's no verification that the chains were successfully created or that they exist before attempting to use them. If iptables command fails for other reasons (e.g., missing iptables binary, permission issues), the script will continue silently and fail when trying to add rules to non-existent chains.

Suggested change
# Create custom chains
iptables -N HARVESTER_ESSENTIAL 2>/dev/null
iptables -N HARVESTER_DYNAMIC 2>/dev/null
# Helper to add rule if missing
add_rule() {
iptables -C "$@" 2>/dev/null || iptables -A "$@"
}
# Helper to ensure a chain exists (create it if missing)
ensure_chain() {
chain="$1"
# Check if the chain already exists
if ! iptables -L "$chain" >/dev/null 2>&1; then
# Attempt to create the chain; if this fails, abort with an error
if ! iptables -N "$chain" >/dev/null 2>&1; then
echo "Failed to ensure iptables chain '$chain' exists" >&2
exit 1
fi
fi
}
# Helper to add rule if missing
add_rule() {
iptables -C "$@" 2>/dev/null || iptables -A "$@"
}
# Ensure custom chains exist
ensure_chain HARVESTER_ESSENTIAL
ensure_chain HARVESTER_DYNAMIC

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +79
#!/bin/sh

if [ "$2" != "up" ]; then
exit 0
fi

# Create custom chains
iptables -N HARVESTER_ESSENTIAL 2>/dev/null
iptables -N HARVESTER_DYNAMIC 2>/dev/null

# Helper to add rule if missing
add_rule() {
iptables -C "$@" 2>/dev/null || iptables -A "$@"
}

# Ensure INPUT chain jumps to our custom chains
add_rule INPUT -j HARVESTER_ESSENTIAL
add_rule INPUT -j HARVESTER_DYNAMIC

# Flush HARVESTER_ESSENTIAL to ensure clean state
iptables -F HARVESTER_ESSENTIAL

# --- Rules for HARVESTER_ESSENTIAL ---

# Allow loopback
add_rule HARVESTER_ESSENTIAL -i lo -j ACCEPT

# Allow ICMP (Ping)
add_rule HARVESTER_ESSENTIAL -p icmp -j ACCEPT

# Allow VRRP (Keepalived)
add_rule HARVESTER_ESSENTIAL -p vrrp -j ACCEPT

# Allow Established/Related connections
add_rule HARVESTER_ESSENTIAL -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

# Common Rules
# TCP 80, 443, 22
add_rule HARVESTER_ESSENTIAL -p tcp --dport 80 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
add_rule HARVESTER_ESSENTIAL -p tcp --dport 443 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
add_rule HARVESTER_ESSENTIAL -p tcp --dport 22 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT

# UDP 8472 (VXLAN)
add_rule HARVESTER_ESSENTIAL -p udp --dport 8472 -j ACCEPT

# K8s/RKE2 Common
add_rule HARVESTER_ESSENTIAL -p tcp -m multiport --dports 6443:6444 -j ACCEPT
add_rule HARVESTER_ESSENTIAL -p tcp -m multiport --dports 10248:10250 -j ACCEPT
add_rule HARVESTER_ESSENTIAL -p tcp --dport 10010 -j ACCEPT
add_rule HARVESTER_ESSENTIAL -p tcp --dport 9099 -j ACCEPT

# Determine role and apply specific rules
IS_SERVER=false
if systemctl is-enabled rke2-server.service 2>/dev/null | grep -q enabled; then
IS_SERVER=true
elif systemctl is-active rke2-server.service 2>/dev/null | grep -q active; then
IS_SERVER=true
fi

if [ "$IS_SERVER" = "true" ]; then
# Master/Server specific
add_rule HARVESTER_ESSENTIAL -p tcp --dport 9345 -j ACCEPT
add_rule HARVESTER_ESSENTIAL -p tcp -m multiport --dports 10256:10260 -j ACCEPT
add_rule HARVESTER_ESSENTIAL -p tcp -m multiport --dports 2379:2382 -j ACCEPT
add_rule HARVESTER_ESSENTIAL -p tcp --dport 9091 -j ACCEPT
add_rule HARVESTER_ESSENTIAL -p tcp --dport 2112 -j ACCEPT
else
# Worker/Agent specific
add_rule HARVESTER_ESSENTIAL -p tcp --dport 10256 -j ACCEPT
fi

# --- End HARVESTER_ESSENTIAL ---

# FORWARD chain rules
add_rule FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

# Set default policies
iptables -P INPUT DROP
iptables -P FORWARD DROP
Copy link

Copilot AI Jan 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The script doesn't handle IPv6 traffic at all. It only configures iptables (IPv4) rules but doesn't configure ip6tables. This means IPv6 traffic will follow default policies which might differ from the intended security posture. Either IPv6 should be explicitly disabled, or corresponding ip6tables rules should be configured, or this limitation should be documented.

Copilot uses AI. Check for mistakes.
@@ -0,0 +1,79 @@
#!/bin/sh
Copy link

Copilot AI Jan 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The script uses 'sh' as the interpreter but relies on shell features and patterns that, while POSIX-compliant, could benefit from bash-specific error handling. Consider adding 'set -e' at the beginning to exit on any command failure, or alternatively add proper error checking after critical operations to prevent the script from continuing after failures and potentially leaving the system in an inconsistent state.

Suggested change
#!/bin/sh
#!/bin/sh
set -e

Copilot uses AI. Check for mistakes.
Comment on lines +20 to +21
# Flush HARVESTER_ESSENTIAL to ensure clean state
iptables -F HARVESTER_ESSENTIAL
Copy link

Copilot AI Jan 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only the HARVESTER_ESSENTIAL chain is flushed, but the HARVESTER_DYNAMIC chain is never flushed. This inconsistency could lead to duplicate rules accumulating in HARVESTER_DYNAMIC over time as the dispatcher script runs on every interface up event. Consider either flushing both chains or documenting why HARVESTER_DYNAMIC should preserve rules across interface events.

Suggested change
# Flush HARVESTER_ESSENTIAL to ensure clean state
iptables -F HARVESTER_ESSENTIAL
# Flush custom chains to ensure clean state
iptables -F HARVESTER_ESSENTIAL
iptables -F HARVESTER_DYNAMIC

Copilot uses AI. Check for mistakes.
This commit introduces a NetworkManager dispatcher script to apply initial
iptables rules when network interfaces are brought up.

This commit introduces a NetworkManager dispatcher script to apply initial
iptables rules when network interfaces are brought up.
Creating two custom chains:
  - `HARVESTER_ESSENTIAL`: Contains core rules required for Harvester and
    RKE2 functionality (SSH, K8s API, VXLAN, etc.).
  - `HARVESTER_DYNAMIC`: A placeholder chain for users or external
   components

Signed-off-by: Chris Chiu <chris.chiu@suse.com>
@mingshuoqiu mingshuoqiu force-pushed the issue_5681_v2 branch 3 times, most recently from 8d95fc3 to 4b84b03 Compare January 26, 2026 04:48
Check the kubeovn status to add the ports to the ACCEPT list
It would help the kubeovn working accross boots.

Signed-off-by: Chris Chiu <chris.chiu@suse.com>
Create a script in NetworkManager dispatcher to monitor the kubeovn
status and add/remove rules accordingly

Signed-off-by: Chris Chiu <chris.chiu@suse.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants