Closed SpComb closed 1 year ago
For comparison, kube-router configures separate point-to-point IPIP tunnel interfaces, so it's not affected by this.
7: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN mode DEFAULT group default qlen 1
link/ipip 0.0.0.0 brd 0.0.0.0 promiscuity 0
ipip remote any local any ttl inherit nopmtudisc
8: tun-aaaaaaa@bond0: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 1460 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1
link/ipip 192.0.2.2 peer 192.0.2.1 promiscuity 0
ipip remote 192.0.2.1 local 192.0.2.2 dev bond0 ttl inherit pmtudisc addrgenmode eui64
9: tun-bbbbbbb@bond0: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 1460 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1
link/ipip 192.0.2.2 peer 192.0.2.0 promiscuity 0
ipip remote 192.0.2.0 local 192.0.2.2 dev bond0 ttl inherit pmtudisc addrgenmode eui64
With the tunl0
interface being down, the incoming IP-IP packets from unconfigured sources get rejected by the kernel with ICMP unreachable:
15:18:11.214722 x.y.z.w > 192.0.2.2: x.y.z.w.52126 > 10.96.0.10.53: 5619+ [1au] A? kubernetes.default.svc.cluster.local. (65) (ipip-proto-4)
15:18:11.214829 192.0.2.2 > x.y.z.w: ICMP 192.0.2.2 protocol 4 port 93 unreachable, length 121
If you bring the tunl0
interface up and disable RPF on it, then does accept the injected traffic.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
The flannel
ipip
backend creates a single ipip tunnel device withremote any
:This tunnel device will accept, de-encapsulate and forward any IPIP packets arriving with the correct destination address, regardless of the source address. Given a cluster with nodes using externally routable node IPs, there is nothing to prevent arbitrary external hosts that do not belong to the cluster from sending arbitrary encapsulated packets to any of the cluster hosts.
This is a security issue that risks exposing internal pods/services within the cluster to untrusted external attackers. An external attacker with knowledge of the internal IP addresses in use on the cluster can use this configuration to inject packets using spoofed cluster-internal IPs into the cluster. In configurations lacking reverse-path filtering (RPF) at the host/network level, the external attacker could also use a routable source address to establish TCP connections to services within the cluster.
The default
vxlan
backend also has a somewhat similar issue with accepting packets on UDP port 8472 from arbitrary sources, but that is somewhat mitigated in the defaultvxlan
backend by requiring the attacker to have knowledge of theflannel.1
VXLAN interface's (randomly-generated?) 48-bit MAC address in order to inject unicast packets... however, injected VXLAN packets with a broadcast destination address may still get processed in some cases (ICMP ping?).EDIT: edited the title to clarify that only clusters using externally routable node IPs are affected. Clusters using internal node IPs would only accept IPIP packets with a destination address matching the internal node IPs. IPIP packets to any other externally routable local IPs on the same node should get rejected by the kernel.
Expected Behavior
Flannel nodes should only accept ip-ip packets from source addresses belonging to other nodes in the same cluster.
This would raise the bar by requiring the attacking node to have the ability to spoof the external node source addresses in order to inject packets, and actively hijack routing in order to establish connections.
Current Behavior
Flannel nodes accept incoming ip-ip packets from arbitrary source addresses to the local
nodeIP
, and tunneled packets containing spoofed cluster pod/svc IPs will be forwarded to the internal containers.Possible Solutions
Create separate ipip interfaces bound to specific sources and leave the default
tunl0
interface down?Create and manage
iptables
rules to whitelist incoming IP-IP packet sources?Document the security requirement for limiting external IP-IP traffic to nodes (i.e. only use private/internal/non-globally-routable
kubelet --node-ip
addresses)?Steps to Reproduce (for bugs)
Given a node in a kubernetes cluster deployed using
networking.podSubnet: 10.32.0.0/16
+networking.serviceSubnet: 10.96.0.0/16
, and with flannel deployed using anet-conf.json
of{ "Network": "10.32.0.0/12", "Backend": { "Type": "ipip" } }
:The node at
192.0.2.1
will have the following relevant parts in its network configuration, with the master node at192.0.2.0
, and a second node at192.0.2.2
:Default case with RPF enabled, using a spoofed cluster-internal source IP
An external attacker at any arbitrary external host with knowledge of:
clusterIP
such as10.96.0.10
flannel.ipip
interfacecan then do the following:
Looking at the tcpdump traces on the external network interfaces across the nodes, the DNS query from the external host to the internal DNS service gets injected into the cluster. In this case, the DNS pod is running on the master node, so the reply goes to the spoofed second node, which returns an ICMP unreachable for the unrecognized UDP response packet.
Attacker node (x.y.z.w)
node1 (192.0.2.1)
master (192.0.2.0)
node2 (192.0.2.2)
Advanced case with RPF disabled
The default case requires spoofing a valid source address within the cluster due to RPF being enabled on the victim node. However, with RPF disabled on the victim node:
we can get very close to not just injecting spoofed packets into the cluster, but actually connecting to internal cluster services. In this case, the attacker no longer needs any knowledge of the pod CIDRs allocated to the specific nodes:
Looking at the tcpdump on the victim node, the incoming packet is accepted and forwarded to the DNS pod, and the response packet is actually sent back to the attacking node using the internal
10.96.0.10
cluster-internal source IP:In this case, the upstream router drops the packet with an incorrect source address per its own RPF rules before it reaches the attacking node. However, in some network topologies without any RPF filtering between the attacker and the victim, the external attacker may actually be able to connect to arbitrary internal cluster services, including the default 10.96.0.10 DNS service in order to resolve the service
clusterIP
addresses.Context
Nodes connected to the same raw ethernet network are naturally also exposed to similar access from an attacker directly connected to the same ethernet network, but typical cloud provider networks will filter out any traffic using cluster-internal source/destination IP addresses between the cluster nodes and the untrusted attacker node. However, this is not the case for IP-IP tunneled packets...
Your Environment
quay.io/coreos/flannel:v0.10.0-amd64