Get started
Login
© 2024

ACL syntax

You can write Tailscale access control rules such as ACLs and grants in the tailnet policy file, which is expressed in human JSON (HuJSON).

The tailnet policy file has the following top-level sections relating to ACLs:

The tailnet policy file also contains grants and the following network-wide policy settings (unrelated to access control): derpMap, disableIPv4, and randomizeClientPort.

Access rules

The acls section lists access rules for your tailnet. Each rule grants access from a set of sources to a set of destinations.

Access rules can use groups and tags to grant access to pre-defined sets of users and assign service role accounts to nodes. Together, groups and tags let you build powerful role-based access control (RBAC) policies.

Tailscale automatically translates all ACLs to lower-level rules that allow traffic from a source IP address to a destination IP address and port.

The following example shows an access rule with an action, src, proto, and dst.

{
  "action": "accept",
  "src": [ <list-of-sources> ],
  "proto": "tcp", // optional
  "dst": [ <list-of-destinations> ],
}

The acl section of the tailnet policy supports the legacy fields users and ports, but the best practice is to use src (instead of users) and dst (instead of ports).

action

Tailscale access rules deny access by default. As a result, the only possible action is accept. accept allows traffic from the source (src) to the destination (dst).

src

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

TypeExampleDescription
Any*All traffic originating from Tailscale devices in your tailnet, any approved subnets and autogroup:shared. It does not allow traffic originating from non-tailscale devices (unless it is an approved route).
Usershreya@example.comIncludes all the provided user's devices.
Groupgroup:<group-name>Includes all users in the provided group.
Tailscale IP100.101.102.103Includes only the device that owns the provided Tailscale IP. IPv6 addresses must follow the format [1:2:3::4]:80.
Subnet CIDR Range192.168.1.0/24Includes any IP address within the provided subnet.
Hostmy-hostIncludes the Tailscale IP address or CIDR in the hosts section.
Tagtag:productionIncludes all devices with the provided tag.
Autogroupautogroup:<role|property>Includes devices of users, destinations, or usernames with the same properties or roles.
Autogroup (all)autogroup:danger-allA special autogroup that selects all sources including those outside your tailnet.

You can optionally include the srcPosture field to further restrict src devices to the ones matching a set of device posture conditions.

proto

The proto field is an optional field you can use to specify the protocol to which the rule applies. Without a protocol, the access rule applies to all TCP and UDP traffic.

You can specify proto as an IANA IP protocol number 1-255 (for example, "16") or one of the supported named aliases.


Expand to view all named aliases.
ProtocolprotoIANA protocol number
Internet Group Management (IGMP)igmp2
IPv4 encapsulationipv4, ip-in-ip4
Transmission Control (TCP)tcp6
Exterior Gateway Protocol (EGP)egp8
Any private interior gatewayigp9
User Datagram (UDP)udp17
Generic Routing Encapsulation (GRE)gre47
Encap Security Payload (ESP)esp50
Authentication Header (AH)ah51
Stream Control Transmission Protocol (SCTP)sctp132

Notes about the proto field:

  • You must use Tailscale version v1.18.2 or later to use the proto field. Earlier versions of Tailscale will fail and block access rules with protocols.
  • If traffic is allowed for a given pair of IP addresses, then ICMP will also be allowed.
  • Only TCP, UDP, and SCTP traffic support specifying ports. All other protocols only support * as the protocol.

dst

The dst field specifies a list of destinations to which the rule applies. Each element in the list specifies a host and one or more ports in the format <host>:<ports>.

The host can be any of the following types:

TypeExampleDescription
Any*Includes any destination (no restrictions).
Usershreya@example.comIncludes any device currently signed in as the provided user.
Groupgroup:<group-name>Includes all users in the provided group.
Tailscale IP address100.101.102.103Includes only the device that owns the provided Tailscale IP address.
Hostsexample-host-nameIncludes the Tailscale IP address in the hosts section.
Subnet CIDR Range192.168.1.0/24Includes any IP address within the given subnet.
Tagstag:<tag-name>Includes any device with the provided tag.
Internet access through an exit nodeautogroup:internetIncludes devices with access to the internet through exit nodes.
Own devicesautogroup:selfIncludes devices where the same user is authenticated on both the src and the dst. This does not include devices for which the user has tags.
Tailnet devicesautogroup:memberIncludes devices on the tailnet where the user is a direct member (not a shared user) of the tailnet.
Admin devicesautogroup:adminIncludes devices where the user is an Admin.
Network admin devicesautogroup:network-adminIncludes devices where the user is a Network admin.
IT admin devicesautogroup:it-adminIncludes to devices where the user is an IT admin.
Billing admin devicesautogroup:billing-adminIncludes devices where the user is a Billing admin.
Auditor devicesautogroup:auditorIncludes devices where the user is an Auditor.
Owner devicesautogroup:ownerIncludes devices where the user is the tailnet Owner.

The ports field can be any of the following types:

TypeDescriptionExample
AnyIncludes any port number.*
SingleIncludes a single port number.22
MultipleIncludes two or more port numbers separated by commas.80,443
RangeIncludes a range of port numbers.1000-2000

Subnet routers and exit nodes

ACLs don't limit the discovery of routes. If a device is a subnet router, you can restrict access to it independently from the subnet. If a device is an exit node, you can restrict access to it independently from its public IP address.

To restrict access to a subnet, ensure that no ACL allows access to those routes. You can enforce this with a test that fails if any rule accidentally allows access. The following example demonstrates a test that fails if not-allowed@example.com is allowed access to 198.51.100.7:22.

"tests": [
   {
     "src": "not-allowed@example.com",
     "accept": ["192.0.2.100:22"], // allow access to the tailscale IP
     "deny": ["198.51.100.7:22"], // does not allow access to the subnet
   }
],

Only devices with access to autogroup:internet can use exit nodes. All other devices (without access to autogroup:internet) cannot use exit nodes. You can enforce this with a test that fails if any rule accidentally allows access to a public address. The following example test fails if not-allowed@example.com can access 198.51.100.8:22.

"tests": [
   {
     "src": "not-allowed@example.com",
     "accept": ["192.0.2.100:22"], // allow access to the tailscale IP
     "deny": ["198.51.100.8:22"], // does not allow access to a public IP
   }
],

You cannot restrict the use of specific exit nodes using ACLs. Refer to issue #1567 for updates.

Taildrop precedence

Taildrop permits you to share files between devices you're logged in to, even if you use ACLs to restrict access.

Grants

Grants are currently in beta.

Grants are a new, more powerful approach to access control. They let you do everything you can with ACLs, plus more. When communicating with a destination device, you can grant application layer capabilities to a set of devices or users. You can also continue to define traditional network layer capabilities. For example, you can use a grant rule to give a group of users access to port 8443 on a server, and define the files they can edit on that server.

The grants system combines network layer and application layer capabilities into a shared syntax. As a result, it offers enhanced flexibility and fine-grained control over resource access. Each grant only requires a source and a destination. Because Tailscale takes a deny-by-default approach, each grant has an implied accept action.


Learn how to grant capabilities at the network and application layers.

Reference users

You can specify users in an access rule's source (src) and destination (dst) fields. To specify a user, use one of the following formats (depending on how the user signs into Tailscale):

FormatDescriptionExample
username@example.comUse if the user signs into Tailscale with an email address.alice@example.com
username@githubUse if the user signs into Tailscale with a GitHub account.alice@github
username@passkeyUse if the user signs into Tailscale with a Passkey.alice@passkey

You can use groups to reference sets of users. Groups let you define role-based access controls. There are multiple types of groups:

  • Auto groups that reference all users with the same property.
  • Groups defined in the groups section of the tailnet policy file as a specific list of users.
  • Groups provisioned in the identity provider and synced through user and group provisioning.

Autogroups

Autogroups are available for all plans.

An autogroup is a special group that automatically includes users, destinations, or usernames with the same properties.

AllowedAutogroupDescriptionAvailability by plan
As a dstautogroup:internetUse to allow access for any user through any exit node in your tailnet.Available on all plans
autogroup:selfUse to allow access for any user that is authenticated as the same user as the source. Does not apply to tags.
As a src or dst, tagOwner, or autoApproverautogroup:ownerUse to allow access for the tailnet Owner.Available on all plans
autogroup:adminUse to allow access for any user who has the role of Admin.
autogroup:memberUse to allow access for any user who is a direct member (including all invited users) of the tailnet. Does not include users from shared devices.
autogroup:taggedUse to allow access for any device that is tagged.
autogroup:auditorUse to allow access for any user who has the role of Auditor.Available on the Personal, Personal Plus, Premium, and Enterprise plans
autogroup:billing-adminUse to allow access for any user who has the role of Billing admin.
autogroup:it-adminUse to allow access for any user who has the role of IT admin.
autogroup:network-adminUse to allow access for any user who has the role of Network admin.
user:*@<domain>Use to allow access for any user whose login is in the specified domain and who is a direct member (including all invited users) of the tailnet. Does not include users from shared devices.Available on the Starter, Premium, and Enterprise plans
As a srcautogroup:sharedUse to allow access for any user who accepted a sharing invitation to your network. This lets you write rules without knowing the email addresses in advance.Available on all plans
As an SSH userautogroup:nonrootUse to allow Tailscale SSH access to any user that is not root.Available on the Personal, Personal Plus, Premium, and Enterprise plans
localpart:*@<domain>Use to allow Tailscale SSH access to the user whose name matches the local-part of the user's login.Available on the Premium and Enterprise plans

autogroup:self only applies to user-owned devices. It does not apply to tagged devices. You cannot use autogroup:self with autogroup:tagged.

The legacy autogroup autogroup:members will continue to work, but it's best practice to use autogroup:member instead. You cannot use both autogroup:member and autogroup:members in the same tailnet policy file.

The following example ssh rule allows all users Tailscale SSH access to devices they own (as non-root):

"ssh": [
  {
    // All users can SSH to their own devices, as non-root
    "action": "accept",
    "src": ["autogroup:member"],
    "dst": ["autogroup:self"],
    "users": ["autogroup:nonroot"]
  },
]

In the default ACL, the ssh rule uses autogroup:self for the dst field andautogroup:nonroot in the users field. If you change the dst field fromautogroup:self to some other destination, such as an ACL tag, also consider replacing autogroup:nonroot in the users field. If you don't removeautogroup:nonroot from the users field, then anyone permitted by the src setting will be able to SSH in as any nonroot user on the dst device.

Domain based autogroups

Some autogroups include a specific domain name. For example, user:*@example.com or localpart:*@example.com. These autogroups include users who are both members of the tailnet and whose login is in the autogroup domain. For example, if the tailnet example.com uses the autogroup user:*@altostrat.com, this group includes all members of the example.com tailnet who log in as a user at @altostrat.com (such as laura@altostrat.com).

The following restrictions apply to the domains used in autogroups:

  • The provided domain must not be a known shared domain (such as gmail.com).
  • If a tailnet uses domain aliases, you must explicitly specify the aliased domains in the ACL. For example, if example.io is aliased to example.com and you want to include users from both example.com and example.io, use both user:*@example.com and user:*@example.io.
  • Although the expressions use the wildcard *, it does not support arbitrary wildcards. For example, user:b*b@example.com will not match bob@example.com.

Groups

The groups section lets you create groups of users, which you can use in access rules (instead of listing users out explicitly). Any change you make to the membership of a group propagates to all the rules that reference that group.

The following example demonstrates creating an engineering group and a sales group.

"groups": {
  "group:engineering": [
    "dave@example.com",
    "laura@example.com",
  ],
  "group:sales": [
    "brad@example.com",
    "alice@example.com",
  ],
},

Every group name must start with the prefix group:. Each group member 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.

You can add or remove a user's group membership by editing the tailnet policy file, as shown in the example groups definition above, and directly from the Users page of the admin console.

Edit a user's group membership from the Users page

You must be an Owner, Admin, or Network admin to edit a user's group membership from the Users page.

  1. Open the Users page in the admin console.
  2. Find the user by name.
  3. Select the ellipsis icon menu > Edit group membership.
  4. In the Edit group membership dialog:
    1. To add a group, select Add to a group, then the group to add.
    2. To remove a group, select the X next to the group to delete.
  5. When you finish editing the groups for the user, select Save.

Provisioned groups

You can create groups in your identity provider and sync them with Tailscale's ACLs with user and group provisioning.

You can use the same human-readable group names in your identity provider to refer to groups in your tailnet policy file. The following example shows an access rule that manages access for the “security-team” group.

{
	"acls": [
		{
			"action": "accept",
			"src": ["group:security-team@example.com"],
			"dst": ["tag:logging:*"]
		}
	],
	"tagOwners": {
		"tag:logging": ["group:security-team@example.com"]
	}
}

You can only edit groups defined in ACLs. You can use groups synced from a System for Cross-domain Identity Management (SCIM) integration or tailnet autogroups, but you cannot edit them.

Reference multiple devices

You can define access rules for sets of devices using tags or hosts. Tags let you define role-based access controls so that different services have different access rules. Hosts let you define controls based on a reference to an IP address.

  • Tags reference groups of non-user devices (such as applications or servers). For example, you might have a tag that groups all servers in a particular data center.
  • Hosts reference groups of devices by IP address ranges (both on and beyond the tailnet). For example, you can use hosts to address applications with fixed IP addresses that you might be unable to modify.

Tags

Tags are available for all plans.

The tags section of the tailnet policy file lets you create tags that group non-human devices. You can then use the tags to select these devices in an ACL.

You must define the tag in the tagOwners section of the tailnet policy file before using it in an ACL. To tag a device, authenticate as the tag on the device.

Hosts

Hosts are available for all plans.

The hosts section lets you define a human-friendly name for an IP address or CIDR range.

The following example shows two host definitions: one for a single IP address and one for a CIDR range.

"hosts": {
  "example-host-1": "198.51.100.100",
  "example-network-1": "198.51.100.0/24",
},

The human-friendly hostname cannot include the character @.

Postures

Postures are available for all plans.

The postures section lets you define a set of device posture management rules that a device must meet as part of a specific access rule.

The following example shows how to use postures to select macOS devices running node version 1.40 or later.

"postures": {
    "posture:latestMac": [
        "node:os IN ['macos']",
        "node:tsReleaseTrack == 'stable'",
        "node:tsVersion >= '1.40'",
    ],
},

Each posture must start with the prefix posture: followed by a name, a set of posture attributes, and their allowed values, given as a list of strings.

Refer to device posture management for more information

Tag owners

Tags are available for all plans.

The tagOwners section of the tailnet policy file defines the tags assignable to devices and the list of users allowed to assign each tag.

The following example shows a tagOwners definition that:

  • Sets the webserver tag as the owner of the engineering group.
  • Sets the secure-server tag as the owner of president@example.com and the security-admins group.
  • Sets the corp tag as the owner of the autogroup:member autogroup.
"tagOwners": {
  "tag:webserver": [
    "group:engineering",
  ],
  "tag:secure-server": [
    "group:security-admins",
    "president@example.com",
  ],
  "tag:corp": [
    "autogroup:member",
  ],
}

Every tag name must start with the prefix tag:. A tag owner can be a user's full login email address (as defined in the users section above), a group name, an autogroup, or another tag.

A shorthand notation, [], is available for autogroup:admin. That is, the following are equivalent:

"tag:monitoring": [
  "autogroup:admin",
],
"tag:monitoring": [],

The autogroups autogroup:admin and autogroup:network-admin can assign all tags, so [] implicitly allows only autogroup:admin and autogroup:network-admin.

Auto approvers

Auto approvers are available for all plans.
Auto approvers are currently in beta.

The autoApprovers section of the tailnet policy file defines the list of users who can perform specific actions without further approval from the admin console. Some actions in Tailscale require double opt-in: an Admin must enable them on the device running Tailscale and in the Tailscale admin console. These actions include:

For routes, this also permits the auto approvers to advertise a subnet of the specified routes.

Tailscale stops advertising a route if one of the following occurs:

  • The device is re-authenticated by a different user (who cannot advertise the route or exit node).
  • The user who advertised the route is suspended or deleted.

To avoid a scenario where Tailscale stops advertising a route, consider using a tag as an auto approver.

The following example shows an autoApprovers definition that automatically approves the 192.0.2.0/24 routes for alice@example.com, members of the engineering group, and devices tagged with foo. It also automatically allows devices tagged with foo to use an exit node.

"autoApprovers": {
  "routes": {
    "192.0.2.0/24": ["group:engineering", "alice@example.com", "tag:foo"],
  },
  "exitNode": ["tag:bar"],
}

The auto approver of a route or exit node can be a user's full login email address (as defined in the users section above), a group name, an autogroup or a tag.

Tailscale SSH

The ssh section of the tailnet policy file defines lists of users and devices that can use Tailscale SSH (and the SSH users). To allow a connection, the tailnet policy file must contain rules permitting both network access and SSH access:

  1. An access rule to allow connections from the source to the destination on port 22.
  2. An SSH access rule to allow connections from the source to the destination and the given SSH users. Tailscale SSH uses this to distribute keys to authenticating SSH connections.

The following example shows an ssh definition that requires a list of sources, destinations, and SSH users to re-authenticate every 20 hours.

{
  "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
  "acceptEnv": [ "GIT_EDITOR", "GIT_COMMITTER_*", "CUSTOM_VAR_V?" ] // optional, allowlists environment variables that can be forwarded from clients to the host
},

action

Specifies whether to accept the connection or to perform additional checks on it.

  • accept accepts connections from users already authenticated on the tailnet.
  • check requires users to periodically reauthenticate according to the checkPeriod.

src

Specifies the source (where a connection originates from). You can only define an access rule's destination (dst) as yourself, a group, a tag, or an autogroup. You cannot use *, other users, IP addresses, or hostnames.

It's impossible to guarantee the ownership of an IP address or hostname when you create an access rule. As a security measure, Tailscale prevents using users, IP addresses, or hostnames in the dst field of access rules to protect against scenarios in which one user can unintentionally access a device that doesn't belong to them. Tailscale also prevents any src and dst combinations that allow multiple users to access a single user's device.

Granting access to autogroup:members also allows access to external invited users if the destination device is shared with them, even if they have no devices in your tailnet.

dst

Specifies the destination (where the connection goes). The destination can be a user, tag, or autogroup. Unlike ACLs, you cannot specify a port because only port 22 is allowed. You cannot * as the destination.

users

Specifies the set of allowed usernames on the host. Tailscale only uses user accounts that already exist on the host.

  • Specify autogroup:nonroot to allow any user that is not root.
  • Specify localpart:*@<domain> to allow the user on the host whose name matches the local-part of the user's login, if and only if the user's login email is in <domain>. Tailscale does not do any special processing on the local-part. For example, if the login is dave+sshuser@example.com, Tailscale will map this to the ssh user dave+sshuser.
  • If no user is specified, Tailscale will use the local host’s user. That is, if the user is logged in as alice locally, then connects with SSH to another device, Tailscale SSH will try to log in as user alice.

checkPeriod

When action is check, checkPeriod specifies the time period for which to allow a connection before requiring a check. You can specify the time in minutes or hours. The time must be at least one minute and at most 168 hours (one week).

  • The default check period is 12 hours.
  • You can also specify always to require a check on every connection. Using always might cause unexpected behavior with automation tools that open many SSH connections in quick succession (such as Ansible).

acceptEnv

The host must be running Tailscale v1.76.0 or later to use acceptEnv.

Specifies the set of allowlisted environment variable names that clients can send to the host using SendEnv or SetEnv.

Values can contain * and ? wildcard characters. * matches zero or more characters and ? matches a single character.

acceptEnv examples

acceptEnvPermittedRejected
*FOO_A FOO_B FOO_OTHER BAZ
FOO_*FOO_A FOO_B FOO_OTHERBAZ
FOO_?FOO_A FOO_BFOO_OTHER BAZ
FOO_AFOO_AFOO_B FOO_OTHER BAZ

Order of evaluation

Tailscale evaluates SSH access rules using 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.

Tailnets that have not modified their ACLs have a default SSH policy allowing users to access devices they own using check mode.

The only types 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). An SSH access rule from a tagged device cannot be in check mode.
  • From a user to a tagged device that has been shared with them, as long as the destination host has Tailscale configured with SSH and the destination’s ACL allows the user to connect over SSH.

That is, the broadest policy allowed would be:

{
	"acls": [
		{
			"action": "accept",
			"src": ["*"],
			"dst": ["*:*"]
		}
	],
	"ssh": [
		{
			"action": "accept",
			"src": ["autogroup:member"],
			"dst": ["autogroup:self"],
			"users": ["root", "autogroup:nonroot"]
		},
		{
			"action": "accept",
			"src": ["autogroup:member"],
			"dst": ["tag:prod"],
			"users": ["root", "autogroup:nonroot"]
		},
		{
			"action": "accept",
			"src": ["tag:logging"],
			"dst": ["tag:prod"],
			"users": ["root", "autogroup:nonroot"]
		}
	]
}

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

{
	"acls": [
		{
			"action": "accept",
			"src": ["*"],
			"dst": ["*:*"]
		}
	],
	"ssh": [
		{
			"action": "accept",
			"src": ["autogroup:member"],
			"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"]
  }
}

To allow Alice to access devices in the development environment tagged tag:dev that have been shared with them:

{
  "ssh": [
    {
      "action": "accept",
      "src": ["alice@example.com"],
      "dst": ["tag:dev"],
      "users": ["root", "alice"]
    },
  ]
}

It might be useful to match host users with login emails. For example, you can allow dave@example.com to authenticate as the host user dave.

To allow any tailnet member in the login domain example.com to access devices in the production environment that are tagged tag:prod, as a user that matches their login email local-part:

{
	"acls": [
		{
			"action": "accept",
			"src": ["user:*@example.com"],
			"dst": ["tag:prod:*"]
		}
	],
	"ssh": [
		{
			"action": "accept",
			"src": ["user:*@example.com"],
			"dst": ["tag:prod"],
			"users": ["localpart:*@example.com"]
		}
	]
}

Node attributes

Node attributes are currently in beta.

The nodeAttrs section of the tailnet policy file defines additional attributes that apply to specific devices in your tailnet. You can use node attributes to set different NextDNS configurations for different devices in your tailnet.

The following example shows a nodeAttrs definition that targets my-kid@my-home.com and tag:server with the attributes nextdns:abc123 and nextdns:no-device-info.

"nodeAttrs": [
    {
        "target": ["my-kid@my-home.com", "tag:server"],
        "attr": [
            "nextdns:abc123",
            "nextdns:no-device-info",
        ],
    },
],

target

Specifies which nodes (devices) the attributes apply to. You can select the devices using a tag (tag:server), user (alice@example.com), group (group:kids), or *.

attr

Specifies which attributes apply to those nodes (devices).

For example:

  • The attribute nextdns:abc123 specifics the NextDNS configuration ID abc123. If this is used, the attribute overrides the global NextDNS configuration.
  • The attribute nextdns:no-device-info disables sending device metadata to NextDNS.

The following example allows members of the tailnet to use Tailscale Funnel on their nodes:

"nodeAttrs": [
    {
         "target": ["autogroup:members"],
         "attr":   ["funnel"],
     },
],

Tests

ACL tests are available for all plans.

The tests section lets you write assertions about your access rules that run as checks each time the tailnet policy file changes. If an assertion fails, the Tailscale rejects the updated tailnet policy file with an error. The error message indicates the failing tests.

ACL tests let you ensure you don't accidentally revoke important permissions or expose a critical system.

A tests definition looks like this:

"tests": [
  {
    "src": "dave@example.com",
    "srcPostureAttrs": {
      "node:os": "windows",
    },
    "proto": "tcp",
    "accept": ["example-host-1:22", "vega:80"],
    "deny": ["192.0.2.3:443"],
  },
],

src

Specifies the user identity to test, which can be a user's email address, a group, a tag, or a host that maps to an IP address. The test case runs from the perspective of a device authenticated with the provided identity.

srcPostureAttrs

Specifies the device posture attributes as key-value pairs to use when evaluating posture conditions in access rules. You only need to use this field if the access rules contain device posture conditions.

proto

Specifies the IP protocol for accept and deny rules, similar to the proto field in ACL rules. When omitted, the test checks for either TCP or UDP access.

accept and deny destinations

Specifies destinations to accept or deny. 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:

TypeExampleDescription
Tailscale IP100.101.102.103Includes the device with the provided Tailscale IP address. IPv6 addresses must follow the format [1:2:3::4]:80.
Hostmy-hostIncludes the Tailscale IP address in the hosts section.
Usershreya@example.comIncludes the Tailscale IP addresses of devices signed in as the provided user.
Groupgroup:security@example.comIncludes the Tailscale IP addresses of devices signed in as a representative member of the provided group.
Tagtag:productionIncludes the Tailscale IP addresses of devices tagged with the provided tag.

Sources in src and destinations in accept and deny must refer to specific entities and do not support * wildcards. For example, an accept destination cannot be tags:*.

The legacy allow (instead of accept) continues to work in ACLs. However, it is best practice to use accept.

SSH Tests

SSH tests are available for all plans.

The sshTests section lets you write assertions about your Tailscale SSH access rules. SSH tests function similarly to ACL tests.

SSH tests run when the tailnet policy file changes. If an assertion fails, Tailscale rejects the updated tailnet policy file with an error detailing the failing tests.

The following example shows a sshTests definition performs the following tests on connections from dave@example.com to example-host-1:

  • If the user is dave, it accepts the connection.
  • If the user is admin, it checks the connection.
  • If the user is root, it denies the connection.
"sshTests": [
  {
    "src": "dave@example.com",
    "dst": ["example-host-1"],
    "accept": ["dave"],
    "check": ["admin"],
    "deny": ["root"],
  },
],

src

Specifies the user identity that's attempting to connect as SSH, which can be a user's email address, a group, a tag, or a host that maps to an IP address. The test case runs from the perspective of a device authenticated with the provided identity.

dst

Specifies one or more destinations to which the src user is connecting, which can be a user's email address, a group, a tag, or a host that maps to an IP address.

accept

Specifies zero, one, or more usernames to disallow on the dst host without requiring an additional check. Refer to action accept.

check

Specifies zero, one, or more usernames to disallow on the dst host if the src user passes an additional check. Refer to action check.

deny

Specifies zero, one, or more usernames to disallow on the dst host (under any circumstances).

IP sets

An IP set is a way to manage groups of IP addresses. It can encapsulate a collection of IP addresses, CIDRs, hosts, autogroups, and other IP sets. The primary benefit of IP sets is that they let you group multiple network parts into a single collection, enabling you to apply access control policies to the collection rather than the individual IP addresses, hosts, or subnets.

Refer to the IP sets documentation.

Network policy options

Network policy options are available for all plans.

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

derpMap

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 using Tailscale-provided DERP servers. For example, you might want to disable tailnet-provided DERP servers to meet corporate compliance requirements. Refer to running custom DERP servers for more information.

disableIPv4

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

OneCGNATRoute

The OneCGNATRoute field controls the routes that Tailscale clients generate.

Tailscale clients can have either:

  • One large 100.64/10 route to avoid churn in the routing table as devices go online and offline. (The churn is disruptive to Chromium-based browsers on macOS.)
  • Fine-grained /32 routes.

The possible values for OneCGNATRoute are:

  • An empty string or not provided: Use default heuristics for each platform.
    • For all platforms (other than macOS), Tailscale adds fine-grained /32 routes for each device.
    • On macOS (for Tailscale v1.28 or later), Tailscale adds one 100.64/10 route. Tailscale won't use one 10.64/10 route if other interfaces also route IP addresses in that range.
  • "mac-always": macOS clients always add one 100.64/10 route.
  • "mac-never": macOS clients always add fine-grained /32 routes.

randomizeClientPort

The randomizeClientPort field (if set to true) makes devices prefer a random port for WireGuard traffic over the default static port 41641. You should only use the randomizeClientPort field as a workaround for some buggy firewall devices after consulting with Tailscale (support).