Introduction

DeepSeek Harness (DSH) adopts a “everything is a plugin” design philosophy. When using DSH to build scenarios that require remote access or API services, authentication is a key part of secure deployment. dsh-auth-tailscale is an adapter plugin that provides a connectionRequestAuthorizer implementation for the dsh-client-connection-authz plugin. This plugin leverages the identity information injected and spoofing-protected by Tailscale Serve to help developers implement access control based on exact user allowlists, ordinary usage capabilities, and administrative capabilities.

Core Features

This plugin acts as an authentication layer for Tailscale Serve and implements the following capabilities:

  1. Identity Injection and Spoofing Protection: It processes the Tailscale-User-Login, Tailscale-User-Name, and Tailscale-App-Capabilities headers, which are generated by Tailscale Serve.
  2. Fine-Grained Permission Control:
    • Exact user allowlist: Restricts specific login accounts using an allowlist.
    • Ordinary usage capability: Restricts ordinary API/WebSocket access using an App Capability.
    • Separate administrative capability: Restricts access to loopback privileged endpoints using an App Capability.
  3. Fail-Closed Mechanism: If identity information is missing, the identity format is invalid (such as malformed RFC 2047 encoding), the Capability JSON is invalid, or permissions are insufficient, the plugin denies access.

Installation

Before installation, ensure that the current GitHub credentials have permission to read private repositories. Use the following installation command:

gh auth setup-git
dsh plugin --profile web add \
  git+https://github.com/sperictao/dsh-client-connection-authz.git \
  git+https://github.com/sperictao/dsh-auth-tailscale.git

Note: The two repositories are currently private. The above command uses HTTPS credentials; you can also switch to an SSH URL with a configured public key.

Configuration

The plugin reads policies from environment variables through bundle patching. It is recommended to use both allowlists and capabilities to build defense in depth:

Environment Variable Meaning
DSH_TAILSCALE_ALLOWED_LOGINS A comma-separated Tailscale login allowlist (case-sensitive). If unset or resolved as empty, all remote logins are denied (local access is not affected).
DSH_TAILSCALE_USE_CAPABILITY The App Capability required for ordinary remote API/WebSocket access.
DSH_TAILSCALE_ADMIN_CAPABILITY The App Capability required for remote access to loopback privileged endpoints. If not configured, remote privileged calls always return 403.

Example configuration:

export DSH_TAILSCALE_ALLOWED_LOGINS='alice@example.com,bob@example.com'
export DSH_TAILSCALE_USE_CAPABILITY='example.com/cap/dsh'
export DSH_TAILSCALE_ADMIN_CAPABILITY='example.com/cap/dsh-admin'

Deployment Example

To ensure that identity headers are trustworthy, this plugin must be used with Tailscale Serve, and DSH’s listening address must be restricted.

1. Start DSH
Bind DSH to the loopback address to avoid direct exposure:

dsh --profile web \
  --host 127.0.0.1 \
  --port 3080 \
  --trusted-host your-node.your-tailnet.ts.net

2. Configure Tailscale Serve
Serve is responsible for terminating HTTPS, injecting identity headers, and forwarding capabilities:

tailscale serve --bg \
  --accept-app-caps=example.com/cap/dsh,example.com/cap/dsh-admin \
  3080

3. Tailscale Grants Configuration
Configure App Capabilities in the tailnet policy:

{
  "grants": [
    {
      "src": ["group:dsh-users"],
      "dst": ["tag:dsh-host"],
      "app": {
        "example.com/cap/dsh": [{}]
      }
    },
    {
      "src": ["group:dsh-admins"],
      "dst": ["tag:dsh-host"],
      "app": {
        "example.com/cap/dsh": [{}],
        "example.com/cap/dsh-admin": [{}]
      }
    }
  ]
}

Notes

  • Fail-Closed Behavior: An allowlist that is unset or resolves to an empty value is a valid configuration; the plugin will deny all remote logins (a warning is logged at startup) and will not fall back to anonymous access.
  • Listening Address Restrictions: dsh must be bound to 127.0.0.1. Do not bind to 0.0.0.0, and do not use a public Funnel instead of a private Serve.
  • Tagged Devices: The plugin requires Tailscale-User-Login, so tagged-device-only calls will be rejected.
  • Case Sensitivity: Login matching is exact and is not automatically lowercased.
  • Encoding Format: Non-ASCII identity/capability headers are only accepted as UTF-8 RFC 2047 Q-encoding; malformed formats do not fall back to the original value.
  • Capability Structure: The top-level value must be an object, and each value must be a non-empty array of objects; dangerous prototype keys are rejected.
  • Local Spoofing Risk: Other processes on the same host may still forge localhost request headers. This is a local process trust boundary and is not a remote boundary issue that Tailscale can resolve.

Compatibility Scope

This plugin has no DSH runtime dependency (it only depends on the type interfaces provided by cordis, schemastery, and the authz plugin) and is decoupled from DSH versions. Its compatibility is entirely dependent on the peer range for @dsh-external/dsh-client-connection-authz (^0.1.6-alpha.1-authz.1), so it needs to be aligned by version with the authz plugin.

Conclusion

This plugin provides a standardized identity authentication solution through Tailscale Serve, making it suitable for scenarios that require fine-grained permission control in DSH. When using it, pay attention to its fail-closed security policy and the local process trust boundary.