|
This is unreleased documentation for SUSE® Virtualization v1.9 (Dev). |
Host Network Security
By default, SUSE Virtualization nodes do not filter inbound traffic, allowing any host that can reach the management network to connect to any open port. To reduce the attack surface, you can apply iptables rules to restrict inbound traffic to only the ports required for cluster operations.
For the full list of required ports by node role, see Network requirements.
Applying iptables rules
The examples in this section use a custom iptables chain (HARVESTER_INPUT) attached to the INPUT hook on the management bridge (mgmt-br). The rule set follows this structure:
-
Established connections: Allow return traffic for connections already tracked by
conntrack. -
Protocol rules: Allow ICMP, DHCP, and other protocol-level traffic.
-
Service-specific ACCEPT rules: Allow traffic to ports required by the node role.
-
LOG + DROP: Log and drop all remaining traffic.
|
When using Host Network Configuration, you must create an additional rule for the new network interface:
|
# Create the custom chain and attach it to the INPUT hook
iptables -N HARVESTER_INPUT
iptables -A INPUT -i mgmt-br -j HARVESTER_INPUT
iptables -A HARVESTER_INPUT -m conntrack --ctstate ESTABLISHED,RELATED \
-m comment --comment "Accept return traffic from established connections" -j ACCEPT
iptables -A HARVESTER_INPUT -p icmp \
-m comment --comment "ICMP" -j ACCEPT
iptables -A HARVESTER_INPUT -s 10.52.0.0/16 \
-m comment --comment "Allow pod network return traffic" -j ACCEPT
# ... role-specific ACCEPT rules ...
iptables -A HARVESTER_INPUT -m limit --limit 10/min \
-m comment --comment "Rate-limit logging of dropped packets" \
-j LOG --log-prefix HARVESTER_DROP_ --log-level 4
iptables -A HARVESTER_INPUT -m comment --comment "Drop all other traffic" -j DROP
If you apply these commands manually, use iptables -L INPUT -v -n --line-numbers to verify that HARVESTER_INPUT appears as the last entry in the INPUT chain:
harvester1:/home/rancher # iptables -L INPUT -v -n --line-numbers
# Warning: iptables-legacy tables present, use iptables-legacy to see them
Chain INPUT (policy ACCEPT xxx packets, xxxx bytes)
num pkts bytes target prot opt in out source destination
1 301K 140M cali-INPUT all -- * * 0.0.0.0/0 0.0.0.0/0 /* cali:Cz_u1IQiXIMmKD4c */
2 0 0 ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 match-set ovn40services dst
3 0 0 ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 match-set ovn40services src
4 0 0 ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 match-set ovn40subnets dst
5 0 0 ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 match-set ovn40subnets src
6 0 0 ACCEPT udp -- * * 0.0.0.0/0 0.0.0.0/0 udp dpt:6081
7 300K 535M KUBE-PROXY-FIREWALL all -- * * 0.0.0.0/0 0.0.0.0/0 ctstate NEW /* kubernetes load balancer firewall */
8 2391K 1748M KUBE-NODEPORTS all -- * * 0.0.0.0/0 0.0.0.0/0 /* kubernetes health check service ports */
9 300K 535M KUBE-EXTERNAL-SERVICES all -- * * 0.0.0.0/0 0.0.0.0/0 ctstate NEW /* kubernetes externally-visible service portals */
10 2421K 1796M KUBE-FIREWALL all -- * * 0.0.0.0/0 0.0.0.0/0
11 49274 19M HARVESTER_INPUT all -- mgmt-br * 0.0.0.0/0 0.0.0.0/0
|
The pod CIDR |
Debugging and verification
Monitoring INPUT traffic
The HARVESTER_INPUT chain manages incoming management traffic. To inspect rule counters (packets and bytes) and identify active traffic patterns on the node, list all rules by running the following command:
iptables -L HARVESTER_INPUT -v -n --line-numbers
Monitoring dropped packets
The LOG rule records packets that do not match any ACCEPT rule. To monitor dropped packets in real time, run the following command:
journalctl -k -f | grep HARVESTER_DROP
# from the last 5 minutes:
journalctl -k --since "5 minutes ago" | grep HARVESTER_DROP
Key fields in a log entry:
| Field | Description |
|---|---|
|
Indicates the packet arrived on the management bridge |
|
Source and destination IP addresses |
|
Protocol (TCP or UDP) |
|
Source and destination ports (Use |
False positives
After applying rules to a running node, some log entries may appear briefly and then stop. These are false positives caused by lost conntrack state. When you apply new rules, active connection states are reset. As a result, return traffic from pre-existing connections no longer matches the ESTABLISHED,RELATED rule and matches the DROP rule instead. These log entries are harmless and resolve automatically as connections are re-established.
A false positive typically exhibits the following characteristics:
-
TCP flags are
ACK,ACK PSH, orACK FIN(notSYN). -
SPTis a known service port (for example,6443,9345, or10250). -
DPTis a high ephemeral port (above 1024). -
Log entries stop within a few minutes.
Example:
Apr 22 10:00:01 harvester3 kernel: HARVESTER_DROP_IN=mgmt-br OUT= MAC=... SRC=192.168.122.61 DST=192.168.122.63 LEN=52 PROTO=TCP SPT=9345 DPT=46002 WINDOW=521 RES=0x00 ACK FIN URGP=0
In this example:
-
SPT=9345: RKE2 supervisor API -
DPT=46002: Ephemeral port -
ACK FIN: Normal connection teardown (not an incoming blockedSYNconnection request)
Because this represents a connection teardown, it is a false positive and can be ignored.
|
If log entries persist with |
Persisting rules with CloudInit CRD
Custom iptables rules do not persist across reboots. To re-apply your rules automatically at boot time, use a CloudInit CRD.
Configuring the rules during the boot stage ensures they take effect before the node becomes fully operational, preventing initial exposure and avoiding conntrack state loss.
|
Include cleanup commands at the beginning of your script to prevent duplicate chain entries or conflicting rules when the node reboots. |
apiVersion: node.harvesterhci.io/v1beta1
kind: CloudInit
metadata:
name: iptables-control-plane
spec:
matchSelector:
node-role.kubernetes.io/control-plane: "true"
node-role.kubernetes.io/etcd: "true"
filename: 91-iptables-control-plane
contents: |
stages:
boot:
- name: "Apply iptables rules for control-plane node"
commands:
# Clean up any existing chain from a previous boot
- iptables -D INPUT -i mgmt-br -j HARVESTER_INPUT 2>/dev/null || true
- iptables -F HARVESTER_INPUT 2>/dev/null || true
- iptables -X HARVESTER_INPUT 2>/dev/null || true
# Create the chain and attach it
- iptables -N HARVESTER_INPUT
- iptables -A INPUT -i mgmt-br -j HARVESTER_INPUT
# Allow established connections and ICMP
- iptables -A HARVESTER_INPUT -m conntrack --ctstate ESTABLISHED,RELATED -m comment --comment "Accept return traffic from established connections" -j ACCEPT
- iptables -A HARVESTER_INPUT -p icmp -m comment --comment "ICMP" -j ACCEPT
- iptables -A HARVESTER_INPUT -s 10.52.0.0/16 -m comment --comment "Allow pod network return traffic" -j ACCEPT
# ... role-specific ACCEPT rules ...
# Log and drop everything else
- iptables -A HARVESTER_INPUT -m limit --limit 10/min -m comment --comment "Rate-limit logging of dropped packets" -j LOG --log-prefix HARVESTER_DROP_ --log-level 4
- iptables -A HARVESTER_INPUT -m comment --comment "Drop all other traffic" -j DROP
paused: false
|
Nodes must be rebooted after creating or updating a |
Removing the iptables rules
-
Delete the
CloudInitresource. -
Run the following commands on each host to remove the rules and flush the custom chain from the active system:
iptables -D INPUT -i mgmt-br -j HARVESTER_INPUT 2>/dev/null || true
iptables -F HARVESTER_INPUT 2>/dev/null || true
iptables -X HARVESTER_INPUT 2>/dev/null || true
Role-specific CloudInit resources
Create a separate CloudInit resource for each node role in your cluster. If you have not explicitly assigned a role in the SUSE Virtualization configuration, the node defaults to control-plane and you can apply the example in the following section.
|
Ensure that the |
The following examples include ports for the kubeovn-operator and rancher-monitoring add-ons. You can safely remove these rules if you are not using these add-ons. For more information, see Port requirements for add-ons.
Control plane nodes
apiVersion: node.harvesterhci.io/v1beta1
kind: CloudInit
metadata:
name: iptables-control-plane
spec:
matchSelector:
node-role.kubernetes.io/control-plane: "true"
node-role.kubernetes.io/etcd: "true"
filename: 91-iptables-control-plane
contents: |
stages:
boot:
- name: "Apply iptables rules for control-plane node"
commands:
- iptables -D INPUT -i mgmt-br -j HARVESTER_INPUT 2>/dev/null || true
- iptables -F HARVESTER_INPUT 2>/dev/null || true
- iptables -X HARVESTER_INPUT 2>/dev/null || true
- iptables -N HARVESTER_INPUT
- iptables -A INPUT -i mgmt-br -j HARVESTER_INPUT
- iptables -A HARVESTER_INPUT -m conntrack --ctstate ESTABLISHED,RELATED -m comment --comment "Accept return traffic from established connections" -j ACCEPT
- iptables -A HARVESTER_INPUT -p icmp -m comment --comment "ICMP (ping, MTU discovery, etc.)" -j ACCEPT
- iptables -A HARVESTER_INPUT -s 10.52.0.0/16 -m comment --comment "Allow pod network return traffic" -j ACCEPT
- iptables -A HARVESTER_INPUT -p udp --sport 67 --dport 68 -m comment --comment "DHCP server reply" -j ACCEPT
- iptables -A HARVESTER_INPUT -p udp --sport 68 --dport 67 -m comment --comment "DHCP client request" -j ACCEPT
- iptables -A HARVESTER_INPUT -p tcp --dport 22 -m comment --comment "SSH" -j ACCEPT
- iptables -A HARVESTER_INPUT -p tcp --dport 80 -m comment --comment "Harvester UI HTTP" -j ACCEPT
- iptables -A HARVESTER_INPUT -p tcp --dport 443 -m comment --comment "Harvester UI HTTPS" -j ACCEPT
- iptables -A HARVESTER_INPUT -p tcp --dport 2112 -m comment --comment "kube-vip Prometheus metrics" -j ACCEPT
- iptables -A HARVESTER_INPUT -p tcp --dport 2379:2380 -m comment --comment "etcd client/peer" -j ACCEPT
- iptables -A HARVESTER_INPUT -p tcp --dport 6443 -m comment --comment "Kubernetes API server" -j ACCEPT
- iptables -A HARVESTER_INPUT -p tcp --dport 9091 -m comment --comment "calico-node metrics (Prometheus)" -j ACCEPT
- iptables -A HARVESTER_INPUT -p tcp --dport 9345 -m comment --comment "RKE2 supervisor API" -j ACCEPT
- iptables -A HARVESTER_INPUT -p tcp --dport 9796 -m comment --comment "Prometheus node-exporter metrics (rancher-monitoring)" -j ACCEPT
- iptables -A HARVESTER_INPUT -p tcp --dport 10250 -m comment --comment "kubelet API" -j ACCEPT
- iptables -A HARVESTER_INPUT -p tcp --dport 30000:32767 -m comment --comment "NodePort TCP range" -j ACCEPT
- iptables -A HARVESTER_INPUT -p udp --dport 30000:32767 -m comment --comment "NodePort UDP range" -j ACCEPT
- iptables -A HARVESTER_INPUT -p udp --dport 8472 -m comment --comment "VXLAN (Flannel/Canal)" -j ACCEPT
- iptables -A HARVESTER_INPUT -p tcp --dport 8080 -m comment --comment "kube-ovn-webhook HTTP (kubeovn-operator)" -j ACCEPT
- iptables -A HARVESTER_INPUT -p tcp --dport 8443 -m comment --comment "kube-ovn-webhook HTTPS (kubeovn-operator)" -j ACCEPT
- iptables -A HARVESTER_INPUT -p tcp --dport 6641:6644 -m comment --comment "OVN NB/SB DB, Northd, and Raft (kubeovn-operator)" -j ACCEPT
- iptables -A HARVESTER_INPUT -p tcp --dport 10661 -m comment --comment "kube-ovn-monitor metrics (kubeovn-operator)" -j ACCEPT
- iptables -A HARVESTER_INPUT -p tcp --dport 10665 -m comment --comment "kube-ovn-daemon (kubeovn-operator)" -j ACCEPT
- iptables -A HARVESTER_INPUT -p udp --dport 4789 -m comment --comment "VXLAN (Kube-OVN, kubeovn-operator)" -j ACCEPT
- iptables -A HARVESTER_INPUT -m limit --limit 10/min -m comment --comment "Rate-limit logging of dropped packets" -j LOG --log-prefix HARVESTER_DROP_ --log-level 4
- iptables -A HARVESTER_INPUT -m comment --comment "Drop all other traffic" -j DROP
paused: false
Worker nodes
apiVersion: node.harvesterhci.io/v1beta1
kind: CloudInit
metadata:
name: iptables-worker
spec:
matchSelector:
node-role.harvesterhci.io/worker: "true"
filename: 91-iptables-worker
contents: |
stages:
boot:
- name: "Apply iptables rules for worker node"
commands:
- iptables -D INPUT -i mgmt-br -j HARVESTER_INPUT 2>/dev/null || true
- iptables -F HARVESTER_INPUT 2>/dev/null || true
- iptables -X HARVESTER_INPUT 2>/dev/null || true
- iptables -N HARVESTER_INPUT
- iptables -A INPUT -i mgmt-br -j HARVESTER_INPUT
- iptables -A HARVESTER_INPUT -m conntrack --ctstate ESTABLISHED,RELATED -m comment --comment "Accept return traffic from established connections" -j ACCEPT
- iptables -A HARVESTER_INPUT -p icmp -m comment --comment "ICMP (ping, MTU discovery, etc.)" -j ACCEPT
- iptables -A HARVESTER_INPUT -s 10.52.0.0/16 -m comment --comment "Allow pod network return traffic" -j ACCEPT
- iptables -A HARVESTER_INPUT -p udp --sport 67 --dport 68 -m comment --comment "DHCP server reply" -j ACCEPT
- iptables -A HARVESTER_INPUT -p udp --sport 68 --dport 67 -m comment --comment "DHCP client request" -j ACCEPT
- iptables -A HARVESTER_INPUT -p tcp --dport 22 -m comment --comment "SSH" -j ACCEPT
- iptables -A HARVESTER_INPUT -p tcp --dport 80 -m comment --comment "Harvester UI HTTP" -j ACCEPT
- iptables -A HARVESTER_INPUT -p tcp --dport 443 -m comment --comment "Harvester UI HTTPS" -j ACCEPT
- iptables -A HARVESTER_INPUT -p tcp --dport 9091 -m comment --comment "calico-node metrics (Prometheus)" -j ACCEPT
- iptables -A HARVESTER_INPUT -p tcp --dport 9796 -m comment --comment "Prometheus node-exporter metrics (rancher-monitoring)" -j ACCEPT
- iptables -A HARVESTER_INPUT -p tcp --dport 10250 -m comment --comment "kubelet API" -j ACCEPT
- iptables -A HARVESTER_INPUT -p tcp --dport 30000:32767 -m comment --comment "NodePort TCP range" -j ACCEPT
- iptables -A HARVESTER_INPUT -p udp --dport 30000:32767 -m comment --comment "NodePort UDP range" -j ACCEPT
- iptables -A HARVESTER_INPUT -p udp --dport 8472 -m comment --comment "VXLAN (Flannel/Canal)" -j ACCEPT
- iptables -A HARVESTER_INPUT -p tcp --dport 8080 -m comment --comment "kube-ovn-webhook HTTP (kubeovn-operator)" -j ACCEPT
- iptables -A HARVESTER_INPUT -p tcp --dport 8443 -m comment --comment "kube-ovn-webhook HTTPS (kubeovn-operator)" -j ACCEPT
- iptables -A HARVESTER_INPUT -p tcp --dport 10660 -m comment --comment "kube-ovn-controller (kubeovn-operator)" -j ACCEPT
- iptables -A HARVESTER_INPUT -p tcp --dport 10665 -m comment --comment "kube-ovn-daemon (kubeovn-operator)" -j ACCEPT
- iptables -A HARVESTER_INPUT -p udp --dport 4789 -m comment --comment "VXLAN (Kube-OVN, kubeovn-operator)" -j ACCEPT
- iptables -A HARVESTER_INPUT -m limit --limit 10/min -m comment --comment "Rate-limit logging of dropped packets" -j LOG --log-prefix HARVESTER_DROP_ --log-level 4
- iptables -A HARVESTER_INPUT -m comment --comment "Drop all other traffic" -j DROP
paused: false
Witness node
apiVersion: node.harvesterhci.io/v1beta1
kind: CloudInit
metadata:
name: iptables-witness
spec:
matchSelector:
node-role.harvesterhci.io/witness: "true"
filename: 91-iptables-witness
contents: |
stages:
boot:
- name: "Apply iptables rules for witness node"
commands:
- iptables -D INPUT -i mgmt-br -j HARVESTER_INPUT 2>/dev/null || true
- iptables -F HARVESTER_INPUT 2>/dev/null || true
- iptables -X HARVESTER_INPUT 2>/dev/null || true
- iptables -N HARVESTER_INPUT
- iptables -A INPUT -i mgmt-br -j HARVESTER_INPUT
- iptables -A HARVESTER_INPUT -m conntrack --ctstate ESTABLISHED,RELATED -m comment --comment "Accept return traffic from established connections" -j ACCEPT
- iptables -A HARVESTER_INPUT -p icmp -m comment --comment "ICMP (ping, MTU discovery, etc.)" -j ACCEPT
- iptables -A HARVESTER_INPUT -s 10.52.0.0/16 -m comment --comment "Allow pod network return traffic" -j ACCEPT
- iptables -A HARVESTER_INPUT -p udp --sport 67 --dport 68 -m comment --comment "DHCP server reply" -j ACCEPT
- iptables -A HARVESTER_INPUT -p udp --sport 68 --dport 67 -m comment --comment "DHCP client request" -j ACCEPT
- iptables -A HARVESTER_INPUT -p tcp --dport 22 -m comment --comment "SSH" -j ACCEPT
- iptables -A HARVESTER_INPUT -p tcp --dport 2379:2380 -m comment --comment "etcd client/peer" -j ACCEPT
- iptables -A HARVESTER_INPUT -p tcp --dport 9091 -m comment --comment "calico-node metrics (Prometheus)" -j ACCEPT
- iptables -A HARVESTER_INPUT -p tcp --dport 9345 -m comment --comment "RKE2 supervisor API" -j ACCEPT
- iptables -A HARVESTER_INPUT -p tcp --dport 9796 -m comment --comment "Prometheus node-exporter metrics (rancher-monitoring)" -j ACCEPT
- iptables -A HARVESTER_INPUT -p tcp --dport 10250 -m comment --comment "kubelet API" -j ACCEPT
- iptables -A HARVESTER_INPUT -p udp --dport 8472 -m comment --comment "VXLAN (Flannel/Canal)" -j ACCEPT
- iptables -A HARVESTER_INPUT -p tcp --dport 10665 -m comment --comment "kube-ovn-daemon (kubeovn-operator)" -j ACCEPT
- iptables -A HARVESTER_INPUT -p udp --dport 4789 -m comment --comment "VXLAN (Kube-OVN, kubeovn-operator)" -j ACCEPT
- iptables -A HARVESTER_INPUT -m limit --limit 10/min -m comment --comment "Rate-limit logging of dropped packets" -j LOG --log-prefix HARVESTER_DROP_ --log-level 4
- iptables -A HARVESTER_INPUT -m comment --comment "Drop all other traffic" -j DROP
paused: false
Upgrades
False positives during upgrades
SUSE Virtualization restarts multiple components during a cluster upgrade. Each restart clears conntrack state for affected connections, causing return traffic to temporarily trigger the DROP rule (the same false positive mechanism described in False positives), but occurring repeatedly throughout the upgrade process.
You may see log entries similar to the following:
May 05 04:40:28 harvester1 kernel: HARVESTER_DROP_IN=mgmt-br ... SRC=192.168.122.62 DST=192.168.122.61 ... PROTO=TCP SPT=10250 DPT=56266 ... ACK RST URGP=0
May 05 04:43:35 harvester2 kernel: HARVESTER_DROP_IN=mgmt-br ... SRC=192.168.122.61 DST=192.168.122.62 ... PROTO=TCP SPT=6443 DPT=43707 ... ACK URGP=0
Both entries are false positives:
-
SPT=10250 ACK RST:kubeletrestarted and reset an existing connection. TheRSTpacket no longer matches an activeconntrackstate. -
SPT=6443 ACK: The Kubernetes API server restarted. Return traffic from pre-restart connections lost itsconntrackstate.
These log entries may continue for the duration of the upgrade and stop once all components stabilize. This is expected behavior and does not indicate missing rules.
|
If log entries with |
Network issues during upgrades
If network issues persist during an upgrade, temporarily remove the custom chain before upgrading, and then re-apply it after the upgrade completes. For more information, see Removing the iptables rules.