Audience Authorization
tsiam implements a two-layer authorization model that controls which JWT audiences can be requested and by which machines.
Layer 1: Global allowlist#
The global allowlist defines every audience that any node on the Tailnet is ever permitted to request. Any audience not in this list will be rejected regardless of who is asking.
Configure it in config.yaml:
tokens:
allowedAudiences:
- "https://api.example.com"
- "https://database.internal"
- "api://AzureADTokenExchange" # Microsoft Entra ID workload identity
- "sts.amazonaws.com" # AWS IAM federationThis is a required field: tsiam will not start without at least one entry.
Layer 2: Per-node ACL capabilities#
The global allowlist is a service-level boundary, but it doesn’t differentiate between callers. For fine-grained control, use Tailscale ACL capabilities to specify exactly which nodes can request which audiences.
Add a grant to your Tailscale ACL policy using the capability key italypaleale.me/tsiam:
{
"grants": [
{
"src": ["tag:webserver"],
"dst": ["tag:tsiam"],
"app": {
"italypaleale.me/tsiam": [
{
"allowedAudiences": [
"https://api.example.com"
]
}
]
}
},
{
"src": ["tag:backend"],
"dst": ["tag:tsiam"],
"app": {
"italypaleale.me/tsiam": [
{
"allowedAudiences": [
"https://api.example.com",
"sts.amazonaws.com"
]
}
]
}
}
]
}In this example:
- Nodes tagged
tag:webservercan only request tokens forhttps://api.example.com - Nodes tagged
tag:backendcan request tokens for bothhttps://api.example.comandsts.amazonaws.com - The tsiam service node must be tagged
tag:tsiam
Shared workload identity via subject#
If multiple nodes should share a single workload identity (for example, a fleet of identical worker machines), add a subject field to their capability grants and set tokens.subjectClaim: capability in your config:
{
"grants": [
{
"src": ["tag:worker"],
"dst": ["tag:tsiam"],
"app": {
"italypaleale.me/tsiam": [
{
"allowedAudiences": ["sts.amazonaws.com"],
"subject": "worker-fleet"
}
]
}
}
]
}tokens:
subjectClaim: capabilityAll nodes tagged tag:worker will receive tokens with "sub": "worker-fleet", regardless of their individual node IDs. This lets you bind a single IAM role or trust policy to the entire fleet.
Nodes without capabilities#
By default, a node that has no matching ACL capability grant cannot request any audience. The request is rejected even if the audience is in the global allowlist.
To allow nodes without capabilities to request any globally-allowed audience, set:
tokens:
allowEmptyNodeCapability: trueSecurity recommendation: Keep allowEmptyNodeCapability: false (the default) and explicitly grant capabilities to each node or tag. This provides defense in depth, making sure that nodes are not requesting tokens for services they shouldn’t have access to.