A Kubernetes operator that exposes Services on a Tailscale (or Headscale) tailnet.
t7e watches Kubernetes Services. For each whitelisted Service it joins the
tailnet as an ephemeral host named <prefix>-<namespace>-<servicename> and
forwards every matched TCP port to the Service's ClusterIP (falling back to
in-cluster DNS for headless Services). Kubernetes handles load-balancing.
It also serves a server-side-rendered web dashboard as its own tailnet host
(reachable at http://<prefix>/, e.g. http://t7e/) listing all currently
exposed services with a clickable link per forwarded port.
Matching is per-port and TCP only; non-TCP ports are skipped.
The operator is configured by a YAML file (typically mounted from a ConfigMap),
passed via --config (default config.yaml). There is no hot-reload — restart
the pod to apply changes.
# prefix is prepended to every tailnet hostname: <prefix>-<namespace>-<service>.
prefix: t7e
# controlURL is the tailscale/headscale control server.
controlURL: https://headscale.example.com:443
# whitelist selects which service ports get exposed. A port is exposed if it
# matches ANY entry; within an entry every set field must match (AND). Unset
# fields match anything. String fields (namespace, serviceName, protocol) are
# case-insensitive globs ("*", "?"); port is an exact match.
whitelist:
# Expose every TCP port of services named "api-*" in the prod namespace.
- namespace: prod
serviceName: "api-*"
# Expose port 443 of any service in any namespace.
- port: 443| Flag | Env | Description |
|---|---|---|
--config |
CONFIG |
Path to the YAML config file (default config.yaml). |
--auth-key |
T7E_AUTH_KEY |
Tailscale/Headscale auth key (required). |
--kubeconfig |
KUBECONFIG |
Path to kubeconfig; used only when not running in-cluster. |
In-cluster the operator uses the pod's service account; locally it falls back to the kubeconfig.