Device posture management

Device posture attributes and conditions are currently in beta.
Postures and default posture attributes are available for all plans.

What is device posture?

Device posture is a view of how secure or trustworthy a device is. With Tailscale you can collect device attributes and use them as part of connectivity rules within your Tailscale network (known as a tailnet). You can use these rules to limit access for devices on your tailnet that do not meet security requirements.

Device attributes include pre-populated host information such as operating system version, as well as custom attributes from endpoint detection and response tools.

Authorize device API

If you have an endpoint device posture solution, you may already know which machines on your tailnet do and do not meet your device posture requirements.

One approach to ensuring devices on your network comply with your device posture policy is to use the Authorize device API. This allows you to only authorize devices that meet your requirements, de-authorize devices that do not meet your requirements, by temporarily disabling tailnet access until you determine that their posture has been resolved, at which point you can re-authorize the devices.

Device posture attributes

Device posture attributes are key-value pairs of data attached to devices that you can either read and write for your own use, or use in posture access rules. These attributes are in namespaces. For example, the attribute key node:os is in the node namespace, and the key custom:myAttribute is in the custom namespace. Attribute values can be one of three different types: strings, numbers, or booleans.

Posture attributes bring together data from several different sources all in one place:

  • Host information already available via the API such as OS version and Tailscale version in the node namespace.
  • Custom posture attributes set by you, or software you have integrated with our API, in the custom namespace.
Posture attributes are distinct from nodeAttrs. The existing nodeAttrs are set as flags only, not as key-value pairs.

The following posture attributes are currently available by default, for use in access rule postures, and via the node attribute API:

Attribute key Description Allowed values
node:os The operating system the device is running macos, windows, linux, ios, android, freebsd, openbsd, illumos, js
node:osVersion The version of the operating system A version as a quoted string
node:tsAutoUpdate The configuration state of auto-update on the client true, false
node:tsReleaseTrack The release track of the Tailscale client stable, unstable
node:tsVersion The version of Tailscale the client is running A version as a quoted string
The node:tsAutoUpdate attribute is only set to true when Tailscale’s built-in auto-update is enabled. It is set to false when Tailscale is updated using an external mechanism, such as the Apple App Store or Google Play Store.

A machine’s attributes and respective values are visible in the Machine Details view for each device in your tailnet.

Examples

The following examples demonstrate the formatting to use for each type of attribute key.

Attribute key Example
node:os node:os IN ['macos', 'linux']
node:osVersion node:osVersion == '13.4.0'
node:tsReleaseTrack node:tsReleaseTrack == 'stable'
node:tsVersion node:tsVersion >= '1.42.2'
node:tsAutoUpdate node:tsAutoUpdate == true

Device posture conditions

Postures and posture conditions let you create automated network access control rules based on device posture.

A posture is a set of assertions based on device posture attributes. For example, you might specify that the operating system needs to be newer than a particular version.

Posture conditions are a feature for access rules, allowing you to make them conditional on device posture in addition to source, destination, and protocol. This lets you write flexible and fine-grained access controls for your tailnet.

You can use posture conditions to create simple rules, such as denying all access to devices that don’t meet your posture requirements, or control access within your tailnet with far more granularity. For example, you can require devices to meet stricter security requirements in order to be able to connect to production. Or you can disallow access to most of your corporate network for devices that don’t meet your posture requirements, but still allow them to reach the IT help desk.

Postures

A posture is a set of assertions made about posture attributes and only apply to devices initiating the connection. Each posture must start with posture: followed by a name, and a set of posture attributes and their values, given as a list of strings.

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

Currently supported operators:

  • ==
  • !=
  • IN
  • NOT IN
  • <, <=, >=, > (only for numbers and version attributes: node:osVersion and node:tsVersion)

Versions are compared using a compare function which will take into account versions with both numeric and non-numeric fields.

For a posture to match a device, all posture attribute values must be met. In the above example:

  • The operating system must be macOS or Linux
  • The devices must use the stable release version of the Tailscale client
  • Tailscale client version must be 1.40 or later

Posture conditions can be made against any posture attributes, default and custom.

Postures referencing custom and third-party attributes are available for the Personal and Enterprise plans.

If an attribute defined in the posture is unset for a particular device, the posture will not match that device, irrespective of the operator used. For example, a device that does not have the custom:tier attribute assigned to it, will not match a posture that includes an attribute custom:tier, even if that condition is negative (for example, custom:tier != 'prod').

You can create multiple postures in one policy file:

"postures": {
    "posture:latestMac": [
        "node:os == 'macos'",
        "node:osVersion == '13.4.0'",
        "node:tsReleaseTrack == 'stable'",
    ],
    "posture:anyMac": [
        "node:os == 'macos'",
        "node:tsReleaseTrack == 'stable'",
    ],
},
Posture conditions

A posture condition is an extension to the existing tailnet policy file syntax, allowing you to define access rules dependent on device posture:

"acls": [
    {
        // Only requirement to access development servers is Mac + stable Tailscale
        "action": "accept",
        "src": ["autogroup:member"],
        "dst": ["tag:development"],
        "srcPosture": ["posture:anyMac"]
    },{
        // Only devs can access production
        // and production access requires macOS is also up to date
        "action": "accept",
        "src": ["group:dev"],
        "dst": ["tag:production"],
        "srcPosture": ["posture:latestMac"]
    },
],

Access rules can require that any of a list of postures is required for access to be permitted:

"acls": [
    {
        "action": "accept",
        "src": ["group:dev"],
        "dst": ["tag:production"],
        "srcPosture": ["posture:approvedMacs", "posture:approvedWindows", "posture:approvedLinux"]
    },
],

In this example, access is permitted to production if the connecting device meets any of the 3 specified postures.

Default source posture

If you want to apply a baseline posture that applies to all of your access rules, you can set a default source posture:

"defaultSrcPosture": [
    "posture:basicWindows",
    "posture:basicMac",
    "posture:basicLinux",
],

As with srcPosture in access rules, this permits access if any of the supplied postures are met.

If a default source posture is set, it will apply to any access rules that do not have a posture condition. Note that it is not additive, meaning if an access rule specifies a posture condition, only that condition will apply, and the default source posture condition will no longer apply. This can be used to create an access rule that is more permissive than the default:

"acls": [
    {
        // defaultSrcPosture applies to this rule
        "action": "accept",
        "src": ["autogroup:member"],
        "dst": ["tag:intranet"],
    },{
        "action": "accept",
        "src": ["group:dev", "group:sre"],
        "dst": ["tag:production"],
        // This posture condition is instead of, not in addition to, the default source posture
        "srcPosture": ["posture:prodWin", "posture:prodMac"]
    },
],
Tailscale SSH and Posture Conditions

Connections created with the Tailscale SSH Console are also subject to posture condition restrictions. To allow these connections, you can allow the posture condition node:os == 'js'.

Shared Nodes and Posture Conditions

Posture conditions specified with srcPosture and defaultSrcPosture are only applied to src devices within your tailnet. If you have used Tailscale’s node sharing to grant access to a device to a user outside of your tailnet, that user’s device will be able to connect regardless of their posture.

If you wish for your posture conditions to apply to external users, consider inviting the user into your tailnet.

Posture attributes API

Get posture attributes via API
GET /api/v2/device/{deviceID}/attributes

Retrieve all posture attributes for the specified device. This returns a JSON object of all the key-value pairs of posture attributes for the device.

Parameters
deviceID (required in URL path)

The ID of the device to fetch posture attributes for.

Request example
curl "https://api.tailscale.com/api/v2/device/11055/attributes" \
-u "tskey-api-xxxxx:"
Response

The response is 200 on success. The response body is a JSON object containing all the posture attributes assigned to the node. Attribute values can be strings, numbers or booleans.

{
  "attributes": {
    "custom:myScore": 87,
    "custom:diskEncryption": true,
    "custom:myAttribute": "my_value",
    "node:os": "linux",
    "node:osVersion": "5.19.0-42-generic",
    "node:tsReleaseTrack": "stable",
    "node:tsVersion": "1.40.0",
    "node:tsAutoUpdate": false
  }
}
Set custom posture attributes via API
POST /api/v2/device/{deviceID}/attributes/{attributeKey}

Create or update a custom posture attribute on the specified device. User-managed attributes must be in the custom namespace, which is indicated by prefixing the attribute key with custom:.

Custom device posture attributes are available for the Personal and Enterprise plans.
Parameters
deviceID (required in URL path)

The ID of the device on which to set the custom posture attribute.

attributeKey (required in URL path)

The name of the posture attribute to set. This must be prefixed with custom:.

Keys have a maximum length of 50 characters including the namespace, and can only contain letters, numbers, underscores, and colon.

Keys are case-sensitive. Keys must be unique, but are checked for uniqueness in a case-insensitive manner. For example, custom:MyAttribute and custom:myattribute cannot both be set within a single tailnet.

All values for a given key need to be of the same type, which is determined when the first value is written for a given key. For example, custom:myattribute cannot have a numeric value (87) for one node and a string value ("78") for another node within the same tailnet.

Posture attribute value (required in POST body)
{
  "value": "foo"
}

A value can be either a string, number or boolean.

A string value can have a maximum length of 50 characters, and can only contain letters, numbers, underscores, and periods.

A number value is an integer and must be a JSON safe number (up to 2^53 - 1).

Request example
curl "https://api.tailscale.com/api/v2/device/11055/attributes/custom:my_attribute" \
-u "tskey-api-xxxxx:" \
--data-binary '{"value": "my_value"}'
Response

The response is 2xx on success. The response body is currently an empty JSON object.

Delete custom posture attributes via API
DELETE /api/v2/device/{deviceID}/attributes/{attributeKey}

Delete a posture attribute from the specified device. This is only applicable to user-managed posture attributes in the custom namespace, which is indicated by prefixing the attribute key with custom:.

Custom device posture attributes are available for the Personal and Enterprise plans.
Parameters
deviceID (required in URL path)

The ID of the device from which to delete the posture attribute.

attributeKey (required in URL path)

The name of the posture attribute to delete. This must be prefixed with custom:.

Keys have a maximum length of 50 characters including the namespace, and can only contain letters, numbers, underscores, and a delimiting colon.

Request example
curl -X DELETE "https://api.tailscale.com/api/v2/device/11055/attributes/custom:my_attribute" \
-u "tskey-api-xxxxx:"
Response

The response is 2xx on success. The response body is currently an empty JSON object.

Audit log events

The following audit log events are added for device posture.

Target Action Description
Node Create new node attribute Custom node attribute for device posture was created.
Node Update node attribute Custom node attribute for device posture was updated.
Node Delete node attribute Custom node attribute for device posture was deleted.