ACL grants
Tailscale is a programmable private network, which means that you can define exactly what your network looks like, which devices are on it, and what they can access. One of the key inputs to defining your network is the tailnet policy file.
At the core of the tailnet policy is the grants
array. Each entry grants
source
the specified capabilities
on the destination
. The capabilities
being granted can either be at the IP layer (ip
) or at the application layer
(app
). These capabilities are compiled by the policy engine and pushed down to
each Tailscale client and cached locally. This allows the Tailscale client to
make decisions locally without having to query the coordination server.
The grants
section is an array of objects, where each object must have a src
and dst
, and may have ip
and app
capabilities. The src
and dst
fields
are arrays of selectors. The ip
field is an array of of network level
capabilities, and the app
field is a map application level capabilities. We
will walk through each of these fields in more detail below.
Walkthrough
Let us walk through an example of trying to connect an application to Tailscale. In this instance, we will use TailSQL as an example. TailSQL is a web SQL playground that lets you query your databases from the browser. It is a tool for debugging and inspecting your databases. It is also an example of an application that you would want to connect to and secure using Tailscale.
When setting it up, you need to give the production group access to the interface. To achieve that in the tailnet policy file, write something like:
{
"grants": [{
"src": ["group:prod"],
"dst": ["tag:tailsql"],
"ip": ["443"],
}]
}
This rule allows any member of group:prod
to connect to port 443
on any
Tailscale device tagged with tag:tailsql
. It will be compiled by the policy
engine and pushed down to relevant devices to allow these connections through.
Now, let's add some monitoring to TailSQL. It already exposes a metrics endpoint
reachable on port 443
at /debug/varz
, we can allow prometheus access to scrape
that endpoint.
{
"grants": [{
"src": ["group:prod"],
"dst": ["tag:tailsql"],
"ip": ["443"],
},{
"src": ["tag:prom"],
"dst": ["tag:tailsql"],
"ip": ["443"],
}]
}
Now that TailSQL is operational, it is time to give the analytics group access to TailSQL as well. To do so:
{
"grants": [{
"src": ["group:prod", "group:analytics"],
"dst": ["tag:tailsql"],
"ip": ["443"],
},{
"src": ["tag:prom"],
"dst": ["tag:tailsql"],
"ip": ["443"],
}]
}
At this point, we have both the production group and the analytics group with access to the shared TailSQL instance. However, as these are different operational groups, they require access to different datasets. The production group would like to use TailSQL to inspect some backups, whereas the analytics group requires access to the data warehouse. If your databases contain sensitive information, you may want to allow access to the SQL playground only for users in a certain group.
In the above example, even the prometheus service has access to the instance as a side effect of giving it access to the debug endpoint.
This is where we can leverage application layer capabilities to define an authorization policy which allows the production team to query to all available data sources, and restricts the analytics team data warehouse source. Monitoring does not need access to any data sources, it only needs to scrape metrics from TailSQL's HTTPS server.
{
"grants": [{
"src": ["group:prod"],
"dst": ["tag:tailsql"],
"ip": ["443"],
"app": {
"tailscale.com/cap/tailsql": [{
"dataSrc": ["*"],
}],
},
},{
"src": ["group:analytics"],
"dst": ["tag:tailsql"],
"ip": ["443"],
"app": {
"tailscale.com/cap/tailsql": [{
"dataSrc": ["warehouse"],
}],
},
},{
"src": ["tag:prom"],
"dst": ["tag:tailsql"],
"ip": ["443"],
}]
}
Similarly to IP grants, these are compiled and pushed down to relevant clients.
This will then allow all devices tagged with tag:tailsql
to query their local
Tailscale client and query the tailscale.com/cap/tailsql
grant. You can do this by
using the LocalAPI and the tailscale whois
command.
$ tailscale whois 100.64.0.5
Machine:
Name: example.ts.net
ID: nXXXXXCNTRL
Addresses: [100.64.0.5/32 fd7a:115c:a1e0::c477/128]
User:
Name: user@example.com
ID: 12345
Capabilities:
- tailscale.com/cap/tailsql:
[
{
"dataSrc": [
"*"
]
},
{
"dataSrc": [
"warehouse"
]
}
]
ACLs and grants
ACLs and Grants are at feature parity for network level permissions, including features like device posture, ACL tests, and previews. Both can be used simultaneously in your tailnet policy, although we expect grants will be more powerful and expressive for most users.
Reference
Each grant is an object with the following fields:
src
: An array of selectors that define the source of the grant.dst
: An array of selectors that define the destination of the grant.ip
: An optional array of strings that define the IP layer capabilities being granted.app
: An optional map of strings to arrays of objects that define the application layer capabilities being granted.srcPosture
: An optional array of device posture conditions that can be used to further restrictsrc
.
src
The src
field is an array of selectors that define the source of the grant.
These selectors can be any of the following:
*
: The wildcard selector lets you select all devices. This is useful for granting access to all devices.group:<group name>
: The group selector lets you select all members of a group. This is useful for granting access to a group of users.<email>
: The email selector lets you select a specific user. This is useful for granting access to a specific user. For GitHub users, this is theirusername@github
, for Passkeys, this is theirusername@passkey
.tag:<tag name>
: The tag selector lets you select all devices with a specific tag. This is useful for granting access to a group of devices.autogroup:<role>
: The autogroup selector lets you select all members of a role. This is useful for granting access to a role of users. Possible roles areadmin
,member
,owner
,it-admin
,network-admin
,billing-admin
andauditor
.autogroup:tagged
: The autogroup selector lets you select all devices with a tag.autogroup:shared
: The autogroup selector lets you select all devices belonging to user who have accepted a sharing invitation to your network.{cidr}/{ip}
: The cidr selector lets you select all devices in a CIDR range. This is useful for granting access to a group of devices. For example,10.0.0.0/8
or100.64.0.5
.{hostAlias}
: The hostAlias selector lets you use a user-defined alias. This is useful for granting access to a specific device or a CIDR range. These are defined in the hosts section.
dst
The dst
field is an array of selectors that define the destination of the grant.
These selectors can be any of the following:
*
: The wildcard selector lets you select all devices. This is useful for granting access to all devices.group:<group name>
: The group selector lets you select all members of a group. This is useful for granting access to a group of users.<email>
: The email selector lets you select a specific user. This is useful for granting access to a specific user. For GitHub users, this is theirusername@github
. For Passkey users, this is theirusername@passkey
.tag:<tag name>
: The tag selector lets you select all devices with a specific tag. This is useful for granting access to a group of devices.autogroup:<role>
: The autogroup selector lets you select all members of a role. This is useful for granting access to a role of users. Possible roles areadmin
,member
,owner
,it-admin
,network-admin
,billing-admin
andauditor
.autogroup:tagged
: The autogroup selector lets you select all devices with a tag. This is useful for granting access to a group of devices.autogroup:internet
: This is a special autogroup selector that lets you grant access to use an exit node to access the internet.autogroup:self
: This is a special autogroup selector that when combined with a src selector ofautogroup:member
lets you grant access to a user's own devices from their own devices.{cidr}/{ip}
: The cidr selector lets you select all devices in a CIDR range. This is useful for granting access to a group of devices. For example,10.0.0.0/8
or100.64.0.5
.{hostAlias}
: The hostAlias selector lets you use a user-defined alias. This is useful for granting access to a specific device or a CIDR range. These are defined in the hosts section.
ip
The ip
field is an array of strings that define the IP layer capabilities
being granted. These strings can be any of the following formats:
*
: This allows access to all ports on the destination. This implies TCP, UDP and ICMP access.<port>
: This allows access to a specific port on the destination. This implies TCP, UDP and ICMP access. Ports can be specified as a single port or a range of ports. For example,443
or80-443
.<proto>:*
: This allows allproto
access to the destination, regardless of port. This is especially useful for protocols that do not have ports, such as ICMP. For example,icmp:*
orsctp:*
.<proto>:<port>
: This allows access to a specific port on the destination. This lets you specify the protocol. Ports can be specified as a single port or a range of ports. For example,tcp:443
ortcp:80-443
.
proto
can be specified as either an IANA IP protocol number 1-255 (for example, "16"
) or one of the following named aliases (for example, "sctp"
):
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 |
app
The app
field is a map of strings to arrays of objects that define the
application layer capabilities being granted. The strings are the application
layer capabilities being granted, and the objects are the parameters for that
capability. The names of the capabilities are defined by the application and
should follow the format <domainName>/<capabilityName>
. The domainName
lets you namespace your capabilities and avoid collisions with other
applications, and the capabilityName
lets you define the specific
capability. For example, the TailSQL application defines the
tailscale.com/cap/tailsql
capability.
The parameters for each capability are defined by the application and are treated as opaque JSON objects by the policy engine. The policy engine does not validate the parameters, but it does compile them and push them down to the Tailscale clients. The Tailscale clients can then use these parameters to make authorization decisions locally. The parameters are defined by the application and should be documented by the application developer defining the capability.
srcPosture
The srcPosture
field is an array of device posture conditions
that can be used to further restrict src
. For example, you can use this to
restrict access to only devices that are running a specific version of the
Tailscale client.