Architecture¶
Related Notes
index | networking/flannel/explanation | networking/flannel/how-to-guides |
Overview¶
Flannel is a simple overlay network fabric designed for Kubernetes clusters. Developed by CoreOS (now Red Hat), it provides a flat network space where every pod gets a unique IP address reachable from any node. Flannel focuses on one task -- inter-node pod connectivity -- and deliberately does not include network policy enforcement, advanced routing, or observability features.
Flannel is the default CNI plugin in K3s and many lightweight Kubernetes distributions. It is best suited for small-to-medium clusters where simplicity matters more than advanced networking features.
See also: networking/flannel/explanation for limitations and when to use Calico or Cilium instead.
Component Diagram¶
graph TB
subgraph "Control Plane"
BE["Subnet Manager<br/>(etcd or Kubernetes API)"]
end
subgraph "Node 1"
FLAN1["flanneld daemon<br/>(kube-flannel DaemonSet)"]
VTEP1["flannel.1<br/>(VXLAN VTEP interface)"]
BRIDGE1["cni0<br/>(bridge interface)"]
VETH1_1["veth1 (pod)"]
VETH1_2["veth2 (pod)"]
end
subgraph "Node 2"
FLAN2["flanneld daemon"]
VTEP2["flannel.1"]
BRIDGE2["cni0"]
VETH2_1["veth1 (pod)"]
VETH2_2["veth2 (pod)"]
end
BE -->|"subnet leases<br/>& network config"| FLAN1
BE -->|"subnet leases<br/>& network config"| FLAN2
FLAN1 -->|"manages"| VTEP1
FLAN1 -->|"manages"| BRIDGE1
BRIDGE1 --> VETH1_1
BRIDGE1 --> VETH1_2
FLAN2 -->|"manages"| VTEP2
FLAN2 -->|"manages"| BRIDGE2
BRIDGE2 --> VETH2_1
BRIDGE2 --> VETH2_2
VTEP1 <-->|"VXLAN encapsulation<br/>UDP port 8472"| VTEP2
Core Components¶
flanneld Daemon¶
flanneld is the sole per-node daemon, deployed as a Kubernetes DaemonSet (typically kube-flannel-ds). It handles all networking responsibilities on each node:
- Subnet leasing -- claims a subnet lease from the subnet manager (etcd or Kubernetes API). Each node receives a /24 subnet by default from the configured pod CIDR (for example,
10.244.0.0/16). - Route programming -- writes kernel routes so that traffic destined for remote pod subnets is forwarded through the appropriate backend (VXLAN tunnel, host gateway, or WireGuard tunnel).
- Backend management -- creates and manages the tunnel interface (
flannel.1for VXLAN,flannel-wgfor WireGuard) and updates forwarding rules when nodes join or leave. - Subnet file -- writes
/run/flannel/subnet.envcontaining the allocated subnet, MTU, and IP masquerade settings. This file is consumed by the CNI bridge plugin.
Subnet Manager¶
The subnet manager is the coordination backend that stores the global network configuration and per-node subnet leases:
| Backend | Description | When to use |
|---|---|---|
| etcd | Stores network config at /coreos.com/network/ and per-node subnet leases. Requires a separate etcd cluster. |
Standalone etcd deployments, non-Kubernetes environments |
Kubernetes API (--kube-subnet-mgr) |
Uses Kubernetes Node objects and a ConfigMap (kube-flannel-cfg) for network configuration. No external etcd needed. |
Standard Kubernetes clusters (default for K3s) |
When using the Kubernetes backend, Flannel reads the cluster CIDR from the net-conf.json key in the kube-flannel-cfg ConfigMap:
CNI Plugin (bridge)¶
Flannel uses the standard CNI bridge plugin (not its own custom plugin). The CNI configuration is generated from the subnet file written by flanneld:
flanneldwrites/run/flannel/subnet.envwith the node's subnet and MTU.- The CNI config at
/etc/cni/net.d/10-flannel.conflistreferences theflannelCNI plugin. - The
flannelCNI plugin readssubnet.env, creates a veth pair, and attaches one end to thecni0bridge. - The pod's interface gets an IP from the node's allocated subnet.
Overlay Network Diagram¶
sequenceDiagram
participant PodA as Pod A (10.244.1.5)
participant CNI1 as cni0 bridge (Node 1)
participant VTEP1 as flannel.1 VTEP (Node 1)<br/>10.244.1.0/24
participant NET as Physical Network<br/>(Underlay)
participant VTEP2 as flannel.1 VTEP (Node 2)<br/>10.244.2.0/24
participant CNI2 as cni0 bridge (Node 2)
participant PodB as Pod B (10.244.2.8)
Note over PodA,PodB: Pod A sends packet to Pod B on a different node
PodA->>CNI1: Packet: src=10.244.1.5 dst=10.244.2.8
CNI1->>VTEP1: Route lookup: 10.244.2.0/24 via flannel.1
Note over VTEP1: VXLAN encapsulation<br/>Outer: Node1_IP -> Node2_IP<br/>Inner: 10.244.1.5 -> 10.244.2.8<br/>VNI: 1, UDP port: 8472
VTEP1->>NET: Encapsulated VXLAN packet
NET->>VTEP2: Packet arrives at Node 2
Note over VTEP2: VXLAN decapsulation<br/>Extract inner packet
VTEP2->>CNI2: Inner packet: 10.244.1.5 -> 10.244.2.8
CNI2->>PodB: Deliver to pod
Backend Types¶
VXLAN (Default and Recommended)¶
VXLAN encapsulates pod packets inside UDP packets. It is the recommended backend because it works on any network fabric without special support.
- VNI -- defaults to 1 on Linux, must be >= 4096 on Windows.
- UDP port -- defaults to 8472 on Linux (kernel default), must be 4789 on Windows.
- DirectRouting -- when enabled, uses host-gw-style direct routes for nodes on the same L2 subnet and VXLAN only for cross-subnet traffic. Default: disabled.
- GBP -- Group Based Policy for VXLAN. Default: disabled.
- MTU -- defaults to the MTU of the external interface minus 50 bytes (VXLAN overhead).
host-gw¶
Creates static IP routes to remote pod subnets via the remote node's IP address. No encapsulation overhead.
- Requirements -- all nodes must be on the same L2 subnet. No encapsulation means no MTU reduction.
- Performance -- lower latency and higher throughput than VXLAN because there is no encapsulation/decapsulation.
- Limitations -- cannot traverse routers or cross subnets. Only works on flat L2 networks.
WireGuard¶
Uses in-kernel WireGuard to encapsulate and encrypt all inter-node pod traffic.
- Encryption -- all pod-to-pod traffic between nodes is encrypted automatically.
- ListenPort -- defaults to 51820 (IPv4) and 51821 (IPv6).
- PSK -- optional pre-shared key for post-quantum resistance.
- Mode --
separate(default, independent IPv4/IPv6 tunnels),auto(single tunnel, auto-detect address family),ipv4oripv6(single tunnel, forced address family). - PersistentKeepaliveInterval -- keepalive interval in seconds for NAT traversal. Default: disabled (0).
- Requirements -- requires the WireGuard kernel module (
wireguard.ko) on each node.
IPSec (legacy)¶
Uses IPsec (strongSwan) for encrypted tunnels. Operators rarely use this backend now. The WireGuard backend largely superseded it.
Subnet Allocation¶
graph TD
CIDR["Cluster CIDR<br/>e.g. 10.244.0.0/16"]
N1["Node 1 subnet<br/>10.244.1.0/24"]
N2["Node 2 subnet<br/>10.244.2.0/24"]
N3["Node 3 subnet<br/>10.244.3.0/24"]
N4["Node N subnet<br/>10.244.N.0/24"]
CIDR --> N1
CIDR --> N2
CIDR --> N3
CIDR --> N4
N1 -->|"pod IPs<br/>10.244.1.1 - 10.244.1.254"| P1["Pods on Node 1"]
N2 -->|"pod IPs<br/>10.244.2.1 - 10.244.2.254"| P2["Pods on Node 2"]
- Subnet size -- defaults to /24 (254 addresses per node). Configurable via the
SubnetLenfield in the network configuration (for example,"SubnetLen": 26for /26 blocks with 62 addresses). Must be smaller than the cluster CIDR prefix. - Lease renewal -- nodes renew their subnet lease periodically (default every 24 hours for Kubernetes backend, configurable via
--subnet-lease-renew-margin). - Subnet file -- each node writes its allocated subnet to
/run/flannel/subnet.envfor the CNI plugin to consume.
Data Flow Summary¶
| Scenario | Path |
|---|---|
| Pod-to-Pod on same node | veth -> cni0 bridge -> veth (no encapsulation) |
| Pod-to-Pod on different node (VXLAN) | veth -> cni0 -> route -> flannel.1 (VXLAN encap) -> physical NIC -> flannel.1 (decap) -> cni0 -> veth |
| Pod-to-Pod on different node (host-gw) | veth -> cni0 -> route -> physical NIC -> route -> cni0 -> veth |
| Pod-to-external | veth -> cni0 -> iptables MASQUERADE (if --ip-masq=true) -> physical NIC |
What Flannel Does NOT Provide¶
Feature gaps
Flannel is intentionally minimal. It does not include:
- Network policies -- no Kubernetes NetworkPolicy or custom policy enforcement. You must add Calico or a policy controller alongside Flannel.
- eBPF dataplane -- uses kernel VXLAN/host routes, no eBPF acceleration.
- Observability -- no built-in flow logging, service map, or Hubble-equivalent.
- Load balancing -- does not replace kube-proxy. Relies on standard kube-proxy for service routing.
- Multi-cluster -- no built-in ClusterMesh or cross-cluster networking.
- IPAM flexibility -- subnet size is configurable but block affinity, block borrowing, and per-pod subnet allocation (like Calico IPAM) are not supported.
Sources¶
How It Works¶
VXLAN overlay mechanics, subnet lease lifecycle, route programming, and backend internals.
VXLAN Overlay¶
sequenceDiagram
participant PodA as Pod A (Node 1, 10.244.0.2)
participant Flannel1 as flanneld (Node 1)
participant VTEP1 as VXLAN VTEP (flannel.1)
participant Network as Physical Network (UDP 8472)
participant VTEP2 as VXLAN VTEP (flannel.1)
participant PodB as Pod B (Node 2, 10.244.1.3)
PodA->>VTEP1: Packet to 10.244.1.3
VTEP1->>VTEP1: Encapsulate in VXLAN header
VTEP1->>Network: UDP 8472 → Node 2
Network->>VTEP2: Receive VXLAN packet
VTEP2->>VTEP2: Decapsulate
VTEP2->>PodB: Deliver original packet
VXLAN Encapsulation Detail¶
When Pod A sends a packet to Pod B on a different node:
- The packet leaves the pod's veth, enters the
cni0bridge on Node 1 - The kernel does a route lookup:
10.244.1.0/24 via 10.244.1.0 dev flannel.1 - The
flannel.1VTEP encapsulates the original Ethernet frame inside a VXLAN header: - Outer Ethernet: Node 1 MAC → Node 2 MAC (resolved via kernel FDB)
- Outer IP: Node 1 IP → Node 2 IP
- Outer UDP: Source port (hash of inner flow) → Destination port 8472
- VXLAN header: VNI 1 (Virtual Network Identifier)
- Inner frame: Original pod-to-pod Ethernet frame (10.244.0.2 → 10.244.1.3)
- The encapsulated packet traverses the physical network
- Node 2's kernel receives the UDP packet on port 8472, the VXLAN driver decapsulates it, and delivers the inner frame to the
cni0bridge
The VTEP forwarding database (FDB) is populated by flanneld when nodes join or leave. Each flanneld writes the mapping of remote subnet → remote VTEP MAC → remote node IP into the kernel FDB via bridge fdb add commands.
Subnet Lease Model¶
Each node claims a subnet lease from the cluster CIDR. The default subnet size is /24 (254 pod IPs per node), configurable via SubnetLen in the network configuration JSON.
Lease Lifecycle¶
stateDiagram-v2
[*] --> Claiming: Node starts
Claiming --> Active: Subnet assigned
Active --> Active: Renew (every 24h default)
Active --> Expired: Renewal fails (node down)
Expired --> Claiming: Node restarts
Expired --> Reclaimed: Another node claims subnet
Reclaimed --> [*]: Subnet reassigned
Subnet Manager Backends¶
| Backend | Lease Storage | Renewal Mechanism |
|---|---|---|
| etcd | /coreos.com/network/subnets/ prefix |
etcd lease with TTL (default 24h) |
| Kubernetes API | Node annotations + ConfigMap | Periodic renewal via --subnet-lease-renew-margin |
When using the Kubernetes backend (--kube-subnet-mgr), flanneld watches the kube-flannel-cfg ConfigMap for network configuration changes and writes its subnet assignment as an annotation on the Node object.
Route Programming¶
Flanneld programs kernel routes that direct pod traffic to the correct backend:
| Route | Purpose |
|---|---|
10.244.0.0/24 dev cni0 |
Local pod subnet via bridge |
10.244.1.0/24 via 10.244.1.0 dev flannel.1 onlink |
Remote subnet via VXLAN tunnel |
10.244.2.0/24 via 10.244.2.0 dev flannel.1 onlink |
Another remote subnet |
The onlink flag is critical -- it tells the kernel to install the route even though the gateway (for example, 10.244.1.0) is not directly reachable via the flannel.1 interface. The VTEP resolves the gateway to the remote node's physical IP via the FDB.
host-gw Backend Mechanics¶
When using the host-gw backend instead of VXLAN:
- Flanneld writes static routes pointing remote pod subnets to the remote node's physical IP
- No encapsulation occurs -- the kernel forwards original pod packets directly via the physical network
- The physical network must be flat L2 (all nodes on the same subnet)
- MTU is preserved (no VXLAN overhead), resulting in higher throughput
Subnet File¶
Flanneld writes /run/flannel/subnet.env on startup and after each lease renewal:
The CNI bridge plugin reads this file to configure the cni0 bridge interface with the correct subnet, MTU, and masquerade rules. The MTU is calculated as the physical interface MTU minus the backend overhead (50 bytes for VXLAN).
Sources¶
Benchmarks¶
Scope
Performance characteristics, scaling limits, and resource consumption for Flannel.
Backend Performance¶
| Backend | Throughput (10GbE) | Latency Overhead | Encryption |
|---|---|---|---|
| VXLAN | 8-9 Gbps | +80-100us | No |
| host-gw | 9.5+ Gbps | +10-20us | No |
| WireGuard | 7-8 Gbps | +100-200us | Yes |
| UDP (deprecated) | 5-6 Gbps | +200-500us | No |
Resource Usage¶
| Metric | Per Node | Notes |
|---|---|---|
| CPU (idle) | < 10m | Minimal overhead |
| CPU (active) | 50-200m | Under heavy traffic |
| Memory | 30-50Mi | Lightweight |
Scaling Limits¶
| Dimension | Limit | Notes |
|---|---|---|
| Nodes per cluster | 5,000+ | Same as K8s limit |
| Pods per node | 110 | K8s default, not Flannel limit |
| Subnet size | /24 per node (default) | Configurable via SubnetLen |
Sourcing Status¶
Unsourced Performance Data
Do not plan capacity from these numbers. We estimated them from vendor documentation, community benchmarks, and engineering judgment. They do not represent controlled benchmarks with documented test conditions. Specific hardware configurations, software versions, and test methodologies were not recorded.
Use these figures as rough guidance only. For production capacity planning, run your own benchmarks against your specific workload and infrastructure.
Sources¶
Security¶
Related Notes
index | networking/flannel/explanation | networking/flannel/how-to-guides |
Overview¶
Flannel has a deliberately minimal security model. It provides inter-node pod connectivity but does not include any network policy enforcement, identity-based access control, or built-in observability. For clusters requiring network segmentation, encryption, or compliance-grade security, Flannel must be supplemented with additional tools or replaced entirely.
What Flannel Does NOT Provide¶
No built-in security features
Do not use Flannel where segmentation is required. It has no policy or identity features. Flannel is a pure overlay network fabric. It does not implement:
- Kubernetes NetworkPolicy -- no support whatsoever. Flannel silently ignores NetworkPolicy resources.
- Custom network policies -- no Calico-style or Cilium-style policy CRDs.
- Identity-based enforcement -- all pods on the overlay can connect to all other pods by default.
- L7 filtering -- no HTTP, gRPC, or DNS inspection.
- Flow logging or observability -- no Hubble-equivalent, no packet capture, no flow logs.
- Runtime security -- no Tetragon-equivalent for process or file monitoring.
- Service mesh integration -- no sidecar or ambient mesh support.
This means that in a default Flannel deployment, every pod can communicate with every other pod across all namespaces without restriction.
Encryption Options¶
VXLAN Backend (Default) -- No Encryption¶
The default VXLAN backend does not encrypt inter-node traffic. VXLAN packets are plain UDP encapsulation on the wire:
- Risk -- any entity with access to the physical network can sniff pod-to-pod traffic between nodes.
- Mitigation -- rely on underlying network encryption (IPsec tunnels, cloud provider VPC encryption, or physical network encryption).
WireGuard Backend -- Encrypted¶
Flannel includes a WireGuard backend that encrypts all inter-node pod traffic:
{
"Network": "10.244.0.0/16",
"Backend": {
"Type": "wireguard",
"ListenPort": 51820,
"PersistentKeepaliveInterval": 25
}
}
- Encryption -- uses ChaCha20-Poly1305 (WireGuard default). All pod traffic between nodes is encrypted transparently.
- NAT traversal --
PersistentKeepaliveIntervalenables keepalive packets for nodes behind NAT. - Pre-shared key (PSK) -- optional PSK for additional post-quantum resistance.
- Limitations -- only encrypts inter-node traffic. Pod-to-pod traffic on the same node is not encrypted (traverses the cni0 bridge in plaintext). No per-pod or per-namespace encryption granularity.
WireGuard vs Cilium/Calico encryption
Flannel's WireGuard backend provides transport encryption comparable to Calico WireGuard or Cilium WireGuard. But Flannel still lacks the policy enforcement and identity-based security that Calico and Cilium provide alongside encryption.
host-gw Backend -- No Encryption¶
The host-gw backend creates plain IP routes with no encapsulation and no encryption. Traffic is sent as raw packets on the physical network. Only suitable for trusted network environments.
etcd Access Control¶
When using etcd as the subnet manager backend, the security of the etcd cluster directly affects Flannel:
- etcd TLS -- Flannel supports mutual TLS for etcd communication via
--etcd-certfile,--etcd-keyfile, and--etcd-cafileflags. - RBAC -- etcd v3 supports role-based access control. Create a dedicated Flannel user with read/write access only to the
/coreos.com/network/prefix. - Network isolation -- do not expose etcd to pod networks. Use separate network interfaces or firewall rules.
When using the Kubernetes API backend (--kube-subnet-mgr), security relies on Kubernetes API server authentication and RBAC. The Flannel DaemonSet uses a ServiceAccount with permissions to read/write ConfigMaps and Node objects.
iptables and IP Masquerade¶
Flannel can configure iptables rules for egress NAT:
--ip-masq=true-- configures MASQUERADE rules for traffic leaving the Flannel network. Pod traffic to external IPs is NAT'd to the node's IP address.--iptables-forward-rules=true(default) -- adds ACCEPT rules to the iptables FORWARD chain to allow traffic forwarding.--iptables-resync=5-- resync period for iptables rules in seconds.
These are basic connectivity rules, not security policies. They do not provide segmentation or access control.
When to Use Calico or Cilium Instead¶
| Requirement | Flannel | Recommended Alternative |
|---|---|---|
| Kubernetes NetworkPolicy | Not supported | Calico or Cilium |
| Microsegmentation | Not supported | Calico (GlobalNetworkPolicy, tiers) or Cilium (CiliumNetworkPolicy) |
| L7 policy (HTTP/gRPC) | Not supported | Cilium |
| Identity-based policy | Not supported | Cilium |
| Encryption (WireGuard) | Supported via backend | Calico or Cilium (both support WireGuard with policy) |
| Flow observability | Not available | Cilium (Hubble) |
| Runtime security | Not available | Cilium (Tetragon) |
| eBPF acceleration | Not available | Calico (eBPF mode) or Cilium |
| Large scale (1000+ nodes) | Limited scalability | Calico or Cilium |
| Compliance (PCI, HIPAA) | Insufficient alone | Calico or Cilium with audit logging |
Common Upgrade Paths¶
-
Flannel + Calico (Canal) -- Canal combines Flannel's overlay networking with Calico's network policy engine. This is the simplest upgrade path for existing Flannel deployments that need policy enforcement.
-
Replace with Calico -- full migration from Flannel to Calico provides BGP routing, policy, eBPF dataplane, and WireGuard encryption in a single CNI plugin. Requires re-cabling the cluster network.
-
Replace with Cilium -- migration from Flannel to Cilium provides eBPF-based networking, identity-based policy, Hubble observability, and kube-proxy replacement. Best for clusters requiring advanced security and observability.
Security Checklist for Flannel Deployments¶
| Item | Action |
|---|---|
| Encryption | Use the WireGuard backend for production clusters |
| etcd TLS | Enable mutual TLS for etcd communication |
| etcd RBAC | Create a dedicated Flannel user with minimal permissions |
| Egress NAT | Enable --ip-masq for pods that need internet access |
| Network isolation | Use cloud VPC security groups or physical firewalls for external traffic filtering |
| Network policy | If you need segmentation, deploy the Calico policy controller alongside Flannel (Canal pattern) |
| Monitoring | Use external tools (Prometheus node exporter, packet capture) for traffic visibility |
| Node hardening | Restrict SSH access, use read-only root filesystem, limit privileged containers |