Skip to main content

Layer-2 TAP tunnel into a Kubernetes cluster via pod NAD bridge

Project description

k8s-l2-tunneler

Layer-2 TAP tunnel into a Kubernetes cluster. Your developer machine joins the cluster's pod network as a native L2 peer — ping, curl, and DNS all work against pod IPs directly, with no proxy or port-forwarding required.

Architecture

Developer machine
  TAP (stolen IP + MAC)
    └── socat/WireGuard client
          └── NodePort UDP
                └── Tunnel pod
                      socat/WireGuard server → tap0 ↔ br0 ↔ net1
                                                             │
                                                          nad-br0 (host bridge, per tunnel)
                                                             │
                                                             |    Donor pod
                                                           net1 ↔ br-donor ↔ eth0
                                                                              │
                                                                     cluster pod network

Two pods are created per tunnel:

Pod Role
Tunnel pod Runs the socat/WireGuard UDP server. Bridges tap0 (L2 tunnel endpoint) ↔ net1 (NAD)
Donor pod Provides a CNI-registered IP + MAC to the developer TAP. Bridges net1 (NAD) ↔ eth0 (cluster) after identity is stolen

A NetworkAttachmentDefinition (Multus) creates a host-side Linux bridge (nad-tun-<id>) that connects both pods' net1 interfaces — this is the cross-pod L2 segment that was impossible to create from inside either pod.

Both pods are pinned to the same node (mandatory for the host bridge to connect them).

When connecting to an existing cni the donor pod is not created, instead the identity is stolen directly from the NetworkAttachmentDefinition interface on the tunnel pod.

Requirements

Requirement Notes
Multus CNI Must be installed cluster-side
socat/WireGuard Must be installed on the developer machine
Root / sudo TAP creation + raw ARP sockets need CAP_NET_ADMIN
Python ≥ 3.8
uv Package manager

Installation

uv tool install k8s-l2-tunneler
# or, from source:
git clone ...
cd k8s-l2-tunneler
uv sync

Usage

# Create a tunnel (namespace defaults to owner name if omitted)
sudo uv run k8s-l2-tunneler connect-to-cluster --owner alice

# With an explicit namespace and custom local TAP name
sudo uv run k8s-l2-tunneler connect-to-cluster --owner alice --namespace my-ns --local-iface-name cluster-net

# When the cluster is deployed behind a NAT and the pod is able to directly ping your machine's IP
# TODO: support both cluster behind NAT and developer behind NAT using shared STUN server.
sudo uv run k8s-l2-tunneler connect-to-cluster --owner alice --cluster-behind-nat

# Tear it down
sudo uv run k8s-l2-tunneler clean --owner alice

CNI compatibility

CNI Works Notes
Flannel VXLAN Best case — cni0 bridge does MAC learning
Flannel host-gw Same as VXLAN
Canal Flannel data plane; check NetworkPolicy
Calico BGP ✅* *TAP MAC not stolen; promisc mode used instead
Calico VXLAN ✅* Same as Calico BGP
Cilium Works under default policy (no strict source-IP enforcement)
WeaveNet Weave L2 mesh propagates MAC correctly
Antrea OVS flows match on existing (port, IP) registration

MTU

All interfaces in the packet path are configured to MTU 1370 to prevent fragmentation across the network path and any CNI overlay encapsulation.

Development

uv sync
uv run ruff format src/
uv run ruff check src/ --fix
uv run ruff check src/
uv run mypy src/

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

k8s_l2_tunneler-0.2.0.tar.gz (177.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

k8s_l2_tunneler-0.2.0-py3-none-any.whl (37.9 kB view details)

Uploaded Python 3

File details

Details for the file k8s_l2_tunneler-0.2.0.tar.gz.

File metadata

  • Download URL: k8s_l2_tunneler-0.2.0.tar.gz
  • Upload date:
  • Size: 177.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.9 {"installer":{"name":"uv","version":"0.10.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"22.04","id":"jammy","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for k8s_l2_tunneler-0.2.0.tar.gz
Algorithm Hash digest
SHA256 650497da5e735546a1ff6455b91997c9aea58403ea3d7990a1c56289e406695b
MD5 739338fd1630148eada52efbbd05a8ce
BLAKE2b-256 a219d3f0fd537ac4d66666d62d713b497d43c144ac35c24f478e129d141c0975

See more details on using hashes here.

File details

Details for the file k8s_l2_tunneler-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: k8s_l2_tunneler-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 37.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.9 {"installer":{"name":"uv","version":"0.10.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"22.04","id":"jammy","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for k8s_l2_tunneler-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 3072a24bfb0638aa95b642e021dbd403b3d6f74ef2b8ac2c69ea748d1a2f93d2
MD5 6b1a6b14d0691b250ed315b6136b2e9e
BLAKE2b-256 c1d7601758b9a500edc0032d989d3c0a14d99e8f788d9a20eddbf05c9ab2f682

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page