Skip to main content
Version: Next

Wstunnel Configuration

InterLink's wstunnel feature enables secure port exposure for pods with containers that have exposed ports. This feature automatically creates websocket tunnel infrastructure outside the virtual node, allowing external access to pod services without requiring VPN connectivity.

Overview

The wstunnel integration provides:

  • Automatic Infrastructure Creation: Deployment, Service, and Ingress resources
  • Secure Tunneling: WebSocket-based tunneling with random password protection
  • Port Forwarding: Automatic forwarding of all exposed container ports
  • External Access: Ingress-based external access with customizable DNS
  • Resource Management: Automatic cleanup when pods are deleted
info

Wstunnel is disabled by default and must be explicitly enabled in the configuration.


Configuration

Virtual Kubelet Configuration

Add the wstunnel configuration to your Virtual Kubelet config file:

# VirtualKubeletConfig.yaml
InterlinkURL: "http://interlink-api:3000"
InterlinkPort: "3000"
VerboseLogging: true
ErrorsOnlyLogging: false

# Network configuration
Network:
EnableTunnel: true # Enable wstunnel feature
WildcardDNS: "tunnel.example.com" # DNS domain for ingress
WstunnelTemplatePath: "/etc/templates/custom.yaml" # Optional: custom template path

# Other configuration...
Resources:
CPU: "10"
Memory: "20Gi"
Pods: "100"

Configuration Options

OptionTypeRequiredDefaultDescription
EnableTunnelboolNofalseEnable/disable wstunnel feature
WildcardDNSstringYes*""DNS domain for ingress hostnames
WstunnelTemplatePathstringNo""Path to custom wstunnel template

*Required when EnableTunnel is true


How It Works

Automatic Trigger

Wstunnel infrastructure is automatically created when:

  1. Network.EnableTunnel is set to true
  2. Pod has containers with exposed ports
  3. Pod does NOT have interlink.eu/pod-vpn annotation

Resource Creation

For each qualifying pod, interLink creates:

  1. Deployment: Runs wstunnel server with WireGuard
  2. Service: Exposes websocket and forwarded ports
  3. Ingress: Provides external access via DNS

Naming Convention

Resources are named using the pattern: {pod-name}-wstunnel

Example: Pod my-web-app → Resources my-web-app-wstunnel


Template System

Default Template

InterLink includes an embedded default template that creates:

# Deployment with wstunnel server
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{.Name}}
namespace: {{.Namespace}}
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/component: {{.Name}}
template:
metadata:
labels:
app.kubernetes.io/component: {{.Name}}
spec:
containers:
- name: wireguard
image: ghcr.io/dciangot/dciangot/wg:v0.2
command: ["bash", "-c"]
args:
- ./wstunnel server --log-lvl DEBUG --dns-resolver-prefer-ipv4 --restrict-http-upgrade-path-prefix {{.RandomPassword}} ws://0.0.0.0:8080
ports:
- containerPort: 8080
name: webhook
protocol: TCP
- containerPort: 51820
name: vpn
protocol: UDP
{{- range .ExposedPorts}}
- containerPort: {{.Port}}
name: {{.Name}}
protocol: {{.Protocol}}
{{- end}}
resources:
requests:
cpu: 100m
memory: 90Mi
nodeSelector:
kubernetes.io/os: linux

---
# Service for port exposure
apiVersion: v1
kind: Service
metadata:
name: {{.Name}}
namespace: {{.Namespace}}
spec:
type: ClusterIP
selector:
app.kubernetes.io/component: {{.Name}}
ports:
- port: 8080
targetPort: 8080
name: ws
{{- range .ExposedPorts}}
- port: {{.Port}}
targetPort: {{.TargetPort}}
name: {{.Name}}
protocol: {{.Protocol}}
{{- end}}

---
# Ingress for external access
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{.Name}}
namespace: {{.Namespace}}
annotations:
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
nginx.ingress.kubernetes.io/server-snippets: |
location / {
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_http_version 1.1;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- host: ws-{{.Name}}.{{.WildcardDNS}}
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: {{.Name}}
port:
number: 8080

Template Variables

The template system provides these variables:

VariableTypeDescriptionExample
{{.Name}}stringResource namemy-web-app-wstunnel
{{.Namespace}}stringPod namespacedefault
{{.RandomPassword}}stringSecurity passworda1b2c3d4e5f6...
{{.WildcardDNS}}stringDNS domaintunnel.example.com
{{.ExposedPorts}}[]PortMappingPort mappingsSee below

Port Mapping Structure

type PortMapping struct {
Port int32 // Container port number
TargetPort int32 // Target port (usually same as Port)
Name string // Port name
Protocol string // Protocol (TCP/UDP)
}

Custom Templates

You can provide custom templates by:

  1. Creating a custom template file:

    # /etc/templates/custom-wstunnel.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
    name: {{.Name}}
    namespace: {{.Namespace}}
    spec:
    # Your custom configuration...
  2. Configuring the template path:

    Network:
    EnableTunnel: true
    WildcardDNS: "tunnel.example.com"
    WstunnelTemplatePath: "/etc/templates/custom-wstunnel.yaml"
  3. Mounting the template in the Virtual Kubelet deployment:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
    name: virtual-kubelet
    spec:
    template:
    spec:
    containers:
    - name: virtual-kubelet
    volumeMounts:
    - name: wstunnel-template
    mountPath: /etc/templates/custom-wstunnel.yaml
    subPath: custom-wstunnel.yaml
    volumes:
    - name: wstunnel-template
    configMap:
    name: wstunnel-template

Pod Configuration

Basic Pod with Exposed Ports

apiVersion: v1
kind: Pod
metadata:
name: web-server
namespace: default
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
name: http
protocol: TCP
- containerPort: 443
name: https
protocol: TCP
restartPolicy: Never

Pod with Custom Timeout

apiVersion: v1
kind: Pod
metadata:
name: web-server
namespace: default
annotations:
interlink.virtual-kubelet.io/wstunnel-timeout: "5m"
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
name: http
restartPolicy: Never

Disabling Wstunnel for Specific Pods

apiVersion: v1
kind: Pod
metadata:
name: web-server
namespace: default
annotations:
interlink.eu/pod-vpn: "true" # Use VPN instead of wstunnel
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
name: http
restartPolicy: Never

DNS Configuration

Wildcard DNS Setup

Configure your DNS provider to point wildcard subdomains to your ingress controller:

*.tunnel.example.com → your-ingress-controller-ip

Generated Hostnames

For each pod, the system generates hostnames using the pattern:

ws-{pod-name}-wstunnel.{WildcardDNS}

Examples:

  • Pod web-serverws-web-server-wstunnel.tunnel.example.com
  • Pod api-gatewayws-api-gateway-wstunnel.tunnel.example.com

Client Connection Commands

Automatic Command Generation

When wstunnel is enabled, interLink automatically generates a client command annotation for each pod with exposed ports. This annotation contains the complete command needed to connect to the pod's services from a remote location.

Annotation: interlink.eu/wstunnel-client-commands

Example

For a pod with exposed ports, the annotation will contain:

curl -L https://github.com/erebe/wstunnel/releases/latest/download/wstunnel-linux-x64 -o wstunnel && chmod +x wstunnel

./wstunnel client --http-upgrade-path-prefix a1b2c3d4e5f6 -R tcp://[::]:8080:localhost:8080 -R tcp://[::]:9090:localhost:9090 ws://ws-my-pod-wstunnel.tunnel.example.com:80

Command Structure

  1. Download: Downloads the latest wstunnel client binary
  2. Connect: Establishes the websocket tunnel with:
    • --http-upgrade-path-prefix: Unique random password for authentication
    • -R tcp://[::]:PORT:localhost:PORT: Port forwarding rules (one per exposed port)
    • ws://ENDPOINT:80: Websocket endpoint using generated hostname

Retrieving the Command

# Get the complete client command for a pod
kubectl get pod my-pod -o jsonpath='{.metadata.annotations.interlink\.eu/wstunnel-client-commands}'

# Or view all annotations
kubectl describe pod my-pod

Multiple Ports

When a pod exposes multiple ports, all ports are included in a single command with multiple -R options:

# Pod with ports 8080, 9090, and 3000
./wstunnel client --http-upgrade-path-prefix randompassword \
-R tcp://[::]:8080:localhost:8080 \
-R tcp://[::]:9090:localhost:9090 \
-R tcp://[::]:3000:localhost:3000 \
ws://ws-my-pod-wstunnel.tunnel.example.com:80

Security Considerations

Authentication

  • Each wstunnel instance uses a unique random password
  • Passwords are generated using cryptographically secure random numbers
  • Access is restricted via the restrict-http-upgrade-path-prefix parameter

Network Security

  • WebSocket connections are established over HTTP/HTTPS
  • Consider using TLS termination at the ingress level
  • Implement network policies to restrict traffic if needed

Resource Security

  • Wstunnel resources are automatically cleaned up when pods are deleted
  • Resources are labeled for easy identification and management
  • Consider implementing RBAC policies for wstunnel resources

Monitoring and Troubleshooting

Checking Wstunnel Status

# List all wstunnel resources
kubectl get deployment,service,ingress -l interlink.virtual-kubelet.io/type=wstunnel

# Check specific pod's wstunnel resources
kubectl get deployment,service,ingress -l app.kubernetes.io/component=my-pod-wstunnel

# Check wstunnel pod logs
kubectl logs -l app.kubernetes.io/component=my-pod-wstunnel

Common Issues

  1. Pod IP not assigned

    # Check pod status
    kubectl get pod my-pod -o yaml | grep -A 10 status

    # Check virtual kubelet logs
    kubectl logs -l nodeName=virtual-kubelet
  2. Wstunnel timeout errors

    # Increase timeout annotation
    kubectl annotate pod my-pod interlink.virtual-kubelet.io/wstunnel-timeout=10m
  3. DNS resolution issues

    # Test DNS resolution
    nslookup ws-my-pod-wstunnel.tunnel.example.com

    # Check ingress configuration
    kubectl get ingress my-pod-wstunnel -o yaml
  4. Template errors

    # Check virtual kubelet logs for template parsing errors
    kubectl logs -l nodeName=virtual-kubelet | grep -i template

Debug Commands

# Get pod with full details
kubectl get pod my-pod -o yaml

# Check wstunnel deployment
kubectl describe deployment my-pod-wstunnel

# Test websocket connection
curl -i -N -H "Connection: Upgrade" -H "Upgrade: websocket" \
-H "Sec-WebSocket-Key: test" -H "Sec-WebSocket-Version: 13" \
http://ws-my-pod-wstunnel.tunnel.example.com/your-random-password

# Check service endpoints
kubectl get endpoints my-pod-wstunnel

Best Practices

Configuration

  • Set appropriate WildcardDNS that you control
  • Use custom templates for specific requirements
  • Configure reasonable timeout values based on your infrastructure

Security

  • Regularly rotate ingress TLS certificates
  • Implement network policies to restrict access
  • Monitor wstunnel resource usage

Operations

  • Monitor DNS resolution and ingress health
  • Set up alerts for wstunnel pod failures
  • Regular cleanup of orphaned resources

Performance

  • Size wstunnel pods appropriately for your traffic
  • Use appropriate resource limits in custom templates
  • Consider using NodePort or LoadBalancer services for high traffic

Migration Guide

From VPN to Wstunnel

  1. Update Virtual Kubelet configuration:

    Network:
    EnableTunnel: true
    WildcardDNS: "tunnel.example.com"
  2. Remove VPN annotations from pods:

    kubectl annotate pod my-pod interlink.eu/pod-vpn-
  3. Restart pods to trigger wstunnel creation:

    kubectl delete pod my-pod
    kubectl apply -f my-pod.yaml

From Wstunnel to VPN

  1. Add VPN annotation to pods:

    metadata:
    annotations:
    interlink.eu/pod-vpn: "true"
  2. Restart pods to use VPN instead of wstunnel


Advanced Configuration

Custom Ingress Controller

# Custom template with different ingress controller
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{.Name}}
namespace: {{.Namespace}}
annotations:
traefik.ingress.kubernetes.io/router.entrypoints: websecure
traefik.ingress.kubernetes.io/router.tls: "true"
spec:
tls:
- hosts:
- ws-{{.Name}}.{{.WildcardDNS}}
secretName: {{.Name}}-tls
rules:
- host: ws-{{.Name}}.{{.WildcardDNS}}
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: {{.Name}}
port:
number: 8080

Resource Limits

# Custom template with resource limits
spec:
template:
spec:
containers:
- name: wireguard
resources:
requests:
cpu: 100m
memory: 90Mi
limits:
cpu: 500m
memory: 256Mi

Multiple Ingress Rules

# Multiple ingress rules for different services
spec:
rules:
- host: ws-{{.Name}}.{{.WildcardDNS}}
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: {{.Name}}
port:
number: 8080
{{- range .ExposedPorts}}
- host: {{.Name}}-{{.Port}}.{{.WildcardDNS}}
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: {{.Name}}
port:
number: {{.Port}}
{{- end}}