Contents

k8s-gateway: Multi-Protocol Kubernetes Gateway

k8s-gateway: Multi-Protocol Kubernetes Gateway

k8s-gateway is a Go-based gateway service that exposes multiple network interfaces to access resources deployed in private Kubernetes networks — SSH (bastion with PTY), gRPC, NETCONF, and Telnet.

Project Overview

Managing network devices and services inside Kubernetes clusters often requires secure, multi-protocol access without exposing every endpoint publicly. k8s-gateway solves this by acting as a single entry point with protocol-aware proxying.

  • SSH — full bastion server with its own PTY terminal
  • gRPC — transparent proxy for gRPC services inside the cluster
  • NETCONF — proxy for network device management (RFC 6241)
  • Telnet — legacy protocol proxy for older network equipment

Architecture

External Client
      │
      ▼
 k8s-gateway (Pod)
 ┌────────────────────────────┐
 │  SSH Listener  :22         │──► PTY Terminal / Bastion
 │  gRPC Listener :50051      │──► Internal gRPC Services
 │  NETCONF Listener :830     │──► Network Devices
 │  Telnet Listener :23       │──► Legacy Devices
 └────────────────────────────┘
      │
 Kubernetes ClusterIP / PodNetwork

SSH Bastion with PTY

The SSH component provides a real terminal session, not just port forwarding. It handles key-based authentication and spawns a PTY for interactive use.

func handleSSHSession(session ssh.Session) {
    ptyReq, winCh, isPty := session.Pty()
    if !isPty {
        io.WriteString(session, "PTY required\n")
        session.Exit(1)
        return
    }

    cmd := exec.Command("/bin/sh")
    cmd.Env = append(os.Environ(), fmt.Sprintf("TERM=%s", ptyReq.Term))

    f, err := pty.Start(cmd)
    if err != nil {
        session.Exit(1)
        return
    }
    defer f.Close()

    go func() {
        for win := range winCh {
            setWinsize(f, win.Width, win.Height)
        }
    }()

    go io.Copy(f, session)
    io.Copy(session, f)
    cmd.Wait()
}

gRPC Proxy

For gRPC services, the gateway uses transparent proxying — it forwards raw frames without needing to know the service’s proto definitions.

func (g *GRPCGateway) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    target := g.resolveTarget(r.Header.Get("X-Target-Service"))
    conn, err := grpc.Dial(target, grpc.WithInsecure())
    if err != nil {
        http.Error(w, "upstream unavailable", 502)
        return
    }
    defer conn.Close()
    // bidirectional stream forwarding
    proxy.ServeHTTP(w, r, conn)
}

NETCONF Proxy

NETCONF (used widely for router/switch management) operates over SSH on port 830. The gateway handles the SSH-over-SSH tunneling required to reach devices inside the cluster.

Kubernetes Deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: k8s-gateway
spec:
  replicas: 1
  selector:
    matchLabels:
      app: k8s-gateway
  template:
    spec:
      containers:
      - name: gateway
        image: k8s-gateway:latest
        ports:
        - containerPort: 22    # SSH
        - containerPort: 830   # NETCONF
        - containerPort: 50051 # gRPC
        - containerPort: 23    # Telnet
        env:
        - name: SSH_HOST_KEY
          valueFrom:
            secretKeyRef:
              name: gateway-keys
              key: host-key
---
apiVersion: v1
kind: Service
metadata:
  name: k8s-gateway
spec:
  type: LoadBalancer
  selector:
    app: k8s-gateway
  ports:
  - name: ssh
    port: 22
    targetPort: 22
  - name: netconf
    port: 830
    targetPort: 830
  - name: grpc
    port: 50051
    targetPort: 50051

Use Cases

  • Network Lab Access — reach containerlab/clabernetes topologies inside Kubernetes
  • Device Management — NETCONF/Telnet to routers deployed in private namespaces
  • Service Debugging — interactive shell or gRPC access without port-forwarding every service

Conclusion

k8s-gateway removes the friction of multi-protocol access to private Kubernetes networks. With SSH bastion, gRPC proxying, NETCONF, and Telnet all in one service, it’s a practical tool for network engineering labs and infrastructure management.

Source: GitHub