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 / PodNetworkSSH 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: 50051Use 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