Control access to ProxyGroup resources

Last validated:

When managing a multi-tenant Kubernetes cluster, you can limit access to your deployed ProxyGroup resources, especially when those ProxyGroup instances use different tailnets. In Tailscale v1.96 and later, you can use the ProxyGroupPolicy resource to let cluster administrators limit usage of the tailscale.com/proxy-group annotation on Service and Ingress resources within individual namespaces.

ProxyGroupPolicy resources let you specify whether a namespace can use a given ProxyGroup for ingress or egress. If a user attempts to create an Ingress or Service that specifies a ProxyGroup name that is not within the allow list, the Kubernetes API server rejects it.

Prerequisites

A namespace that contains no ProxyGroupPolicy resource is effectively considered an "allow-all". When you apply a ProxyGroupPolicy to a namespace that already contains Service or Ingress resources using the tailscale.com/proxy-group annotation, these resources are not evaluated until they are next modified.

The following example shows a ProxyGroupPolicy that limits access to all ProxyGroup resources, effectively a "deny-all" policy:

apiVersion: tailscale.com/v1alpha1
kind: ProxyGroupPolicy
metadata:
  name: deny-all
  namespace: example
spec:
  ingress: []
  egress: []

The operator transforms this ProxyGroupPolicy into native ValidatingAdmissionPolicy and ValidatingAdmissionPolicyBinding resources that evaluate the contents of the tailscale.com/proxy-group annotation on Ingress and Service resources within the same namespace.

If a namespace contains multiple ProxyGroupPolicy resources, the operator merges them into a single ValidatingAdmissionPolicy resource.

Multi-tenant example

Consider a multi-tenant Kubernetes cluster in which teams use separate tailnets for their services and each team has a namespace within the cluster for their own workloads.

To set up access to their respective tailnets, create a ProxyGroup resource for each team pointing to their tailnets. To ensure ingress or egress is not allowed to any other tailnets from those namespaces, specify a ProxyGroupPolicy for each namespace:

apiVersion: tailscale.com/v1alpha1
kind: ProxyGroupPolicy
metadata:
  name: billing
  namespace: team-billing
spec:
  ingress:
    - billing-ingress
  egress:
    - billing-egress
---
apiVersion: tailscale.com/v1alpha1
kind: ProxyGroupPolicy
metadata:
  name: customer-engineering
  namespace: team-customer-engineering
spec:
  ingress:
    - customer-engineering-ingress
  egress:
    - customer-engineering-egress

This configuration only lets Service and Ingress resources within the team-billing namespace use the billing-ingress and billing-egress tailscale.com/proxy-group annotations. The Kubernetes API server rejects the following Ingress resource because it references a ProxyGroup from another team:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: example-ingress
  namespace: team-billing
  annotations:
    tailscale.com/proxy-group: customer-engineering-egress
spec:
  defaultBackend:
    service:
      name: example
      port:
        number: 80
  ingressClassName: tailscale
  tls:
    - hosts:
        - example

The same applies to any other ingress or egress methods the operator supports that rely on ProxyGroup resources.