Docs / Admin

Network access controls (ACLs)

Tailscale supports network access control rules, sometimes called ACLs. ACLs let you precisely define what a particular user or device is permitted to access on your Tailscale network.


Introduction

When you first create your network, it gets initialized with an “allow all” access policy, which permits all devices that are signed into your network to access all other devices. When you’re ready to restrict access further, you can do so by editing the access rules in the admin console, or through the Tailscale API.

Tailscale access rules are “default deny”, meaning that a communication between two devices can only proceed if an access rule explicitly allows it, otherwise communication is denied. This is why new networks are initialized with an explicit “allow all” policy, otherwise Tailscale would not let you access anything out of the box.

Access rules can make use of groups to grant access to many users with few rules. Similarly, you can use tags to assign purpose-based identities to devices to further scale up your policies. Combined, groups and tags let you build powerful role-based access control (RBAC) policies. Depending on your definition, server tagging could also be considered a form of attribute-based access control (ABAC).

The access rules you define for your network get distributed to all the devices in your network, and enforcement of the rules happens on each device directly, without further involvement from Tailscale’s servers.

If you’d like to learn more about Tailscale’s approach to access control in general, we’ve written a detailed blog post that goes deep into the history of access control systems, and why we designed Tailscale’s access rules the way we did.

Tailscale policy syntax

Tailscale access control rules are expressed as a single “human JSON” policy file. HuJSON a superset of JSON that allows comments and trailing commas. This makes ACL files easy to maintain while staying read/writable by both humans and machines.

For simple cases, you can edit the policy file by hand in the admin panel. Organizations with more complex needs can use the API to automatically update rules from software.

The policy file has several top-level sections relating to ACLs, which we explore in detail below:

  • acls, the access rules themselves.
  • groups, collections of users, to avoid repeating yourself in access rules.
  • hosts, human readable shorthands for IP addresses.
  • tests, which let you check the behavior of ACLs and avoid accidentally breaking an important permission.
  • tagOwners, to define which users can assign tags to a device.

The policy file also contains network-wide policy settings unrelated to access control: derpMap, disableIPv4, and randomizeClientPort are documented in a separate section at the end of this article, for completeness.

An example policy file:

{
  "acls": [
    // [email protected] can access everything on host vega (defined below)
    {
      "action": "accept",
      "users": ["[email protected]"],
      "ports": ["vega:*"],
    },
    // The security group can access all HTTPS servers, and everything on
    // the corp network.
    {
      "action": "accept",
      "users": ["group:security"],
      "ports": [
        "*:443",
        "corp-network:*"
      ],
    },
    // Both [email protected] and the security group can access lab devices.
    {
      "action": "accept",
      "users": ["[email protected]", "group:security"],
      "ports": ["tag:lab:*"],
    },
    // All lab devices can talk to each other, but nothing else.
    {
      "action": "accept",
      "users": ["tag:lab"],
      "ports": ["tag:lab:*"],
    },
  ],
  // Readable shorthands for devices and networks.
  "hosts": {
    "vega": "100.3.4.5",
    "corp-network": "10.0.0.0/8",
    "critical-corp-server": "10.0.0.1",
  },
  // Role-based groups of users.
  "groups": {
    "group:security": [
      "[email protected]",
      "[email protected]",
    ],
  },
  "tests": [
    // Security can always access HTTPS on vega, but not HTTP.
    {
      "user": "group:security",
      "allow": ["vega:443"],
      "deny": ["vega:80"],
    },
    // [email protected] can SSH into vega and the lab.
    {
      "user": "[email protected]",
      "allow": ["vega:22", "tag:lab:22"],
    },
    // Lab devices can never access a critical corp service.
    {
      "user": "[email protected]",
      "deny": ["critical-corp-server:80"],
    },
  ],
  "tagOwners": {
    "tag:lab": ["[email protected]"],
    "tag:security": ["group:security"],
  },
  "derpMap": {
    "regions": {
      900: {
        "regionID": 900,
        "hostName": "custom-derp.example.com",
      },
    },
  },
  "disableIPv4": false,
  "randomizeClientPort": false,
}

Previewing changes

When editing the ACL policy file in the admin console, you can preview the permisions granted to your users.

To do so, navigate to the “Preview Rules” tab and select a user from the dropdown. A list of ports (one per line) accessible to the specified user is shown, as well the line number that defines that rule. It also includes any other users/groups that can access that port due to that rule.

Another way to increase confidence in your changes is to define some ACL tests, to check that your changes don’t accidentally remove access to an important system, or accidentally open up access wider than you intended.

ACL rules

The acls section of the policy file is a list of access rules for your network. Each rule is a HuJSON object that grants access from a set of sources to a set of destinations.

All rules eventually boil down to allowing traffic from a particular source IP address to a destination IP address and port. While you can write rules that reference IP addresses directly, it’s more common to use higher-level specifiers like usernames and groups, which Tailscale automatically translates to the right low-level rules.

Each access rule looks like this:

{
  "action": "accept",
  "users": [ list-of-sources... ],
  "ports": [ list-of-destinations... ],
}
For backwards compatibility reasons, sources are specified in a field called users and destinations in a field called ports. Both these fields are more expressive than their names would suggest.

Tailscale access rules are “default deny”, so the only possible action is accept, to allow traffic that would otherwise be denied.

The users field specifies a list of sources to which the rule applies. Each element in the list can be one of the following:

Type Example Meaning
Any * No restriction on the source
User [email protected] All devices currently signed in as the given user
Group (ref) group:example Same as listing every user in the group explicitly
Tailscale IP 100.101.102.103 Only the device that owns the given Tailscale IP
Subnet CIDR Range (ref) 192.168.1.0/24 Any IP within the given subnet
Hosts (ref) my-host Looks up the Tailscale IP or CIDR in the `hosts` section
Tags (ref) tag:production All devices currently tagged with the given tag
Shared users (ref) autogroup:shared Devices of users who accepted a sharing invitation for the destination

The ports field specifies a list of destination devices and ports to which the rule applies. Each element in the list is of the form host:ports. host is one of the following:

Type Example Meaning
Any * No restriction on the destination
User [email protected] Any device currently signed in as the given user
Group (ref) group:example Same as listing every user in the group explicitly
Tailscale IP 100.101.102.103 Only the device that owns the given Tailscale IP
Hosts (ref) my-host Looks up the Tailscale IP in the `hosts` section
Subnet CIDR Range (ref) 192.168.1.0/24 Any IP within the given subnet
Tags (ref) tag:production Any device currently tagged with the given tag
Internet access (ref) autogroup:internet Access to the internet through exit nodes

ports is one of the following:

Type Example
Any *
Single 22
Multiple 80,443
Range 1000-2000

Users

Users can be specified in both the source (users) and destination (ports) fields of an access rule. Users must be referenced using the full email address they use to sign into Tailscale.

If you sign into your network with GitHub, use the form [email protected]. For example, the GitHub user alice should be written as [email protected].

Referencing an external user in an access rule does not implicitly grant them access to your Tailscale network. However, if you’ve shared a device with someone outside your Tailscale network, you can use their Tailscale login email in ACLs to further restrict what they can access on the shared device.

Groups

The groups section lets you define a shorthand for a group of users, which you can then use in ACL rules instead of listing users out explicitly. Any change you make to the membership of a group is automatically propagated to all the rules that reference that group.

A groups definition looks like this:

"groups": {
  "group:engineering": [
    "[email protected]",
    "[email protected]",
  ],
  "group:sales": [
    "[email protected]",
    "[email protected]",
  ],
},

Every group name must start with the prefix group:. Each member of a group is specified by their full email address, as explained in the users section above. To avoid the risk of obfuscating group membership, groups cannot contain other groups.

Hosts

The hosts section lets you define a human-friendly name for an IP address or IP range, to make access rules more readable.

A hosts definition looks like this:

"hosts": {
  "example-host-1": "100.100.100.100",
  "example-network-1": "100.100.101.100/24",
},

Tests

The tests section lets you write assertions about your access rules, which are checked whenever the policy file is changed. Failing assertions cause the new policy file to be rejected, with an error detailing which test assertion wasn’t met.

Just like writing tests for software, ACL tests let you ensure that an important permission isn’t accidentally revoked later on, or that a critical system in your network isn’t exposed more than expected.

A tests definition looks like this:

"tests": [
  {
    "user": "[email protected]",
    "allow": ["example-host-1:22", "vega:80"],
    "deny": ["1.2.3.4:443"],
  },
],

The user field specifies the user identity being tested, which can be an email address or a device tag. The test case will be run from the perspective of device signed in as that user or tag.

The allow and deny fields specify destinations that the ACL rules should allow or deny, respectively. Each destination in the list is of the form host:port, where port is a single numeric port and host is one of the following:

Type Example Meaning
Tailscale IP 100.101.102.103
Hosts (ref) my-host Looks up the Tailscale IP in the `hosts` section
User [email protected] The Tailscale IP of a device currently signed in as the given user
Tags (ref) tag:production The Tailscale IP of a device currently tagged with the given tag

Tag Owners

The tagOwners section of the policy file defines the tags that can be applied to devices, and the list of users who are allowed to assign each tag.

Tags are a substitute for a human identity on a device. That is, rather than a device being authenticated as a particular user, the device’s identity on the Tailscale network is the set of tags assigned to it. You can learn more in our article on server role accounts with ACL tags.

A tagOwners definition looks like this:

"tagOwners": {
  "tag:webserver": [
    "group:engineering",
  ],
  "tag:secure-server": [
    "group:security-admins",
    "[email protected]",
  ],
}

Every tag name must start with the prefix tag:. Each owner of a tag can be a user’s full login email address (as defined in the users section above), or a group name.

Network policy options

In addition to access rules, the policy file includes a few network-wide policy settings for specialized purposes. Most networks should never need to specify these.

The derpMap section lets you add custom DERP servers to your network, which your devices will use as needed to relay traffic. You can also use this section to disable the use of Tailscale-provided DERP servers, for example to meet corporate compliance requirements. The derpMap section is detailed in the article on running custom DERP servers.

The disableIPv4 field, if set to true, stops assigning Tailscale IPv4 addresses to your devices. All devices in your network will receive exclusively IPv6 Tailscale addresses, and devices that do not support IPv6 (e.g. systems that have IPv6 disabled in the operating system) will be unreachable. This option is intended for users who have a pre-existing conflicting use of the 100.64.0.0/10 carrier-grade NAT address range.

The randomizeClientPort field, if set to true, makes devices prefer a random port for WireGuard traffic over the default static port 41641. This option is intended as a workaround for some buggy firewall devices, and should only be enabled after consulting with Tailscale (contact us at [email protected]).

Last updated