Metadata-Version: 2.4
Name: k8s-l2-tunneler
Version: 0.1.0
Summary: Layer-2 TAP tunnel into a Kubernetes cluster via pod NAD bridge
Author-email: ronmov <ruin1212@gmail.com>
License-Expression: Apache-2.0
License-File: LICENSE
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: System :: Networking
Requires-Python: >=3.8
Requires-Dist: click
Requires-Dist: kubernetes
Description-Content-Type: text/markdown

# 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

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

## Usage

```bash
# 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

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