Docs / Admin

ABAC, RBAC, access controls (ACLs), and restricted security policies

Access control lists (ACLs) restrict who can access which nodes on your network. ACLs can be defined in the admin panel or the Tailscale API.


Let’s say you have 11 employees in your organization. Five of them are in the accounting department, five are in the engineering department, and then there’s the president.

How can you make it so that engineers can access the engineering servers, accountants can access the accounting servers, and the president can access all of them?

On old-fashioned physical networks, you could try using physical segregation: put the engineering workstations and servers into one subnet, the accounting servers into another subnet, and then use a firewall to stop traffic flowing from one subnet to the other. This complicates things for the president, who wants access to both networks, but that’s okay: perhaps the president can have two computers, one on each network.

That was a relatively common setup before but is harder to do now in the days of Wi-Fi, laptops, multiple offices, and remote workers. A newer method is to move all your servers into the cloud and then use BeyondCorp-style proxies to restrict which users can access which servers. This works, as long as all your servers are web based, and as long as you want to put them all in the cloud, and as long as you don’t mind running a network of proxy servers that creates a network bottleneck between clients and servers.

Tailscale’s security architecture is different. Instead of proxy servers, physical networks, and firewalls, each node can talk directly to each other node, no matter where they are. But to prevent that from becoming a security problem, Tailscale also lets you define security policies — basically, a list of which nodes can access which other nodes. Architecturally, you can think of this as a firewall (packet filter) running on every Tailscale node.

With a traditional firewall, security policies are expressed as a set of packet filtering rules allowing one IP address to talk to another IP address. There’s a rule for Engineer A’s laptop ( to let it talk to Git Server G (, and so on for Engineers B..K. When someone brings up CI Server C (, you file a ticket with the security department to open a firewall rule that lets 10.1.1.x/24 access, and so on.

Tailscale ACLs are similar, but refer to users (and groups) and services, instead of just IP addresses. You can write rules like “everyone in the engineering group should be allowed to access servers tagged as ‘engineering’.” The rules are stored in the central coordination server, and compiled into a set of traditional packet filter rules (“these IP addresses can talk to these other IP addresses”) behind the scenes, then sent to each node for enforcement (also known as access control).

Role-based Access Control (RBAC) and Attribute-based Access Control (ABAC) are variations of the same concept. In RBAC, each user acts in exactly one role at a time (engineering, accounting, IT administrator, etc). In ABAC, each user or server is tagged with a flexible set of attributes that describe their job (employee + engineer + Montreal), and those attributes each grant access to relevant services (employees can access the payroll viewer, engineers can access the Git server, and Montreal users can access the printers in Montreal).

Tailscale allows you to build complex RBAC/ABAC rule sets in a simple way, based on identities pulled in from your identity provider. When you make a change to a user’s group memberships (i.e. roles and attributes) or your ACL policies, the changes are immediately reflected out to all Tailscale nodes to update their enforcement rules. All this typically happens in a few hundred milliseconds.

Tailscale ACL file syntax

Tailscale ACL policies are written in “human usable json,” 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. Organizations with complex policies can write automated scripts to generate Tailscale ACL configurations on their behalf. This makes it easy to integrate Tailscale ACLs with any existing authorization system you already use.

If you’re a Tailscale domain admin, you can view and edit your domain’s ACL policy from the ACL page.

The ACL file has several main sections:


// Declare static groups of users beyond those in the identity service.
"Groups": {
	"group:example": [
		"[email protected]",
		"[email protected]",

The Groups section lets you define groups of users (in RBAC, these are called “roles”). A user can be in more than one group. Every group name must start with the prefix group:.

For explicitness, you must include the full email address of each user (or [email protected] for GitHub user @alice). However, Tailscale currently only lets you share your nodes with users inside the same domain as you. If you write an ACL that permits users outside your domain, it will be silently ignored. Eventually, we will allow inviting users outside your domain.


// Declare hostname aliases to use in place of IP addresses or subnets.
"Hosts": {
	"example-host-1": "",
	"example-host-2": "",

Hosts are convenient names that you can use to refer to particular servers when writing ACL rules, so that the ACLs themselves are more human-readable and thus auditable by non-technical users who need to check regulatory compliance.

Hosts can refer to:

Type Example
Single IP address
Subnet CIDR Range (ref)

The "Hosts" section does not allow lists of hosts, like the Groups section. This is not necessary, because ACL rules (the next section) allow you to create lists of hosts at the rule level instead. Disallowing host lists in this section makes it easier to audit ACL rules.


// Access control lists.
"ACLs": [
	// Engineering users, plus the president, can access port 22 (ssh)
	// and port 3389 (remote desktop protocol) on all servers, and all
	// ports on git-server or ci-server.
		"Action": "accept",
		"Users": ["group:engineering", "[email protected]"],
		"Ports": ["*:22,3389", "git-server:*", "ci-server:*"],

	// Allow engineer users to access any port on a device tagged with
	// tag:production.
		"Action": "accept",
		"Users": ["group:engineers"],
		"Ports": ["tag:production:*"],

	// Allow servers in the my-subnet host and to access hosts
	// on both networks.
		"Action": "accept",
		"Users": ["my-subnet", ""],
		"Ports": ["my-subnet:*", "*"],

	// Allow every user of your network to access anything on the network.
	// Comment out this section if you want to define specific ACL
	// restrictions above.
		"Action": "accept",
		"Users": ["*"],
		"Ports": ["*:*"],

Each entry in the "ACLs" section defines a rule that grants access by a set of users or groups (i.e. roles in RBAC), to a set of servers and ports.

There is no way to explicitly reject connections. Instead, no connections are allowed unless granted by an "accept" rule. This makes compliance audits much simpler: there is no way to hide a rule inside complex logic.

“Action” must always be present, but only the value "accept" is allowed.

“Users” describes the source of traffic. It can include any of the host values in the table below.

Type Example
User [email protected]
All Users *
Groups (ref) group:example
Hosts (ref) my-host
Tags (ref) tag:production
Tailscale IP
Subnet CIDR Range (ref)

“Ports” describes the destination of traffic in a host:port format. It can include any host value in the table above, along with a port like below:

Type Format Example with host
Single port 443 [email protected]:443
Range of ports 8000-9000 my-host:8000-9000
List of ports and ranges 80,443,8000-9000 *:80,443,8000-9000
All ports **


// Define who is allowed to use which tags.
"TagOwners": {
	// Everyone in the montreal-admins or global-admins group are
	// allowed to tag servers as montreal-webserver.
	"tag:montreal-webserver": [
	// Only a few admins are allowed to create API servers.
	"tag:api-server": [
		"[email protected]",

TagOwners define tags, and a list of users allowed to configure devices with that tag. All tag names must start with tag:. Users can be groups or specific email addresses.

You can refer to tags you define from ACL rules:

"ACLs": [
	// ... other ACL rules ...
	// All users in Montreal are allowed to access the Montreal web
	// servers.
		"Action": "accept",
		"Users": ["group:montreal-users"],
		"Ports": ["tag:montreal-webserver:80,443"],

	// Montreal web servers are allowed to make outgoing connections to
	// the API servers, but only on https port 443.
	// In contrast, this doesn't grant API servers the right to initiate
	// any connections.
		"Action": "accept",
		"Users": ["tag:montreal-webserver"],
		"Ports": ["tag:api-server:443"],

Once you’ve created some tags, be sure to tag your devices to ensure the ACLs are applied.


// Declare tests to check functionality of ACL rules
"Tests": [
		"User": "[email protected]",
		"Allow": ["example-host-1:22", "example-host-2:80"],
		"Deny": ["exapmle-host-2:100"],
		"User": "[email protected]",
		"Allow": [""],

ACLs can get large and it may be hard to keep track of what groups, roles, tags, etc, give permissions to what machines. The "Tests" section of your ACL lets you declare tests to ensure updates to your ACL don’t accidentally revoke access to key systems, or expose resources to users you didn’t intend. If a test fails due to an ACL change, you’ll receive an error and any changes to the ACL won’t be committed.

A test requires a target User (email or [email protected]), and either a list of Allow’d destinations, Deny’d destinations, or both. Acceptable items in Allow/Deny lists are specific ports to either a user or IP address as shown above.

Editing ACLs

You can edit your ACLs in two ways.

  1. We provide a simple text editor in the admin panel where you can make changes. Some teams may choose to maintain ACL files elsewhere (e.g. to take advantage of version control systems) and paste changes in to save.
  2. You can also use the Tailscale API to automate edits to your ACL file. This is a great way to integrate with external systems.

Preview Rules

Whether through the admin panel or the API, you can generate a preview of which rules will affect a user.

To do so in the admin panel, 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.

ACL tags

ACL tags are a beta feature. During the beta it is possible to re-tag a node without reauthenticating. This means someone with root access on the machine can change or delete tags (to tags permitted by TagOwners) at any time. This could be used to get access that would normally not be available to the node. When this feature is officially supported, it will require an interactive login before changing tags.

Every node on Tailscale needs to be authenticated as some user, which defines the permissions of that node. This works well for end user devices, but creates problems for servers.

Tags allow defining custom permissions for servers and infrastructure devices without inheriting permissions from the user (often an IT or DevOps admin) who authenticated the device.

To begin using ACL tags, first define "TagOwners" and "ACLs" rules to define the shape of your network. Next, you can start to re-tag your nodes using the --advertise-tags option to tailscale up. Right now, only Linux-based servers can have tags. A node can request multiple tags, if you separate them with commas.

sudo tailscale up --advertise-tags=tag:montreal-webserver,tag:api-server

To undo the tagging operation, use the --advertise-tags= flag without any value:

sudo tailscale up --advertise-tags=

Last updated