Expose a Kubernetes cluster workload to your tailnet (cluster ingress)
You can use the Tailscale Kubernetes operator to expose a Kubernetes cluster workload to your tailnet in three ways:
- Create a
LoadBalancer
typeService
with thetailscale
loadBalancerClass
that fronts your workload. - Annotate an existing
Service
that fronts your workload. - Create an
Ingress
resource fronting aService
orService
s for the workloads you wish to expose.
Prerequisites
Exposing a cluster workload via a tailscale Load Balancer Service
Create a new Kubernetes Service
of type LoadBalancer
:
- Set
spec.type
toLoadBalancer
. - Set
spec.loadBalancerClass
totailscale
.
After provisioning completes, the Service
status will show the fully-qualified domain name of the Service
in your tailnet. You can view the Service
status by running kubectl get service <service name>
.
You should also see a new node with that name appear in the Machines page of the admin console.
Exposing a cluster workload by annotating an existing Service
If the Service
you want to expose already exists, you can expose it to Tailscale using object annotations.
Edit the Service
and under metadata.annotations
, add the annotation tailscale.com/expose
with the value "true"
. Note that "true"
is quoted because annotation values are strings, and an unquoted true
will be incorrectly interpreted as a boolean.
In this mode, Kubernetes doesn’t tell you the Tailscale machine name. You can look up the node in the Machines of the admin console to learn its machine name. By default, the machine name of an exposed Service
is <k8s-namespace>-<k8s-servicename>
, but it can be changed.
Exposing a Service
using Ingress
You can use the Tailscale Kubernetes operator to expose an Ingress
resource in your Kubernetes cluster to your tailnet. When configured using an Ingress
resource, you also get the ability to identify callers using HTTP headers injected by the Ingress
proxy.
Ingress
resources only support TLS, and are only exposed over HTTPS. You must enable HTTPS on your tailnet.
Edit the Ingress
resource you want to expose to use the Ingress
class tailscale
:
- Set
spec.ingressClassName
totailscale
. - Set
tls.hosts
to the desired host name of the Tailscale node. Only the first label is used. See custom machine names for more details.
For example, to expose an Ingress
resource nginx
to your tailnet:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx
spec:
defaultBackend:
service:
name: nginx
port:
number: 80
ingressClassName: tailscale
tls:
- hosts:
- nginx
The backend is HTTP by default. To use HTTPS on the backend, either set the port name to https
or the port number to 443
:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx
spec:
defaultBackend:
service:
name: nginx
port:
name: https
ingressClassName: tailscale
---
apiVersion: v1
kind: Service
metadata:
name: nginx
spec:
ports:
- name: https
port: 443
targetPort: 443
type: ClusterIP
A single Ingress
resource can be used to front multiple backend Services
:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress
spec:
ingressClassName: tailscale
rules:
- http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: ui-svc
port:
number: 80
- path: /api
pathType: Prefix
backend:
service:
name: api-svc
port:
number: 80
Currently the only supported Ingress
path type is Prefix
. Requests for paths with other path types will be routed according to Prefix
rules.
Exposing a Service
to the public internet using Ingress
and Tailscale Funnel
You can also use the Tailscale Kubernetes operator to expose an Ingress
resource in your Kubernetes cluster to the public internet using Tailscale Funnel. To do so:
-
Add a
tailscale.com/funnel: "true"
annotation:apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: funnel annotations: tailscale.com/funnel: "true" spec: defaultBackend: service: name: funnel port: number: 80 ingressClassName: tailscale tls: - hosts: - funnel
-
Update the ACLs for your tailnet to allow Kubernetes Operator proxy services to use Tailscale Funnel.
Add a node attribute to allow nodes created by the Kubernetes operator to use Funnel:
"nodeAttrs": [
{
"target": ["tag:k8s"], // tag that Tailscale Operator uses to tag proxies; defaults to 'tag:k8s'
"attr": ["funnel"],
},
...
]
Note that even if your policy has the funnel
attribute assigned to autogroup:member
(the default), you still need to add it to the tag used by proxies because autogroup:member
does not include tagged devices.
Removing a Service
Any of the following actions remove a Kubernetes Service
you exposed from your tailnet:
- Delete the
Service
entirely. - If you use the
tailscale.com/expose
annotation, remove the annotation. - If you use an
Ingress
resource, delete it or change or unsetspec.ingressClassName
.
Deleting a Service
's Tailscale node in the admin console does not clean up the Kubernetes state associated with that Service
.
IPv6 support
Ingress
To proxy traffic to IPv6 backends, you might need to disable IPv4 tailnet addresses for the proxy tailnet nodes.
You need to disable IPv4 tailnet addresses for:
-
Proxies used to expose cluster workloads using Tailscale ingress
Service
s if they are running in a cluster that allocates IPv6 addresses toService
s. -
Proxies used to expose cloud services using Tailscale ExternalName
Service
s if the cloud services have IPv6 addresses.
You can disable tailnet IPv4 addresses for a specific tag using a disable-ipv4
node attribute in ACLs.
The following node attributes configuration example disables IPv4 addresses for all nodes tagged with tag:k8s
:
"nodeAttrs": [
{
"target": ["tag:k8s"],
"attr": [
"disable-ipv4",
],
},
]
Tailnet IPv6 connectivity does not depend on host support for IPv6, so you can disable IPv4 addresses for nodes running on hosts that do not support IPv6.
Similarly, tailnet clients can connect to proxies with only tailnet IPv6 addresses even if they aren't running on hosts with IPv6 support.
Customization
Learn how to customize the operator and resources it manages.
Troubleshooting
Learn how to troubleshoot the operator and resources it manages.
Limitations
- Tags are only considered during initial provisioning. That is, editing
tailscale.com/tags
on an already exposedService
doesn’t update the tags until you clean up and re-expose theService
. - The requested machine name is only considered during initial provisioning. That is, editing
tailscale.com/hostname
on an already exposedService
doesn't update the machine name until you clean up and re-expose theService
. - Cluster-ingress using Kubernetes
Ingress
resource requires TLS certificates. Currently, the certificates are provisioned on the first connect. This means that the first connection might be slow or even time out.