Documentation
Syntax reference for the tailnet policy file
You can write Tailscaleaccess control rules such asACLs andgrants in the tailnet policy file, which is expressed inhuman JSON (HuJSON).
The tailnet policy file has the following top-level sections:
| Section | Key | Type | Purpose |
|---|---|---|---|
| Grants | grants | Access control | Create network-level and application-level access control policies with optional route filtering. Prefer grants for access control policies. |
| ACLs | acls | Access control | Create network-level access control policies. |
| SSH | ssh | Access control | Specify who can use Tailscale SSH. |
| Auto approvers | autoApprovers | Automation | Specify who can bypass the approval process to advertise subnet routers, exit nodes, and app connectors. |
| Node attributes | nodeAttrs | Attributes | Apply additional attributes to devices and users. |
| Postures | postures | Attributes | Define device posture rules to target in access control policies. |
| Tag owners | tagOwners | Targets | Define who can assign which tags to devices in your tailnet. |
| Groups | groups | Targets | Define named groups of users, devices, and subnets to target in access control policies and other definitions. |
| Hosts | hosts | Targets | Define named aliases for devices and subnets. |
| IP sets | ipsets | Targets | Define named network segments to target in access control policies and other definitions. |
| Tests | tests | Tests | Write tests to make assertions about access policies (ACLs and network-level grants) that should not change. |
| SSH test | sshTests | Tests | Write tests to make assertions about Tailscale SSH that should not change. |
You can use thevisual policy editor to manage your tailnet policy file. Refer to thevisual editor reference for guidance on using the visual editor.
Grants
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 grantapplication layer capabilities to a set of devices or users. You can also continue to define traditionalnetwork layer capabilities. For example, you can use a grant rule to give a group of users access to port8443 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 impliedaccept action.
Get started with grants
Grant access control permissions across both network connections and application permissions.
ACLs
Tailscale now secures access to resources usinggrants, a next-generation access control policy syntax. Grants provideall original ACL functionality plus additional capabilities.
ACLs will continue to workindefinitely; Tailscale will not remove support for this first-generation syntax from the product. However, Tailscale recommendsmigrating to grants and using grants for all new tailnet policy file configurations because ACLs will not receive any new features.
Theacls section lists access rules for your tailnet. Each rule grants access from a set of sources to a set of destinations.
Access rules can usegroups andtags to grant access to pre-defined sets of users and assign service role accounts to nodes. Together, groups and tags let you build powerfulrole-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 anaction,src,proto, anddst.
{"action":"accept","src":[ <list-of-sources>],"proto":"tcp",// optional"dst":[ <list-of-destinations>],}Theacl section of the tailnet policy supports the legacy fieldsusers andports, but the best practice is to usesrc (instead ofusers) anddst (instead ofports).
action
Tailscale access rules deny access by default. As a result, the only possibleaction isaccept.accept allows traffic from the source (src) to the destination (dst).
src
Thesrc field specifies a list of sources to which the rule applies. Each element in the list can be one of the following:
| Type | Example | Description |
|---|---|---|
| Any | * | All traffic originating from Tailscale devices in your tailnet, any approved subnets andautogroup:shared. It does not allow traffic originating from non-tailscale devices (unless it is an approved route). |
| User | shreya@example.com | Includes all the provided user's devices. |
| Group | group:<group-name> | Includes all users in the provided group. |
| Tailscale IP | 100.101.102.103 | Includes only the device that owns the provided Tailscale IP. IPv6 addresses must follow the format[1:2:3::4]:80. |
| Subnet CIDR Range | 192.168.1.0/24 | Includes any IP address within the provided subnet. |
| Host | my-host | Includes the Tailscale IP address or CIDR in thehosts section. |
| Tag | tag:production | Includes all devices with the provided tag. |
| Autogroup | autogroup:<role|property> | Includes devices of users, destinations, or usernames with the same properties or roles. |
| Autogroup (all) | autogroup:danger-all | A special autogroup that selects all sources including those outside your tailnet. |
You can optionally include thesrcPosture field to further restrictsrc devices to the ones matching a set ofdevice posture conditions.
proto
Theproto 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 specifyproto as anIANA IP protocol number1-255 (for example,"16") or one of the supported named aliases.
Expand to view all named aliases.
| Protocol | proto | IANA protocol number |
|---|---|---|
| Internet Group Management (IGMP) | igmp | 2 |
| IPv4 encapsulation | ipv4,ip-in-ip | 4 |
| Transmission Control (TCP) | tcp | 6 |
| Exterior Gateway Protocol (EGP) | egp | 8 |
| Any private interior gateway | igp | 9 |
| User Datagram (UDP) | udp | 17 |
| Generic Routing Encapsulation (GRE) | gre | 47 |
| Encap Security Payload (ESP) | esp | 50 |
| Authentication Header (AH) | ah | 51 |
| Stream Control Transmission Protocol (SCTP) | sctp | 132 |
Notes about theproto field:
- You must use Tailscale version v1.18.2 or later to use the
protofield. 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 port.
dst
Thedst field specifies a list of destinations to which the rule applies. Each element in the list specifies ahost and one or moreports in the format<host>:<ports>.
Thehost can be any of the following types:
| Type | Example | Description |
|---|---|---|
| Any | * | Includes any destination (no restrictions). |
| User | shreya@example.com | Includes any device currently signed in as the provided user. |
| Group | group:<group-name> | Includes all users in the provided group. |
| Tailscale IP address | 100.101.102.103 | Includes only the device that owns the provided Tailscale IP address. |
| Hosts | example-host-name | Includes the Tailscale IP address in thehosts section. |
| Subnet CIDR Range | 192.168.1.0/24 | Includes any IP address within the given subnet. |
| Tags | tag:<tag-name> | Includes any device with the provided tag. |
| Internet access through anexit node | autogroup:internet | Includes devices with access to the internet throughexit nodes. |
| Own devices | autogroup:self | Select a user's devices.autogroup:self is a special autogroup selector that, when combined with a src selector ofautogroup:<role>,group:<name>, or an individual user, lets you grant access to a user's own devices from their own devices. |
| Tailnet devices | autogroup:member | Includes devices in the tailnet where the user is a direct member (not a shared user) of the tailnet. |
| Admin devices | autogroup:admin | Includes devices where the user is anAdmin. |
| Network admin devices | autogroup:network-admin | Includes devices where the user is aNetwork admin. |
| IT admin devices | autogroup:it-admin | Includes to devices where the user is anIT admin. |
| Billing admin devices | autogroup:billing-admin | Includes devices where the user is aBilling admin. |
| Auditor devices | autogroup:auditor | Includes devices where the user is anAuditor. |
| Owner devices | autogroup:owner | Includes devices where the user is the tailnetOwner. |
| IP sets | ipset:<ip-set-name> | Includes all targets in the IP set. |
Theports field can be any of the following types:
| Type | Description | Example |
|---|---|---|
| Any | Includes any port number. | * |
| Single | Includes a single port number. | 22 |
| Multiple | Includes two or more port numbers separated by commas. | 80,443 |
| Range | Includes a range of port numbers. | 1000-2000 |
Subnet routers and exit nodes
ACLs don't limit the discovery of routes. If a device is asubnet router, you can restrict access to it independently from the subnet. If a device is anexit 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 ifnot-allowed@example.com is allowed access to198.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 toautogroup:internet can use exit nodes. All other devices (without access toautogroup: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 ifnot-allowed@example.com can access198.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 toissue #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.
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):
| Format | Description | Example |
|---|---|---|
username@example.com | Use if the user signs into Tailscale with an email address. | alice@example.com |
username@github | Use if the user signs into Tailscale with a GitHub account. | alice@github |
username@passkey | Use 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
groupssection 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
Anautogroup is a special group that automatically includes users, destinations, or usernames with the same properties.
| Allowed | Autogroup | Description | Availability by plan |
|---|---|---|---|
As adst | autogroup:internet | Use to allow access for any user throughanyexit node in your tailnet. | Available onall plans |
As adst | autogroup:self | Use to allow access for any user that is authenticated as the same user as the source. Does not apply to tags. | Available onall plans |
As asrc ordst,tagOwner, orautoApprover | autogroup:owner | Use to allow access for the tailnetOwner. | Available onall plans |
As asrc ordst,tagOwner, orautoApprover | autogroup:admin | Use to allow access for any user who has the role ofAdmin. | Available onall plans |
As asrc ordst,tagOwner, orautoApprover | autogroup:member | Use 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. | Available onall plans |
As asrc ordst,tagOwner, orautoApprover | autogroup:tagged | Use to allow access for any user who is a device that istagged. | Available onall plans |
As asrc ordst,tagOwner, orautoApprover | autogroup:auditor | Use to allow access for any user who has the role ofAuditor. | Available onthe Personal, Personal Plus, Premium, and Enterprise plans |
As asrc ordst,tagOwner, orautoApprover | autogroup:billing-admin | Use to allow access for any user who has the role ofBilling admin. | Available onthe Personal, Personal Plus, Premium, and Enterprise plans |
As asrc ordst,tagOwner, orautoApprover | autogroup:it-admin | Use to allow access for any user who has the role ofIT admin. | Available onthe Personal, Personal Plus, Premium, and Enterprise plans |
As asrc ordst,tagOwner, orautoApprover | autogroup:network-admin | Use to allow access for any user who has the role ofNetwork admin. | Available onthe Personal, Personal Plus, Premium, and Enterprise plans |
As asrc ordst,tagOwner, orautoApprover | 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 onthe Starter, Premium, and Enterprise plans |
As asrc | autogroup:shared | Use to allow access for any user who accepted asharing invitation to your network. This lets you write rules without knowing the email addresses in advance. | Available onall plans |
| As anSSH user | autogroup:nonroot | Use to allowTailscale SSH access to any user that is notroot. | Available onthe Personal, Personal Plus, Premium, and Enterprise plans |
| As anSSH user | localpart:*@<domain> | Use to allowTailscale SSH access to the user whose name matches thelocal-part of the user's login. | Available onthe Premium and Enterprise plans |
autogroup:self only applies to user-owned devices. It does not apply to tagged devices. You cannot useautogroup:self withautogroup:tagged.
The legacy autogroupautogroup:members will continue to work, but it's best practice to useautogroup:member instead. You cannot use bothautogroup:member andautogroup:members in the same tailnet policy file.
The following examplessh 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, thessh rule usesautogroup:self for thedst field andautogroup:nonroot in theusers field. If you change thedst field fromautogroup:self to some other destination, such as anACL tag, also consider replacingautogroup:nonroot in theusers field. If you don't removeautogroup:nonroot from theusers field, then anyone permitted by thesrc setting will be able to SSH in as any nonroot user on thedst device.
Domain based autogroups
Some autogroups include a specific domain name. For example,user:*@example.com orlocalpart:*@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 tailnetexample.com uses the autogroupuser:*@altostrat.com, this group includes all members of theexample.com tailnet who log in as a user at@altostrat.com (such aslaura@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.iois aliased toexample.comand you want to include users from bothexample.comandexample.io, use bothuser:*@example.comanduser:*@example.io. - Although the expressions use the wildcard
*, it does not support arbitrary wildcards. For example,user:b*b@example.comwill not matchbob@example.com.
Groups
Thegroups 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 anengineering group and asales 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 prefixgroup:. Each group member is specified by their full email address, as explained in theusers 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 examplegroups definition above, and directly from theUsers page of the admin console.
Edit a user's group membership from the Users page
You must be anOwner, Admin, or Network admin to edit a user's group membership from theUsers page.
- Open theUsers page in the admin console.
- Find the user by name.
- Select the
menu >Edit group membership.
- In theEdit group membership dialog:
- To add a group, selectAdd to a group, then the group to add.
- To remove a group, select theX next to the group to delete.
- When you finish editing the groups for the user, selectSave.
Synced groups
You can create groups in your identity provider and sync them with Tailscale's access control policies withuser 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 thesecurity-team group.
{"grants":[{"src":["group:security-team@example.com"],"dst":["tag:logging"],"ip":["*"]}],"tagOwners":{"tag:logging":["group:security-team@example.com"]}}You can only edit groups defined in the tailnet policy file. 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
Thetags section of the tailnet policy file lets you createtags that group non-human devices. You can then use the tags to select these devices in an ACL.
You mustdefine the tag in thetagOwners section of the tailnet policy file before using it in an ACL. To tag a device,authenticate as the tag on the device.
Hosts
Thehosts 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
Thepostures section lets you define a set ofdevice posture management rules that a device must meet as part of a specific access rule.
The following example shows how to usepostures to select macOS devices runningnode 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 prefixposture: followed by a name, a set ofposture attributes, and their allowed values, given as a list of strings.
Refer todevice posture management for more information
Tag owners
ThetagOwners 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 atagOwners definition that:
- Sets the
engineeringgroup as the owner of thewebservertag. - Sets
president@example.comand thesecurity-adminsgroup as owners of thesecure-servertag. - Sets the
autogroup:memberautogroup as the owner of thecorptag.
"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 prefixtag:. A tag owner can be a user's full login email address (as defined in theusers section above), agroup name, anautogroup, or another tag.
A shorthand notation,[], is available forautogroup:admin. That is, the following are equivalent:
"tag:monitoring":["autogroup:admin",],"tag:monitoring":[],The autogroupsautogroup:admin andautogroup:network-admin can assign all tags, so[] implicitly allows onlyautogroup:admin andautogroup:network-admin.
Auto approvers
TheautoApprovers 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: anAdmin must enable them on the device running Tailscale and in the Tailscale admin console. These actions include:
- Advertising a specified set of routes as a subnet router.
- Advertising an exit node.
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 atag as an auto approver.
The following example shows anautoApprovers definition that automatically approves the192.0.2.0/24 routes foralice@example.com, members of theengineering group, and devices tagged withfoo. It also automatically allows devices tagged withfoo 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 theusers section above), agroup name, anautogroup or a tag.
Auto-approver policies only apply when Tailscale first receives a subnet route advertisement. Updating the tailnet policy file to add or modify auto-approvers does not retroactively approve existing unapproved routes. To trigger auto-approval for an existing unapproved route, remove the route from the subnet router and advertise it again.
Tailscale SSH
Thessh section of the tailnet policy file defines lists of users and devices that can useTailscale SSH (and the SSH users). To allow a connection, the tailnet policy file must contain rules permitting both network access and SSH access:
- An access rule to allow connections from the source to the destination on port 22.
- 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 anssh 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.
acceptaccepts connections from users already authenticated in the tailnet.checkrequires users to periodically reauthenticate according to thecheckPeriod.
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 thedst 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 anysrc anddst combinations that allow multiple users to access a single user's device.
Granting access toautogroup:members also allows access toexternal invited users if the destination device isshared with them, even if they have no devices in your tailnet.
dst
Specifies the destination (where the connection goes). The destination can be a tag,autogroup:self (if the source contains only users or groups), or a single named user (if the source contains only the same named user). The reason for these limitations is Tailscale does not let a user start a Tailscale SSH session on a user-owned device, unless the source is a device owned by the same user.
You cannot specify a port for the destination because the only allowed port is22. You cannot specify* 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:nonrootto allow any user that is notroot. - Specify
localpart:*@<domain>to allow the user on the host whose name matches thelocal-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 isdave+sshuser@example.com, Tailscale will map this to the ssh userdave+sshuser. - If no user is specified, Tailscale will use the local host's user. That is, if the user is logged in as
alicelocally, then connects with SSH to another device, Tailscale SSH will try to log in as useralice.
checkPeriod
Whenaction ischeck,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
alwaysto require a check on every connection. Usingalwaysmight cause unexpected behavior with automation tools that open many SSH connections in quick succession (such asAnsible).
acceptEnv
The host must be running Tailscale v1.76.0 or later to useacceptEnv.
Specifies the set of allowlisted environment variable names that clients can send to the host usingSendEnv orSetEnv.
Values can contain* and? wildcard characters.* matches zero or more characters and? matches a single character.
acceptEnv examples
| acceptEnv | Permitted | Rejected |
|---|---|---|
* | FOO_AFOO_BFOO_OTHERBAZ | |
FOO_* | FOO_AFOO_BFOO_OTHER | BAZ |
FOO_? | FOO_AFOO_B | FOO_OTHERBAZ |
FOO_A | FOO_A | FOO_BFOO_OTHERBAZ |
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 useralice@example.com to access a resource with anaccept rule, and a rule allowinggroup:devops whichalice@example.com belongs to, to access a resource with acheck rule, then thecheck rule applies.
Tailnets that have not modified their tailnet policy file have adefault 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 atagged 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 incheck mode.
- From a user to a tagged device that has beenshared 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:
{"grants":[{"src":["*"],"dst":["*"],"ip":["*"]}],"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):
{"grants":[{"src":["*"],"dst":["*"],"ip":["*"]}],"ssh":[{"action":"accept","src":["autogroup:member"],"dst":["autogroup:self"],"users":["autogroup:nonroot"]}]}To allowgroup:sre to access devices in the production environment taggedtag:prod:
{"groups":{"group:sre":["alice@example.com","bob@example.com"]},"grants":[{"src":["group:sre"],"dst":["tag:prod"],"ip":["*"]}],"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 taggedtag:dev that have beenshared 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 allowdave@example.com to authenticate as the host userdave.
To allow any tailnet member in the login domainexample.com to access devices in the production environment that are taggedtag:prod, as a user that matches their login email local-part:
{"grants":[{"src":["user:*@example.com"],"dst":["tag:prod"],"ip":["*"]}],"ssh":[{"action":"accept","src":["user:*@example.com"],"dst":["tag:prod"],"users":["localpart:*@example.com"]}]}Node attributes
ThenodeAttrs section of the tailnet policy file defines additional attributes that apply to specific devices in your tailnet.
One way you could use node attributes would be to set differentNextDNS configurations for different devices in your tailnet. The following example shows anodeAttrs definition that targetsmy-kid@my-home.com andtag:server with the attributesnextdns:abc123 andnextdns: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:abc123specifics the NextDNS configuration IDabc123. If this is used, the attribute overrides the global NextDNS configuration. - The attribute
nextdns:no-device-infodisables sending device metadata to NextDNS.
The following example allows members of the tailnet to useTailscale Funnel on their nodes:
"nodeAttrs":[{"target":["autogroup:members"],"attr":["funnel"],},],You can use anodeAttrs policy to enable therandomize-client-port setting for specific devices instead of using anetwork-wide policy setting.
"nodeAttrs":[{"target":["tag:office-network","group:sea-office"],"attr":["randomize-client-port"],},],app
Specifies which application layer capabilities apply to these nodes (devices).
The following example node attribute definition configures theexample-connector tag for theexample.com domains.
{"target":["*"],"app":{"tailscale.com/app-connectors":[{"name":"example-app","connectors":["tag:example-connector"],"domains":["example.com"],"routes":["192.0.2.0/24"],},],},}The specific application defines the names of capabilities in the format<domainName>/<capabilityName>. The example usestailscale.com/app-connectors.
The value associated with each capability is an array of JSON objects, each containing capability-specific configuration options.
Refer to theHow app connectors work andBest practices for using app connectors topics.
Tests
Thetests section lets you write assertions about your access control policies (grants and ACLs) 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.
Tests let you ensure you don't accidentally revoke important permissions or expose a critical system.
Atests 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 auser's email address, agroup, atag, or ahost that maps to an IP address. The test case runs from the perspective of a device authenticated with the provided identity.
srcPostureAttrs
Specifies thedevice 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 containdevice posture conditions.
proto
Specifies the IP protocol foraccept anddeny rules, similar to theproto field inACL rules. When omitted, the test checks for either TCP or UDP access.
When testing Internet Control Message Protocol (ICMP) access, set"proto": "icmp" and use port0 in your destinations since ICMP doesn't use ports. The following example tests that useralice@example.com canping devices tagged withtag:production:
"tests":[{"src":"alice@example.com","proto":"icmp","accept":["tag:production:0"],},],accept anddeny destinations
Specifies destinations to accept or deny. Each destination in the list is of the formhost:port whereport is a single numeric port andhost is one of the following:
| Type | Example | Description |
|---|---|---|
| Tailscale IP | 100.101.102.103 | Includes the device with the provided Tailscale IP address. IPv6 addresses must follow the format[1:2:3::4]:80. |
| Host | my-host | Includes the Tailscale IP address in thehosts section. |
| User | shreya@example.com | Includes the Tailscale IP addresses of devices signed in as the provided user. |
| Group | group:security@example.com | Includes the Tailscale IP addresses of devices signed in as a representative member of the provided group. |
| Tag | tag:production | Includes the Tailscale IP addresses of devices tagged with the provided tag. |
You cannot use CIDR (subnet) notation to test subnet ranges. For example,192.168.1.0/24 is not valid. Instead, you must specify the individual IP addresses or hostnames.
Sources insrc and destinations inaccept anddeny must refer to specific entities and do not support* wildcards. For example, anaccept destination cannot betags:*.
The legacyallow (instead ofaccept) continues to work in ACLs. However, it is best practice to useaccept.
SSH Tests
ThesshTests section lets you write assertions about yourTailscale SSH access rules. SSH tests function similarly to ACLtests.
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 asshTests definition performs the following tests on connections fromdave@example.com toexample-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 auser's email address, agroup, atag, or ahost 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 thesrc user is connecting, which can be auser's email address, agroup, atag, or ahost that maps to an IP address.
accept
Specifies zero, one, or more usernames to disallow on thedst host without requiring an additional check. Refer toactionaccept.
check
Specifies zero, one, or more usernames to disallow on thedst host if thesrc user passes an additional check. Refer toactioncheck.
deny
Specifies zero, one, or more usernames to disallow on thedst 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 theIP sets documentation.
Network policy options
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
ThederpMap section lets you addcustom 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 torunning custom DERP servers for more information.
disableIPv4
Instead of thedisableIPv4 field, it is recommended to use thedisable-ipv4 node attribute as described inCGNAT conflicts.
ThedisableIPv4 field (if set totrue) 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 the100.64.0.0/10 carrier-grade NAT address range.
OneCGNATRoute
TheOneCGNATRoute field controls the routes that Tailscale clients generate.
Tailscale clients can have either:
- One large
100.64/10route to avoid churn in the routing table as devices go online and offline. (The churn isdisruptive to Chromium-based browsers on macOS.) - Fine-grained
/32routes.
The possible values forOneCGNATRoute are:
- An empty string or not provided: Use default heuristics for each platform.
- For all platforms (other than macOS), Tailscale adds fine-grained
/32routes for each device. - On macOS (for Tailscale v1.28 or later), Tailscale adds one
100.64/10route. Tailscale won't use one100.64/10route if other interfaces also route IP addresses in that range.
- For all platforms (other than macOS), Tailscale adds fine-grained
"mac-always": macOS clients always add one100.64/10route."mac-never": macOS clients always add fine-grained/32routes.
randomizeClientPort
You should only use therandomizeClientPort field as a workaround for somefirewall devices after consulting withTailscale Support.
Setting therandomizeClientPort field totrue makes devices use a random port forWireGuard traffic rather than the default static port41641.
Last updated Nov 26, 2025
