Kubernetes
Pattern 1 — sidecar in the pod
Containers in a pod already share a network namespace, so a tunnel container gives every container in that pod your address. Use a full tunnel config. Store it as a Secret — it holds a private key.
kubectl create secret generic aip-tunnel --from-file=aip0.conf=./anchoredip-42.confdeployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: partner-sync
spec:
replicas: 1 # see "replicas and peers" below
selector:
matchLabels: { app: partner-sync }
template:
metadata:
labels: { app: partner-sync }
spec:
containers:
- name: tunnel
image: lscr.io/linuxserver/wireguard:latest
securityContext:
capabilities:
add: ["NET_ADMIN"]
volumeMounts:
- name: conf
mountPath: /config/wg_confs
readOnly: true
- name: app
image: your/app:latest
volumes:
- name: conf
secret:
secretName: aip-tunnel
defaultMode: 0400Pattern 2 — one egress proxy for the cluster
Better when several workloads need the same identity. Run the tunnel once, behind a Service, and have your applications use it as an HTTP proxy. One peer, one machine slot, any number of clients.
egress.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: aip-egress
spec:
replicas: 1
selector:
matchLabels: { app: aip-egress }
template:
metadata:
labels: { app: aip-egress }
spec:
containers:
- name: tunnel
image: lscr.io/linuxserver/wireguard:latest
securityContext:
capabilities: { add: ["NET_ADMIN"] }
volumeMounts:
- { name: conf, mountPath: /config/wg_confs, readOnly: true }
- name: proxy
image: ubuntu/squid:latest
ports:
- { containerPort: 3128 }
volumes:
- name: conf
secret: { secretName: aip-tunnel, defaultMode: 0400 }
---
apiVersion: v1
kind: Service
metadata:
name: aip-egress
spec:
selector: { app: aip-egress }
ports:
- { port: 3128, targetPort: 3128 }in your application
env:
- name: HTTPS_PROXY
value: http://aip-egress:3128
- name: HTTP_PROXY
value: http://aip-egress:3128
- name: NO_PROXY
value: .svc,.cluster.local,10.0.0.0/8Set NO_PROXY carefully. Without it, in-cluster calls take a detour to Kazakhstan and back, which turns a sub-millisecond hop into a few hundred milliseconds and will look like your application got slow for no reason.
Managed clusters
Nothing here needs a cloud-specific feature — no NAT gateway, no reserved IP, no VPC peering. It works the same on EKS, GKE, AKS, DigitalOcean, Hetzner and a k3s box under a desk, which is the point: the identity belongs to you rather than to the cluster, and it survives you moving the cluster.
NET_ADMIN is required for the tunnel container. On a cluster with a restrictive Pod Security Standard, that container needs the baseline profile; your application container does not have to be touched.
Verify
kubectl exec deploy/partner-sync -c app -- curl -s https://api.ipify.org
kubectl exec deploy/aip-egress -c tunnel -- wg showCheck from the application container, not the tunnel one. See troubleshooting if the handshake never completes — on a managed cluster, egress UDP is the usual culprit.