Skip to content

Attach a cluster to your own tailnet

Bridge a Longbridge cluster into a Tailscale tailnet you already operate — your coordination plane, your ACLs — with a managed connector. Covers the copy-paste ACL stanza, both authentication modes, and reaching services by name.

A Mesh network is a tailnet Longbridge runs the coordination plane for. But if you already run your own Tailscale tailnet (or a self-hosted Headscale), you can bridge a cluster straight into it instead — same managed connector, but it joins your network under your ACLs. Your existing machines reach the cluster’s pods and services with nothing new to install.

The trade is ownership: because it’s your tailnet, you own the two policy decisions Longbridge otherwise makes for you — which tag the connector carries, and whether its advertised routes are approved. Both live in your tailnet’s ACL, and this guide gives you the stanza to paste.

You’ll need: a cluster with at least one node, Console access (or the Terraform provider), and admin on a Tailscale tailnet. A QEMU VM makes a fine throwaway node.

1. Choose a tag

The connector joins your tailnet as a tagged node — never a user’s device. Pick a tag you’ll recognize, for example tag:corp. It’s yours, in your namespace; the only tags Longbridge refuses are its own reserved tag:lb-*.

2. Add the ACL stanza

Paste this into your tailnet’s ACL (Tailscale admin console → Access controls), adjusting the tag and the CIDRs to match. It does two things: lets you own the tag, and auto-approves the routes the connector advertises so you don’t hand-approve them every time the connector restarts.

{
  "tagOwners": {
    "tag:corp": ["autogroup:admin"]
  },
  "autoApprovers": {
    "routes": {
      "10.244.0.0/16": ["tag:corp"],
      "10.96.0.0/16": ["tag:corp"]
    }
  }
}
  • tagOwners lets an admin mint credentials that stamp tag:corp on a device — the connector is one such device.
  • autoApprovers.routes says a device tagged tag:corp may advertise those CIDRs and have them approved automatically. They are the cluster’s pod and service ranges (10.244.0.0/16 and 10.96.0.0/16 by default; a carved cluster uses the ranges you chose). Without this the attachment stays Awaiting approval until you approve the routes by hand.

3. Create a credential

Longbridge joins the connector with a credential you supply. Two modes — pick one:

  • Auth key — the simplest. In the Tailscale admin console, mint a reusable, pre-approved, tagged auth key (tag tag:corp). Longbridge uses it verbatim. Works with a self-hosted Headscale too.
  • OAuth client — the tidiest for the long run. Create an OAuth client with the auth_keys scope and the tag tag:corp. Longbridge mints a fresh, ephemeral key per connector from it, so there’s no long-lived shared secret in the cluster. OAuth is a Tailscale-managed-tailnet feature; a self-hosted Headscale uses an auth key.

Your credential is sent to the shard and stored there as a Kubernetes Secret in the cluster’s management namespace. It is never persisted by the Console.

4. Attach

In the Console, open the cluster’s Networking tab and choose Attach external network. Pick your authentication mode, paste the credential, and enter the tag (tag:corp) and — for a self-hosted Headscale — its login server. Leave the routes at Pods + services unless you want to expose less.

Prefer code? The Terraform resource does the same:

resource "longbridge_control_plane_external_attachment" "corp" {
  cluster   = "test"
  auth_mode = "oauth"
  tag       = "tag:corp"
  # login_server defaults to Tailscale's own; set it for a self-hosted Headscale.

  client_id     = var.tailscale_client_id
  client_secret = var.tailscale_client_secret
  # or, for auth_mode = "authKey":
  # auth_key = var.tailscale_auth_key
}

The credential attributes are write-only — Terraform sends them on create and never reads them back, so they won’t show up in a later plan.

5. Check it’s serving

The attachment reports two things it can actually observe:

  • connectorReady — the connector is up in the cluster.
  • routesApproved — the connector’s own tailscale status shows your tailnet has approved the advertised routes. If you added the auto-approver in step 2 this flips to Serving on its own; if it’s stuck on Awaiting approval, your ACL auto-approver isn’t matching the tag or the CIDRs.

Once it’s Serving, any machine on your tailnet reaches the cluster by ClusterIP:

curl http://10.96.0.10       # e.g. a Service's ClusterIP

Reach services by name (optional)

Routing works by IP out of the box. To resolve cluster names, point a Tailscale split-DNS nameserver at the cluster’s in-cluster DNS: in Access controls → DNS, add a nameserver for the cluster.local domain pointing at kube-dns’s ClusterIP (usually the .10 of the service range, 10.96.0.10). Because the connector advertises the whole service range, that address is reachable, so your machines resolve my-svc.my-ns.svc.cluster.local and connect. (The per-cluster *.cluster.internal rewrite that managed networks offer is Longbridge-side and doesn’t apply here.)

Detach

Detach from the cluster’s Networking tab, or terraform destroy the resource. The connector leaves the cluster and its machine deregisters from your tailnet; the cluster keeps running untouched. Re-attach any time.