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.1.0.tar.gz (90.3 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.1.0-py3-none-any.whl (37.2 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: k8s_l2_tunneler-0.1.0.tar.gz
  • Upload date:
  • Size: 90.3 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.1.0.tar.gz
Algorithm Hash digest
SHA256 0fb9cc0fb6361df502c63dc702daa419fb6269dd54e52821ae12468545cd054f
MD5 795a3f21a0a23809c49ac4f67f4b814c
BLAKE2b-256 b5094f661486ce6a85e27afeb68f9f8fccbc3069b83f3d624e02630fa55080bd

See more details on using hashes here.

File details

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

File metadata

  • Download URL: k8s_l2_tunneler-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 37.2 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.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 e6a12d61731721cbca532e8c1868156080b7b4df5258a2b9f9f1c37305e92e49
MD5 3017f1cb52ff5f8f14df465dd1c9c7e5
BLAKE2b-256 cdb15ce6b0af4e002a0765d2ba5a042da090c062ddd561287e68633b460fb38a

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