> ## Documentation Index
> Fetch the complete documentation index at: https://namespace.so/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Tailscale

export const CenteredImage = ({src, alt, width, caption, className}) => {
  const [basePath, setBasePath] = useState("");
  useEffect(() => {
    const path = window.location.pathname;
    setBasePath(path === "/docs" || path.startsWith("/docs/") ? "/docs" : "");
  }, []);
  return <Frame caption={caption} className={className} style={{
    maxWidth: width,
    marginInline: "auto"
  }}>
			<OptimizedImage src={`${basePath}${src}`} alt={alt} />
		</Frame>;
};

Connect Namespace workloads to your Tailscale tailnet with workload identity federation.

<Info>
  Tailscale integration is currently supported for Linux workloads only.
</Info>

Namespace relies on workload identity federation to connect your workloads to your Tailscale tailnet.
To get started, you need a Tailscale OIDC client ID and the set of tags that Namespace workloads
should advertise when they register.

At runtime, Namespace issues a short-lived OpenID Connect ID token and uses it to register the
workload with your tailnet. No long-lived Tailscale auth key or client secret needs to be stored
in Namespace.

## Configure Tailscale

Use the Tailscale admin console to create the client ID that Namespace will store.

<Steps titleSize="h3">
  <Step title="Create an OpenID Connect trust credential">
    Open Tailscale's [Trust credentials](https://login.tailscale.com/admin/settings/trust-credentials) page,
    select **Credential**, then choose **OpenID Connect**.
  </Step>

  <Step title="Configure Namespace as the issuer">
    Configure the credential to trust Namespace's OIDC issuer:

    * **Issuer**: `Custom issuer`
    * **Issuer URL**: `https://federation.namespaceapis.com`
    * **Subject**: `<workspace-id>/*`

    The subject pattern above allows workloads from one Namespace workspace to join your tailnet.
    Namespace issues ID tokens with subjects in the form `<workspace-id>/<instance-id>` for workloads.

    You can find your workspace ID in [Workspace settings](https://cloud.namespace.so/workspace/settings).

    <CenteredImage width={900} alt="Tailscale OpenID Connect trust credential settings" src="/docs/images/integrations/tailscale-credential-setup-1.png" />
  </Step>

  <Step title="Grant node-registration access and tags">
    Grant the credential the ability to register nodes and select the tags that Namespace workloads are allowed to advertise.
    The tags you save in Namespace must be a subset of the tags allowed here.

    For Namespace-managed node registration, enable the scope that allows auth key generation for node joins:

    * **Scope**: `auth_keys`
    * **Tags**: every tag you plan to pass through `nsc integrations tailscale set --tag ...`

    After you generate the credential, Tailscale shows both a **Client ID** and an **Audience**.
    Namespace only needs the **Client ID**. It automatically requests an ID token with audience `api.tailscale.com/<client-id>`.

    <CenteredImage width={900} alt="Tailscale scopes and tags for Namespace workload identity" src="/docs/images/integrations/tailscale-credential-setup-2.png" />
  </Step>
</Steps>

## Configure the integration in Namespace

Once you have the Tailscale client ID, store it in your Namespace workspace with a friendly name.

You can do this from the [Integrations page](https://cloud.namespace.so/workspace/integrations) in the Namespace console, or with the CLI:

```bash theme={null}
nsc integrations tailscale set corp --oauth-client-id <tailscale-client-id> --tag tag:namespace --tag tag:ci
```

This command creates or replaces the named spec `corp`.
The stored tags are the tags Namespace passes to `tailscale up --advertise-tags=...` when the workload joins your tailnet.

You can pass tags either multiple times or as a comma-separated list:

```bash theme={null}
nsc integrations tailscale set corp \
  --oauth-client-id <tailscale-client-id> \
  --tag tag:namespace,tag:ci
```

### Magic DNS

You can enable [Tailscale Magic DNS](https://tailscale.com/kb/1081/magicdns) so that workloads
can reach other devices on your tailnet by their machine name. To enable it, pass the `--enable-magic-dns` flag:

```bash theme={null}
nsc integrations tailscale set corp \
  --oauth-client-id <tailscale-client-id> \
  --tag tag:namespace \
  --enable-magic-dns
```

You can also toggle Magic DNS directly from the [Integrations page](https://cloud.namespace.so/workspace/integrations).
To test that Magic DNS is working correctly you can perform a DNS lookup:

```bash theme={null}
dig +search +short <device-name>
```

## Inspect And Remove Specs

List the currently configured Tailscale specs in your workspace:

```bash theme={null}
nsc integrations tailscale list
```

To inspect the full machine-readable response instead, use JSON output:

```bash theme={null}
nsc integrations tailscale list --output json
```

Remove a named spec when you no longer need it:

```bash theme={null}
nsc integrations tailscale remove corp
```

## How Namespace Uses The Spec

When a Namespace workload uses one of these named specs, Namespace resolves the saved client ID and tags,
issues a short-lived ID token from `https://federation.namespaceapis.com`, and joins Tailscale with:

```bash theme={null}
tailscale up \
  --client-id="<tailscale-client-id>?preauthorized=true&ephemeral=true" \
  --id-token="$ID_TOKEN" \
  --advertise-tags=tag:namespace,tag:ci
```

This means:

* You keep long-lived Tailscale secrets out of Namespace
* Each workload authenticates with a short-lived Namespace-issued OIDC token
* Tailscale authorization stays scoped to the workspace and tags you configured above
* Devices are registered as ephemeral and auto-removed after going offline

### Use with GitHub Actions

You can connect your CI runners to your Tailscale tailnet by adding the `tailscale.spec` feature
to your runner configuration. This lets your GitHub Actions workflows access private services
on your tailnet (e.g. databases, staging environments, internal APIs).

<Tabs>
  <Tab title="With runner profiles">
    Append the `tailscale.spec` feature to your profile name:

    ```yaml {2} theme={null}
    runs-on:
      - namespace-profile-my-profile;tailscale.spec=corp
    ```
  </Tab>

  <Tab title="With runner labels">
    Add the `tailscale.spec` feature to the `namespace-features` label:

    ```yaml {3} theme={null}
    runs-on:
      - nscloud-ubuntu-22.04-amd64-4x16-with-features
      - namespace-features:tailscale.spec=corp
    ```
  </Tab>
</Tabs>

The runner will automatically join your tailnet before the workflow job starts.
Replace `corp` with the name of the Tailscale spec you created with `nsc integrations tailscale set`.

See [Connecting to Tailscale](/docs/reference/github-actions/runner-configuration#connecting-to-tailscale) in the runner configuration reference for how
this feature fits alongside other runner settings.

### Use with Devboxes

Devboxes support Tailscale out of the box. You can enable it in two ways:

* **Workspace defaults**: workspace admins can select a Tailscale spec on the [Devboxes defaults page](https://cloud.namespace.so/workspace/devboxes/defaults) so every new Devbox automatically joins your tailnet.
* **Per-devbox configuration**: add the integration to your Devbox YAML config:

```yaml theme={null}
integrations:
  tailscale:
    spec: corp
```

See [Creating from a spec file](/docs/devbox/managing#creating-from-a-spec-file) for the full configuration reference.

## Notes

* Tailscale integration is currently supported for Linux workloads.
* The named integration only stores the client ID and tags; it does not store a Tailscale client secret.
* If Tailscale rejects the advertised tags, check that the same tags are allowed on the Tailscale trust credential.
* For more background on Namespace-issued OIDC tokens, see [Workload Federation with OpenID Connect](/docs/federation/openid).
