Declarative node sharing
Declarative node sharing lets you manage access to resources across multiple trusted tailnets by defining sharing relationships directly in the tailnet policy file.
Unlike link-based node sharing, which shares individual nodes with individual users, declarative node sharing works at the policy level: administrators use policy to control which resources they share across tailnet boundaries, without managing each node share individually.
Use declarative node sharing when your organization operates multiple trusted tailnets and needs to provide access between them. For example:
- Share centralized infrastructure: Give users in separate tailnets access to shared services or infrastructure, such as monitoring or development resources.
- Connect business units or acquired organizations: Share selected resources between tailnets operated by different teams, subsidiaries, or acquired companies while keeping each tailnet independently administered.
- Support machine-to-machine access: Let tagged devices in one tailnet access resources in another tailnet through policy.
Declarative node sharing assumes, but does not establish, a trust relationship between the administrators of both tailnets. Do not use it to share resources with unknown or untrusted tailnets.
If you only need to share an individual machine with a specific user outside your tailnet, use link-based node sharing instead.
Get access
While declarative node sharing is in alpha, you must request access to the feature from the Tailscale admin console.
- Open the General page of the admin console
- Go to Feature previews.
- Find Declarative node sharing.
- Select Join waitlist.
Joining the waitlist does not immediately enable the feature. Tailscale notifies you through email when declarative node sharing is enabled for your tailnet. Because this is an alpha feature, functionality might change as Tailscale learns from early usage and feedback.
How it works
Declarative node sharing uses a double opt-in model: an administrator configures each tailnet's policy file, and access takes effect only once both sides are in place.
Each tailnet has a distinct role:
- The receiving tailnet controls which of its local groups and tags an external tailnet is allowed to reference.
- The sharing tailnet writes grants that give those external groups or tags access to specific local resources.
Before you begin
Complete the following before you configure declarative node sharing:
- Confirm declarative node sharing feature access is enabled on the sharing tailnet. Only the sharing tailnet needs to have been accepted into the alpha. There is no minimum Tailscale client version or plan requirement to use the feature.
- Exchange tailnet IDs with the administrator of the other tailnet. You can retrieve a tailnet ID from the General page of the admin console, in the Unique IDs section.
- Agree on which groups and tags in the receiving tailnet will receive access, and confirm they are defined in that tailnet's policy file. Declarative sharing can reference only groups and tags defined in the policy file. Note that synced groups such as SCIM or Google groups are not supported.
Configure declarative node sharing
Both tailnets must update their tailnet policy files.
Configure the receiving tailnet
In the receiving tailnet, first define the sharing tailnet in the externalTailnets section of its policy, then explicitly allow that tailnet to reference selected local groups or tags.
For example:
{
"externalTailnets": {
"<tailnet-alias>": {
"externalID": "<sharing-tailnet-id>",
"allowIncomingConnections": false,
"allowExternalReferencesTo": [
"group:<group-name>"
]
}
},
"groups": {
"group:<group-name>": [
"<user-1>",
"<user-2>"
]
}
}
allowExternalReferencesTo controls the list of local groups or tags the external tailnet can reference in its policy.
Configure the sharing tailnet
In the sharing tailnet, define the receiving tailnet in its own externalTailnets section:
{
"externalTailnets": {
"<tailnet-alias>": {
"externalID": "<receiving-tailnet-id>",
"allowIncomingConnections": true,
}
}
}
allowIncomingConnections must be set to true, indicating that the sharing tailnet accepts incoming traffic from this tailnet.
The sharing tailnet can then create a grant that specifies which groups/tags in the external tailnet can access a local resource.
For example:
{
"grants": [
{
"src": [
"group://<tailnet-alias>/<group-name>"
],
"dst": [
"<resource>"
],
"ip": [
"*"
]
}
]
}
External groups use the following syntax:
group://<tailnet-alias>/<group-name>
External tagged devices use:
tag://<tailnet-alias>/<tag-name>
Use the external group or tag as the src of the grant. The dst specifies the resource in the sharing tailnet that it can access.
If a group or tag is referenced that the receiving tailnet has not included in their allowExternalReferencesTo list, the grant rule will be ignored.
Connect to a shared resource
After both tailnets have updated their tailnet policy files, permitted users and devices can connect directly to the shared resource. Use either:
- The resource's Tailscale IP address.
- Its fully qualified MagicDNS name, such as
machine.example.ts.net.
You must use the fully qualified MagicDNS name when you connect across tailnets. A short MagicDNS name such as machine is not sufficient.
There is no individual invitation or share-acceptance step.
You can use the visual policy editor to manage your tailnet policy file. Refer to the visual editor reference for guidance on using the visual editor.
Declarative sharing versus link-based node sharing
Declarative node sharing is designed for ongoing sharing relationships between trusted tailnets. Administrators define access through policy, and both tailnets explicitly opt in to the relationship.
Link-based node sharing is designed for sharing an individual machine with an individual Tailscale user outside your tailnet. The administrator creates a share and the recipient accepts it.
You can continue to use both methods. Declarative sharing does not change or replace existing link-based shares.