Grants
Tailscale’s access control methodology follows the least privilege and zero trust principles. There are two ways to define access controls for your tailnet: access control lists (ACLs) and grants. Both methods follow a deny-by-default principle and are defined in the tailnet policy file using a declarative huJSON syntax.
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.
{
"grants": [
// Grants can still define network layer access controls
{
"src": [<list-of-sources>], // These sources (devices or users)
"dst": [<list-of-destinations], // can access these destination devices
"ip": [<list-of-ports-or-protocols>], // using the following ports or protocols
}
// But they can also define application layer capabilities
{
"src": [<list-of-sources>], // These sources (devices or users)
"dst": [<list-of-destinations], // can access these destination devices
"ip": [<list-of-ports-or-protocols>], // using the following ports or protocols,
"app": {<list-of-application-capabilities>} // and once they have access, they are granted these application permissions.
}
]
}
Each entry grants the source (src
) specified capabilities on the destination
. You can use the grants
object to grant capabilities at the network layer (ip
) or the application layer (app
). The Tailscale policy engine compiles all capabilities and sends them to each Tailscale client. Each client then caches the policies locally to improve performance and reduce reliance on the coordination server.
Grants and ACLs
Grants and ACLs are at feature parity for network-level permissions, including features like device posture, ACL tests, and previews. You can use both grants and ACLs simultaneously in your tailnet policy. However, the best practice is to prefer grants because they offer more power and flexibility for most users.
Reference
The grants
section of your tailnet policy file is an array of objects, where each object must have a network source field (src
) and a network destination field (dst
). Grant objects can optionally include the ip
, app
, or srcPosture
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
(Optional): An array of strings that define the network-layer capabilities to grant.app
(Optional): A map of strings to arrays of objects that define the application-layer capabilities to grant.srcPosture
(Optional): An array of device posture conditions to further restrict thesrc
.via
(Optional): A reference to one or more devices to route traffic through. Learn more about route filtering with Via.
src
The src
field is an array of selectors that define the target network sources. A network source is the device or node that initiates a network communication or sends data packets.
You can use any of the following selectors to define the network source
Selector | Description | Example |
---|---|---|
* | Select all sources in your tailnet and from approved subnet routes. This does not include devices outside your tailnet (unless they're on an approved subnet). | |
autogroup:danger-all | Select all sources, including those outside your tailnet. | |
group:<groupName> | Select all members of a specific group. | group:prod |
<email> | Select a specific user by their email address. For GitHub users, use username@github . For Passkey users, use username@passkey . | name@example.com , username@github , username@passkey |
tag:<tagName> | Select all devices with a specific tag. | tag:tailsql |
autogroup:<role> | Select all members of a specific role. Possible roles are admin , member , owner , it-admin , network-admin , billing-admin , and auditor . | autogroup:admin |
autogroup:tagged | Select all devices with a tag (any tag). | |
autogroup:shared | Select all devices that belong to users who have accepted a sharing invitation to your tailnet. | |
<cidr>/<ip> | Select all devices in a CIDR range. | 192.0.2.0/24 , 192.0.2.5 . |
<hostAlias> | Select a host by its user-defined alias. You can use this selector to grant access to a specific device or a CIDR range. You can find hostAlias definitions in the hosts section. | example-host-name |
ipset: <ipsetName> | Select an IP set (a named group of IP address ranges). | ipset: prod |
dst
The dst
field is an array of selectors that define the destination of the grant. A network destination refers to the device, user, or target that receives the data packets from the source.
You can use any of the following selectors to define the network destination:
Selector | Description | Example |
---|---|---|
* | Select all sources in your tailnet and from approved subnet routes. This does not include devices outside your tailnet (unless they're on an approved subnet). | |
autogroup:danger-all | Select all sources, including those outside your tailnet. | |
group:<groupName> | Select all members of a specific group. | group:analytics |
<email> | Select a specific user by their email address. For GitHub users, use username@github . For Passkey users, use username@passkey . | name@example.com , username@github , username@passkey |
tag:<tagName> | Select all devices with a specific tag. | tag:tailsql |
autogroup:<role> | Select all members of a specific role. Possible roles are admin , member , owner , it-admin , network-admin , billing-admin , and auditor . | autogroup:admin |
autogroup:tagged | Select all devices with a tag (any tag). | |
autogroup:internet | autogroup:internet is a special autogroup selector that lets you grant access to use an exit node to access the internet. | |
autogroup:self | Select a user's devices. autogroup:self is a special autogroup selector that, when combined with a src selector of autogroup:member , lets you grant access to a user's own devices from their own devices. | |
<cidr>/<ip> | Select all devices in a CIDR range. | 192.0.2.0/24 , 192.0.2.5 . |
<hostAlias> | Select a host by its user-defined alias. You can use this selector to grant access to a specific device or a CIDR range. You can find hostAlias definitions in the hosts section. | example-host-name |
ipset: <ipsetName> | Select an IP set (a named group of IP address ranges). | ipset: prod |
ip
The ip
field is an array of strings that grant network layer capabilities. You can use any of the following selectors to grant access to network layer capabilities:
Selector | Description | Example |
---|---|---|
* | Allow access to all ports on the destination (implies TCP, UDP, and ICMP access). | |
<port> | Allow access to a specific port on the destination (implies TCP, UDP, and ICMP access). You can specify a single port (443 ) or a range of ports (80-443 ). | 443 , 80-443 |
<proto>:* | Allow all ports of the specified protocol (proto ) access to the destination. This is especially useful for protocols that do not have ports, such as ICMP. For example, icmp:* or sctp:* . | icmp:* , sctp:* |
<proto>:<port> | Allow access to a specific protocol and port combination on the destination. You can specify a single port (tcp:443 ) or a range of ports (tcp:80-443 ). | tcp:443 , tcp:80-443 |
You can specify the IP protocol (proto
) as an IANA IP protocol number 1-255
(for example, "16"
) or one of the following named aliases (for example, "sctp"
).
Expand 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 |
app
The app
field is an optional field that maps strings to arrays of objects that define the application layer capabilities to grant. The strings are the application layer capabilities to grant, and the objects are the parameters for those capabilities.
The specific application (such as TailSQL) defines the names of capabilities names in the format <domainName>/<capabilityName>
.
- The
domainName
groups capabilities into namespaces to avoid collisions with other applications. - The
capabilityName
defines the specific capability. For example, the TailSQL application defines thetailscale.com/cap/tailsql
capability.
The specific application also defines the parameters for each capability. The Tailscale policy engine treats these parameters as opaque JSON objects. The policy engine compiles the parameters and sends them to the Tailscale clients but does not validate them. The Tailscale clients can then use these parameters to make authorization decisions locally.
Tailscale is not involved in creating, naming, or validating application capabilities or their parameters (unless it's a Tailscale application). It's the application developer's responsibility to document all capabilities and parameters.
srcPosture
The srcPosture
field is an array of device posture conditions you can use to further restrict the network source (src
). For example, you can use srcPosture
to restrict access to only devices running a specific version of the Tailscale client.
via
Via introduces routing awareness to grants by letting you include a via
field to specify how Tailscale can route the destination (dst
) from the source (src
).
You can use the via
syntax to define the exit nodes, subnet routers, or app connectors a source can access when they use a specific destination. For example, you can create a grant that forces traffic through a specific exit node when it goes from the engineering team group to the GitHub app connector.
Example scenario
The following scenario demonstrates connecting an application (TailSQL) to Tailscale and fine-tuning access to TailSQL based on tags and groups.
In this example scenario, the tailnet has the following configured:
- A
prod
group for the production team. - An
analytics
group for the analytics team. - A TailSQL application tagged with
tailsql
and running on port443
. - A Prometheus server tagged with
prom
.
The final example grants group:prod
access to all TailSQL data sources, grants group:analytics
access to the TailSQL warehouse
data source, and allows Prometheus to monitor TailSQL.
{
"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"],
},
]
}
Expand for step-by-step instructions to re-create the example grants
along with context and explanations.
-
Create a
grants
object in the tailnet policy file that grants the production group (group:prod
) access to the TailSQL interface (identified bytag:tailsql
and port443
). The following example lets devices in your tailnet connect in theprod
group connect to port443
of devices tagged withtailsql
.{ "grants": [ { "src": ["group:prod"], "dst": ["tag:tailsql"], "ip": ["443"], } ] }
-
Allow Prometheus to monitor the TailSQL application. TailSQL already exposes a metrics endpoint reachable on port
443
at/debug/varz
. The following example allows Prometheus (identified bytag:prom
) access that endpoint.{ "grants": [ { "src": ["group:prod"], "dst": ["tag:tailsql"], "ip": ["443"], }, { "src": ["tag:prom"], "dst": ["tag:tailsql"], "ip": ["443"], } ] }
-
Allow users in the
analytics
group to connect to TailSQL devices by adding"group:analytics"
to thesrc
array.{ "grants": [ { "src": ["group:prod", "group:analytics"], "dst": ["tag:tailsql"], "ip": ["443"], }, { "src": ["tag:prom"], "dst": ["tag:tailsql"], "ip": ["443"], }, ] }
At this point, the example grants Prometheus and the
prod
andanalytics
groups access to the shared TailSQL instance. However, the Prometheus server, theprod
group, and theanalytics
group all require access to different datasets. Theprod
group uses TailSQL to inspect some backups, whereas theanalytics
group requires access to the data warehouse.
You can configure thegrant
only to let each group access what it needs (and no more) by leveraging theapp
field to define application-level capabilities. -
Fine-tune access to the TailSQL application by defining two
app
policies: one that lets theprod
group query all data sources. And another that restricts theanalytics
group's access to only thewarehouse
data source.{ "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"], }] }
-
Review the
grant
using the LocalAPI and thetailscale whois
command. In the following example,192.0.2.5
is part of theprod
group and can access all data sources atTailscale.com/cap/tailsql
.$ tailscale whois 192.0.2.5 Machine: Name: example.ts.net ID: nXXXXXCNTRL Addresses: [192.0.2.5/24] User: Name: user@example.com ID: 12345 Capabilities: - tailscale.com/cap/tailsql: [ { "dataSrc": [ "*" ] }, { "dataSrc": [ "warehouse" ] } ]