Tailscale SSH

Tailscale SSH allows Tailscale to manage the authentication and authorization of SSH connections on your tailnet.

With Tailscale SSH, you can:

  • SSH as normal, using Tailscale for authentication. With Tailscale SSH, Tailscale takes over port 22 for SSH connections incoming from the Tailscale network. Tailscale will authenticate and encrypt the connection over WireGuard, using Tailscale node keys. The SSH client and server will still create an encrypted SSH connection, but it will not be further authenticated.
  • Verify high-risk connections with check mode. Optionally require certain connections, or connections as certain users (e.g., root), to re-authenticate before connecting. This allows the user to access these high-risk applications for the next 12 hours or for a specified check period before re-authenticating again.

Your SSH config (/etc/ssh/sshd_config) and keys (~/.ssh/authorized_keys) files will not be modified, which means that other SSH connections to the same host, not made over Tailscale, will still work.

Tailscale SSH is currently in beta. To try it, follow the steps below to enable it for your network using Tailscale v1.24 or greater.

How is Tailscale SSH different?

Historically, to secure an SSH connection, you generate a keypair on the machine you are connecting from (known as the client), with the private key stored on the client, and the public key distributed to the device you want to connect to (known as the server). This lets the server authenticate communication from the client.

With Tailscale, you can already connect machines in your network, and encrypt communications end-to-end from one point to another—and this includes, for example, SSHing from your work laptop to your work desktop. Tailscale also knows your identity, since that’s how you connected to your tailnet. When you enable Tailscale SSH, Tailscale claims port 22 for the Tailscale IP address (that is, only for traffic coming from your tailnet) on the devices for which you have enabled Tailscale SSH. This routes SSH traffic for the device from the Tailscale network to an SSH server run by Tailscale, instead of your standard SSH server. With Tailscale SSH, based on the ACLs in your tailnet, you can allow devices to connect over SSH and rely on Tailscale for authentication instead of public key authentication.

How does it work?

Compared to using SSH keys, using Tailscale SSH changes how authentication of your connections, key generation and distribution, and user revocation work.

Authentication and authorization

Normally, to establish an SSH connection, the local SSH client you use will connect to the SSH server on the machine you’re trying to reach.

With Tailscale SSH, Tailscale will authenticate and encrypt the connection over WireGuard, using Tailscale node keys. The SSH client and server will still create an SSH connection, but during the SSH protocol’s authentication phase, the Tailscale SSH server already knows who the remote party is and takes over, not requiring the SSH client to provide further proof (using the SSH authentication type none).

Tailscale will only authorize the two devices to connect if the ACLs in the tailnet allow it. Tailscale uses netstack port interception and just-in-time automatic configuration of the client known_hosts file to make ssh myhost work without any new binary or config file. Tailscale implements the SSH File Transfer Protocol (SFTP) which allows SCP and SFTP to work for newer SSH clients.

Encryption

With Tailscale SSH, in addition to encryption provided by the SSH protocol, Tailscale encrypts the connection end-to-end using WireGuard, which also includes integrity.

Key management and distribution

Tailscale already manages and distributes node keys and machine keys for devices in your tailnet. Tailscale uses the node key for authentication, authorization, and encryption of the SSH connection.

With Tailscale SSH, Tailscale also distributes public SSH host keys. The private key is stored locally, and the public key is shared with the Tailscale control plane for distribution. This host key means that the SSH client recognizes the host it is connecting to. Once the host is recognized, Tailscale stores the host key to avoid presenting the user with an “unknown host” error message.

Based on an ACL, if two devices are permitted to connect, then Tailscale’s control plane will share their public node keys for discovery, which lets these devices generate an end-to-end encrypted WireGuard connection. If also permitted by the ACL, Tailscale will share their public SSH host keys, which lets these devices be recognized as part of an SSH connection. If a key is compromised, the device can remove the keys on the device, re-install Tailscale, and re-authenticate to generate and distribute new node and SSH host keys.

User revocation

ACLs determine which devices, and which users, are authorized for an SSH connection. Unlike with SSH keys which need to be purged, to remove a user’s ability to SSH to a device, the ACL can be updated to restrict a user’s access. Once the ACL is saved, clients respond to the new rules within seconds. This will terminate existing SSH connections the user has established.

Check mode

Optionally, connections over Tailscale SSH can require a user to re-authenticate before establishing an SSH connection. This requires the user to sign in again with their identity provider. A user will not need to re-authenticate for other connections in check mode for the next 12 hours, or a specified check period.

Configure Tailscale SSH

Prerequisites

Tailscale SSH’s server component is only available on Linux. You can connect from any device running Tailscale, regardless of platform. Tailscale SSH’s server component requires Tailscale v1.24 or greater.

To enable Tailscale SSH, you must:

  • Advertise Tailscale SSH from the destination to which you want to connect.
  • Ensure an ACL exists that allows the source to connect to the destination on port 22.
    • This is not necessary if you haven’t modified the ACLs in your account, as the default ACL allows all traffic.
    • This may require modifying the ACL policy file to include SSH. You need to be an Admin or Network Admin in order to modify ACLs.
  • Ensure an ACL exists that allows the source to SSH to the destination machine using Tailscale SSH.
    • This is not necessary if you haven’t modified the ACLs in your account, as the SSH access rules in the default ACL allows all traffic.
    • This will require modifying the ACL policy file to include SSH policies. You need to be an Admin or Network Admin in order to modify ACLs.

On the host being connected to, you need to advertise that Tailscale is managing SSH connections which originate from the Tailscale network to this host. To do so, run:

tailscale up --ssh
Running tailscale up --ssh will cause any existing SSH connections you have to the host’s Tailscale IP to hang.

This generates a host keypair, shares its public half with the Tailscale control plane for distribution to clients, and configures tailscaled to intercept all traffic to port 22 on the Tailscale IP address. This SSH initialization only needs to be done once per host.

Ensure Tailscale SSH is permitted in ACLs

Before you can use Tailscale SSH, you have to tell Tailscale which users are allowed to SSH to which devices. Since Tailscale automatically manages the authorization and authentication for you, you need to explicitly define these connections.

SSH access rules are defined in the ACL policy file, which you can edit through the admin console, or through the Tailscale API.

For a connection to be permitted, the ACL policy file must contain rules permitting both network access and SSH access:

  1. An allowed connection from the source to the destination. This is used to allow any connections in Tailscale (including SSH connections), to distribute keys for WireGuard. See ACL rules to learn more.
  2. An allowed SSH connection from the source to the destination and the given SSH users. This is used for Tailscale SSH, to distribute keys for authenticating SSH connections.

Each SSH access rule looks like this:

{
  "action": "check", // "accept" or "check"
  "src": [list-of-sources],
  "dst": [list-of-destinations],
  "users": [list-of-ssh-users],
  "checkPeriod": "20h", // optional, only for check actions. default 12h
},

Where,

  • action, which is whether to accept the connection or to perform additional checks on it.
  • src, the source where a connection originates from. This can be a user, group, or tag.
  • dst, the destination where the connection goes. This can be a user, group, or tag. Note that unlike ACLs, a port cannot be specified. Only port 22 is allowed, and does not need to be specified as it is used by default.
  • users, which are the set of allowed usernames on the host. An SSH access rule can also specify autogroup:nonroot to allow any user that is not root. If no user is specified, Tailscale will use the local host’s user. That is, if I am logged in as alice locally, then SSH to another device, Tailscale SSH will try to log in as user alice. Like other SSH clients, Tailscale will only use user accounts that already exist on the host, not create new accounts.
  • Optionally, for check mode only, checkPeriod, which is the time period for which to allow a connection before requiring a check. This can be specified in minutes or hours, with a minimum of one minute and a maximum of 168 hours (one week). If not specified, this is 12 hours.

SSH access rules are evaluated considering the most restrictive policies first:

  • Check policies
  • Accept policies

For example, if you have an access rule allowing the user alice@example.com to access a resource with an accept rule, and a rule allowing group:devops which alice@example.com belongs to, to access a resource with a check rule, then the check rule applies.

The only kinds of connections that are allowed are:

  • From a user to their own devices, as any user including root.
  • From a user to a tagged device, as any user including root.
  • From a tagged device to another tagged device, for any tags. Note that an SSH access rule from a tagged device cannot be in check mode.

Tailscale SSH cannot be used to access nodes that are shared with you.

That is, the broadest policy allowed would be:

{
  "acls": [
    {
      "action": "accept",
      "src": ["*"],
      "dst": ["*:*"]
    }
  ],
  "ssh": [
    {
      "action": "accept",
      "src": ["autogroup:members"],
      "dst": ["autogroup:self"],
      "users": ["root", "autogroup:nonroot"]
    },
    {
      "action": "accept",
      "src": ["autogroup:members"],
      "dst": ["tag:prod"],
      "users": ["root", "autogroup:nonroot"]
    },
    {
      "action": "accept",
      "src": ["tag:logging"],
      "dst": ["tag:prod"],
      "users": ["root", "autogroup:nonroot"]
    }
  ]
}
SSH access rules in default ACL

By default, new tailnets or existing tailnets that have not modified their ACLs have a usable but conservative Tailscale SSH access rule. Tailscale SSH is configured with a default policy to allow the user to access their own devices using check mode, as either root or non-root:

    "ssh": [
    { // any user can use Tailscale SSH to connect to their own devices
      // in check mode as a root or non-root user
      "action": "check",
      "src": ["autogroup:members"],
      "dst": ["autogroup:self"],
      "users": ["autogroup:nonroot", "root"]
    },
  ]

This simplifies configuration for users who are less familiar with ACLs. You will still need to opt in a destination device.

Modifying the ACL for SSH overrides this default configuration, and removing it disables Tailscale SSH in your tailnet.

SSH access rule examples

To allow a user to only SSH to their own devices, as non-root:

{
  "acls": [
    {
      "action": "accept",
      "src": ["*"],
      "dst": ["*:*"]
    }
  ],
  "ssh": [
    {
      "action": "accept",
      "src": ["autogroup:members"],
      "dst": ["autogroup:self"],
      "users": ["autogroup:nonroot"]
    }
  ]
}

To allow group:sre to access devices in the production environment tagged tag:prod:


{
  "groups": {
    "group:sre": ["alice@example.com", "bob@example.com"]
  },
  "acls": [
    {
      "action": "accept",
      "src": ["group:sre"],
      "dst": ["tag:prod:*"]
    },
  ],
  "ssh": [
    {
      "action": "accept",
      "src": ["group:sre"],
      "dst": ["tag:prod"],
      "users": ["ubuntu", "root"],
    },
  ]
  "tagOwners": {
    // users in group:sre can apply the tag tag:prod
    "tag:prod": ["group:sre"]
  }
}

Connect over SSH

Now that your ACL allows SSH, and the destination host has Tailscale configured with SSH, you should be able to use Tailscale SSH!

To connect to another host device in your tailnet:

ssh device

You can use the MagicDNS hostname to further shorten or simplify the device used in this command.

To use a user different from the local user, specify the user, e.g., ubuntu:

ssh ubuntu@device

Transition from your existing SSH client to Tailscale SSH

When you enable Tailscale SSH, Tailscale claims port 22 on the devices for which you have enabled SSH, and routes SSH traffic for the device to an SSH server run by Tailscale, instead of your standard SSH server. Your SSH config (/etc/ssh/sshd_config) and keys (~/.ssh/authorized_keys) file will not be modified, which means that other SSH connections to the same host, not made over Tailscale, will still work.

Rotate keys

Re-authenticating on the device will generate a new node keypair, store the private key locally, and share the public key with Tailscale for distribution.

To generate new node and SSH host keys:

tailscale up --ssh --force-reauth

Disable Tailscale SSH

Disable Tailscale SSH from a device

Prior to disabling Tailscale SSH, ensure you have another way to SSH to the device, or else you may lose access to it.

Run tailscale up on the device with --ssh=false to disable Tailscale SSH:

tailscale up --ssh=false

Block other devices from connecting to your device over SSH

To disable Tailscale SSH on your device, re-authenticate the device with --ssh=false:

tailscale up --ssh=false

To block incoming connections from the tailnet to your device, including Tailscale SSH connections:

tailscale up --shields-up

Revoke a user’s ability to SSH

To remove a user’s ability to SSH to a device, modify the ACL rule specifying the user’s ability to SSH to the device. An update to ACLs will be pushed to the device, and remove the user’s access, almost instantaneously. You can still allow the user to connect to the device, but not use Tailscale SSH, if that is desired.

This will terminate existing SSH connections the user has established. The user will receive a message, “Access revoked”.

If a user has another way of accessing the device outside of Tailscale, such as their SSH key, this also needs to be removed or revoked.

Disable Tailscale SSH from your tailnet

To completely remove Tailscale SSH functionality from your tailnet:

  • Opt out every host from Tailscale SSH (tailscale up --ssh=false)
  • Remove SSH access rules for Tailscale SSH from the ACLs

You do not need to remove or modify other ACL rules if you still want users to be able to access the specified devices, but not using Tailscale SSH.

Misconfigurations

Tailscale SSH requires ACLs in the config file that allow and specify both the SSH source and destination. Additionally, Tailscale SSH must be enabled on the destination device.

If the ACL is missing, this can be changed in the ACL policy file in the admin console. You need to be an Admin or Network Admin in order to modify ACLs.

If SSH is not advertised on the device, connect to the device over Tailscale, then run tailscale up --ssh.

Configure Tailscale SSH with check mode

SSH check mode allows you to require SSH connections to be further verified before establishing the connection. Check mode requires re-authentication on the device initiating the connection. The SSH initialization provides a URL for signing in. The sign-in attempt may also trigger any identity provider 2FA/MFA or other risk-based challenges.

Example of check mode requiring a user to re-authenticate their session in a browse
Example of check mode requiring a user to re-authenticate their session in a browser

Once re-authenticated to a destination, the user can access the device and any other device on the tailnet without re-verification for the next 12 hours. If a different check period is specified for the connection, then the user can access specifically this device without re-verification for the duration of the check period. For example, if a check period of 10 minutes is specified, if the user has not re-authenticated within the last 10 minutes, they will be asked to re-authenticate even if they have re-authenticated within the last 12 hours.

Check mode is optional and not enabled by default. Check mode is only available for Tailscale SSH connections.

Check mode is controlled through ACL settings. The ssh rule must contain the action field, set to check:

"ssh": [
  {
    "action": "check", // instead of "accept"
    "src": ["autogroup:members"],
    "dst": ["autogroup:self"],
    "users": ["autogroup:nonroot"],
    "checkPeriod": "5m", // optional, in minutes or hours
  }
]

For example, to require check mode for Alice to SSH to devices tagged tag:prod as root and re-authenticate after 1h, but not require check mode for her to SSH to her own devices as non root:

{
  "acls": [
    {
      // All users can connect to all devices using Tailscale
      "action": "accept",
      "src": ["*"],
      "dst": ["*:*"]
    }
  ],
  "ssh": [
    {
      // Alice can use Tailscale SSH to connect to her own devices as a non-root user
      "action": "accept",
      "src": ["alice@example.com"],
      "dst": ["autogroup:self"],
      "users": ["autogroup:nonroot"]
    },
    {
      // Alice can use Tailscale SSH to connect to devices with tag:prod as root user using check mode, with a check period of 1 hour
      "action": "check",
      "src": ["alice@example.com"],
      "dst": ["tag:prod"],
      "users": ["root"],
      "checkPeriod": "1h"
    }
  ]
}

Single-user tailnets

For single-user tailnets on the Personal and Personal Pro plans (such as Gmail accounts), Tailscale SSH is configured with a default policy to allow the user to access their own devices using check mode.

  "ssh": [
    { // Alice can use Tailscale SSH to connect to her own devices in check mode as a non-root user
      "action": "check",
      "src": ["alice@example.com"],
      "dst": ["alice@example.com"],
      "users": ["autogroup:nonroot", "root"]
    },
  ]

Adding an ACL for SSH overrides this default configuration.

Limitations

Devices
  • You can currently use Tailscale SSH to connect to only devices on your Tailscale network. Devices available behind subnet routers, but not running Tailscale, cannot use Tailscale SSH.
  • You can currently use Tailscale SSH to connect to only Linux devices. You can connect from any device running Tailscale, regardless of platform.
  • Restarting the Tailscale daemon (tailscaled), for example by performing an upgrade, will terminate any existing Tailscale SSH session.
Ports

Tailscale SSH assumes you use port 22 for SSH. At this time, there is no way to configure Tailscale SSH to use a different port.

SSH users

SSH access rules are evaluated based on their restrictiveness, so if both a check and an accept rule exist for a given connection, the check rule applies. This means that the user will be restricted by the SSH users in the check rule only, not also considering those allowed in the accept rule.

ACL tests

You cannot currently write ACL tests that include SSH access rules.

Check mode

You can use check mode only on Tailscale SSH connections, not for other SSH connections or for other Tailscale connections.

Best practices to use Tailscale SSH with servers

If you’re setting up servers on Tailscale, and want to use Tailscale SSH to access them, we recommend you use an auth key to provision the server, and an ACL tag to restrict its access.

Here’s how to set up Tailscale SSH on a server:

  1. Create a new ACL tag in your tailnet for the type of shared resource you are managing. For example, this might be its purpose, like server; an environment, like prod or test; or another grouping of resources you have, like front-end. To create a tag, modify the ACL config file to specify the owner of the tag, which is the team or user who can use that tag. If you have an existing tag that’s used for all servers you want to SSH to, that works—else, we recommend setting up a new tag just for this SSH access.

    {
      "tagOwners": {
        "tag:server": ["alice@example.com"]
      }
    }
    
  2. Write ACL rules in the ACL config file which:

    • Allow the desired sources to reach the tagged resources
    • Allow the desired sources to reach the tagged resources using Tailscale SSH
    {
      "acls": [
        {
          "action": "accept",
          "src": ["group:sre"],
          "dst": ["tag:server:*"]
        }
      ],
      "ssh": [
        {
          "action": "accept",
          "src": ["group:sre"],
          "dst": ["tag:server"],
          "users": ["ubuntu", "root"]
        }
      ]
    }
    
  3. Generate an authentication key to automatically connect servers to your network. Select the tag or tags you wish to use for your servers as part of this auth key.

    • If you’re authenticating more than one server, use a reusable auth key.
    • If you’re authenticating ephemeral workloads like containers or functions, use an ephemeral key.
    • If your tailnet has device authorization enabled, and you only intend to use that to approve end-user devices, use a pre-authorized auth key.
    A screenshot of the generate auth key UI
  4. When you provision a new server, install and connect to Tailscale manually as part of your automation tooling. Make sure to specify the authkey including the tags you want, and to enable Tailscale SSH.

    tailscale up --authkey=$key --ssh
    
  5. That’s it! You can now SSH to your servers over Tailscale, using Tailscale SSH.

Last updated

WireGuard is a registered
trademark of Jason A. Donenfeld.

© 2022 Tailscale Inc.

Privacy & Terms