Get started
Login
© 2024

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 type Service with the tailscale loadBalancerClass that fronts your workload.
  • Annotate an existing Service that fronts your workload.
  • Create an Ingress resource fronting a Service or Services for the workloads you wish to expose.

Prerequisites

Exposing a cluster workload using a Kubernetes Service

Exposing a cluster workload via a tailscale Load Balancer Service

Create a new Kubernetes Service of type LoadBalancer:

  1. Set spec.type to LoadBalancer.
  2. Set spec.loadBalancerClass to tailscale.

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 cluster workloads using a Kubernetes Ingress

You can expose cluster workloads either to your tailnet or the public internet over TLS using anIngress resource. When 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 using a MagicDNS name and publicly trusted certificates from LetsEncrypt. You must enable HTTPS and MagicDNS on your tailnet.

Edit the Ingress resource you want to expose to use the Ingress class tailscale:

  1. Set spec.ingressClassName to tailscale.
  2. 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.

A Tailscale Ingress can only be accessed on port 443.

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:

  1. 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
    
  2. 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 unset spec.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:

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 exposed Service doesn’t update the tags until you clean up and re-expose the Service.
  • The requested machine name is only considered during initial provisioning. That is, editing tailscale.com/hostname on an already exposed Service doesn't update the machine name until you clean up and re-expose the Service.
  • 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.

Last updated Dec 20, 2024