Access an IP address behind a subnet router

Last validated:

You can make an IP address that is behind a subnet router accessible to your Kubernetes cluster workloads using an egress ProxyGroup. This is useful for accessing resources that are not directly on your tailnet but are reachable through a subnet router, such as databases or internal services on a private network.

Your cluster workloads access the target using a Kubernetes Service name, like any other in-cluster Kubernetes Service.

A diagram showing ProxyGroup egress architecture for accessing an IP address behind a subnet router.

Prerequisites

Before you begin, make sure you have the following:

  • Install the Tailscale Kubernetes Operator.
  • A subnet router advertising the route that contains the target IP address.
  • An egress ProxyGroup. Refer to the following section for an example.

Create an egress ProxyGroup

Create a ProxyGroup with spec.type set to egress:

apiVersion: tailscale.com/v1alpha1
kind: ProxyGroup
metadata:
  name: egress-proxies
spec:
  type: egress
  replicas: 2

Refer to high availability for production configuration options.

Create a ProxyClass to accept routes

To reach the target IP address, the egress proxy must accept advertised subnet routes. Create a ProxyClass with acceptRoutes enabled:

apiVersion: tailscale.com/v1alpha1
kind: ProxyClass
metadata:
  name: accept-routes
spec:
  tailscale:
    acceptRoutes: true

Create an egress Kubernetes Service

Create a Kubernetes ExternalName Service that references the ProxyGroup, the ProxyClass, and the target IP address:

apiVersion: v1
kind: Service
metadata:
  name: my-subnet-target
  annotations:
    tailscale.com/tailnet-ip: "<ip-behind-subnet-router>"
    tailscale.com/proxy-group: "egress-proxies"
    tailscale.com/proxy-class: "accept-routes"
spec:
  type: ExternalName
  externalName: placeholder
  ports:
    - port: 80
      protocol: TCP
      name: http

The externalName field is overwritten by the Operator. Set spec.ports to match the ports exposed by the target.

The Kubernetes ExternalName Service must explicitly list all ports you want to access in spec.ports. Only port, protocol, and name are used. Other port fields have no effect.

Verify access

Wait for the Kubernetes Service to become ready:

kubectl wait svc my-subnet-target --for=condition=TailscaleEgressSvcReady=true --timeout=5m

Access the target from your workloads using the Kubernetes DNS name:

curl http://my-subnet-target.default.svc.cluster.local

Traffic is round-robin load balanced across the ProxyGroup replicas. Any number of egress Service resources can reference a single ProxyGroup.

Limitations

The following limitations apply to IP-based egress access through subnet routers:

  • Only single IP addresses are supported. IP ranges are not supported.
  • 4via6 addresses are not supported.

Refer to IPv6 support for more information.

Further exploration